internal override uint EqCT(MutableECPoint Q) { MutableECPointPrime R = SameCurve(Q); if (affine != 0) { if (R.affine != 0) { return(mx.EqCT(R.mx) & my.EqCT(R.my) & mz.EqCT(R.mz)); } else { return(EqCTMixed(R, this)); } } else if (R.affine != 0) { return(EqCTMixed(this, R)); } /* * Both points are in Jacobian coordinates. * If Z1 and Z2 are non-zero, then equality is * achieved if and only if both following equations * are true: * X1*(Z2^2) = X2*(Z1^2) * Y1*(Z2^3) = Y2*(Z1^3) * If Z1 or Z2 is zero, then equality is achieved * if and only if both are zero. */ mt1.Set(mz); mt1.MontySquare(); mt2.Set(R.mz); mt2.MontySquare(); mt3.Set(mx); mt3.MontyMul(mt2); mt4.Set(R.mx); mt4.MontyMul(mt1); uint r = mt3.EqCT(mt4); mt1.MontyMul(mz); mt2.MontyMul(R.mz); mt3.Set(my); mt3.MontyMul(mt2); mt4.Set(R.my); mt4.MontyMul(mt1); r &= mt3.EqCT(mt4); uint z1z = mz.IsZeroCT; uint z2z = R.mz.IsZeroCT; return((r & ~(z1z | z2z)) ^ (z1z & z2z)); }
internal override uint EqCT(MutableECPoint Q) { MutableECPointCurve25519 R = SameCurve(Q); return(x.EqCT(R.x)); }
internal override uint DecodeCT(byte[] enc) { /* * Format (specified in IEEE P1363, annex E): * * 0x00 point at infinity * 0x02+b <X> compressed, b = lsb of Y * 0x04 <X> <Y> uncompressed * 0x06+b <X> <Y> uncompressed, b = lsb of Y * * Coordinates X and Y are in unsigned big-endian * notation with exactly the length of the modulus. * * We want constant-time decoding, up to the encoded * length. This means that the four following situations * can be differentiated: * -- Point is zero (length = 1) * -- Point is compressed (length = 1 + flen) * -- Point is uncompressed or hybrid (length = 1 + 2*flen) * -- Length is neither 1, 1+flen or 1+2*flen. */ int flen = curve.flen; uint good = 0xFFFFFFFF; if (enc.Length == 1) { /* * 1-byte encoding is point at infinity; the * byte shall have value 0. */ int z = enc[0]; good &= ~(uint)((z | -z) >> 31); SetZero(); } else if (enc.Length == 1 + flen) { /* * Compressed encoding. Leading byte is 0x02 or * 0x03. */ int z = (enc[0] & 0xFE) - 0x02; good &= ~(uint)((z | -z) >> 31); uint lsbValue = (uint)(enc[0] & 1); good &= mx.Decode(enc, 1, flen); RebuildY2(); if (curve.pMod4 == 3) { good &= my.SqrtBlum(); } else { /* * Square roots modulo a non-Blum prime * are a bit more complex. We do not * support them yet (TODO). */ good = 0x00000000; } /* * Adjust Y depending on LSB. */ mt1.Set(my); mt1.Negate(); uint dn = (uint)-(int)(my.GetLSB() ^ lsbValue); my.CondCopy(mt1, dn); /* * A corner case: LSB adjustment works only if * Y != 0. If Y is 0 and requested LSB is 1, * then the decoding fails. Note that this case * cannot happen with usual prime curves, because * they have a prime order, implying that there is * no valid point such that Y = 0 (that would be * a point of order 2). */ good &= ~(uint)-(int)(my.GetLSB() ^ lsbValue); mz.Set(1); } else if (enc.Length == 1 + (flen << 1)) { /* * Uncompressed or hybrid. Leading byte is either * 0x04, 0x06 or 0x07. We verify that the X and * Y coordinates fulfill the curve equation. */ int fb = enc[0]; int z = (fb & 0xFC) - 0x04; good &= ~(uint)((z | -z) >> 31); z = fb - 0x05; good &= (uint)((z | -z) >> 31); good &= mx.Decode(enc, 1, flen); RebuildY2(); mt1.Set(my); mt1.FromMonty(); good &= my.Decode(enc, 1 + flen, flen); mt2.Set(my); mt2.MontySquare(); good &= mt1.EqCT(mt2); /* * We must check the LSB for hybrid encoding. * The check fails if the encoding is marked as * hybrid AND the LSB does not match. */ int lm = (fb >> 1) & ((int)my.GetLSB() ^ fb) & 1; good &= ~(uint)-lm; mz.Set(1); } else { good = 0x00000000; } /* * If decoding failed, then we force the value to 0. * Otherwise, we got a value. Either way, this uses * affine coordinates. */ mx.CondCopy(curve.mp, ~good); my.CondCopy(curve.mp, ~good); mz.CondCopy(curve.mp, ~good); affine = 0xFFFFFFFF; return(good); }
public static bool VerifyRaw(ECPublicKey pk, byte[] hash, int hashOff, int hashLen, byte[] sig, int sigOff, int sigLen) { try { /* * Get the curve. */ ECCurve curve = pk.Curve; /* * Get r and s from signature. This also verifies * that they do not exceed the subgroup order. */ if (sigLen == 0 || (sigLen & 1) != 0) { return(false); } int tlen = sigLen >> 1; ModInt oneQ = new ModInt(curve.SubgroupOrder); oneQ.Set(1); ModInt r = oneQ.Dup(); ModInt s = oneQ.Dup(); r.Decode(sig, sigOff, tlen); s.Decode(sig, sigOff + tlen, tlen); /* * If either r or s was too large, it got set to * zero. We also don't want real zeros. */ if (r.IsZero || s.IsZero) { return(false); } /* * Convert the hash value to an integer modulo q. * As per FIPS 186-4, if the hash value is larger * than q, then we keep the qlen leftmost bits of * the hash value. */ int qBitLength = oneQ.ModBitLength; int hBitLength = hashLen << 3; byte[] hv; if (hBitLength <= qBitLength) { hv = new byte[hashLen]; Array.Copy(hash, hashOff, hv, 0, hashLen); } else { int qlen = (qBitLength + 7) >> 3; hv = new byte[qlen]; Array.Copy(hash, hashOff, hv, 0, qlen); int rs = (8 - (qBitLength & 7)) & 7; BigInt.RShift(hv, rs); } ModInt z = oneQ.Dup(); z.DecodeReduce(hv); /* * Apply the verification algorithm: * w = 1/s mod q * u = z*w mod q * v = r*w mod q * T = u*G + v*Pub * test whether T.x mod q == r. */ /* * w = 1/s mod q */ ModInt w = s.Dup(); w.Invert(); /* * u = z*w mod q */ w.ToMonty(); ModInt u = w.Dup(); u.MontyMul(z); /* * v = r*w mod q */ ModInt v = w.Dup(); v.MontyMul(r); /* * Compute u*G */ MutableECPoint T = curve.MakeGenerator(); uint good = T.MulSpecCT(u.Encode()); /* * Compute v*iPub */ MutableECPoint M = pk.iPub.Dup(); good &= M.MulSpecCT(v.Encode()); /* * Compute T = u*G+v*iPub */ uint nd = T.AddCT(M); M.DoubleCT(); T.Set(M, ~nd); good &= ~T.IsInfinityCT; /* * Get T.x, reduced modulo q. * Signature is valid if and only if we get * the same value as r (and we did not encounter * an error previously). */ s.DecodeReduce(T.X); return((good & r.EqCT(s)) != 0); } catch (CryptoException) { /* * Exceptions may occur if the key or signature * have invalid values (non invertible, out of * range...). Any such occurrence means that the * signature is not valid. */ return(false); } }