public static byte[] SignRaw(ECPrivateKey sk, IDigest rfc6979Hash, byte[] hash, int hashOff, int hashLen) { ECCurve curve = sk.Curve; byte[] q = curve.SubgroupOrder; RFC6979 rf = new RFC6979(rfc6979Hash, q, sk.X, hash, hashOff, hashLen, rfc6979Hash != null); ModInt mh = rf.GetHashMod(); ModInt mx = mh.Dup(); mx.Decode(sk.X); /* * Compute DSA signature. We use a loop to enumerate * candidates for k until a proper one is found (it * is VERY improbable that we may have to loop). */ ModInt mr = mh.Dup(); ModInt ms = mh.Dup(); ModInt mk = mh.Dup(); byte[] k = new byte[q.Length]; for (;;) { rf.NextK(k); MutableECPoint G = curve.MakeGenerator(); if (G.MulSpecCT(k) == 0) { /* * We may get an error here only if the * curve is invalid (generator does not * produce the expected subgroup). */ throw new CryptoException( "Invalid EC private key / curve"); } mr.DecodeReduce(G.X); if (mr.IsZero) { continue; } ms.Set(mx); ms.ToMonty(); ms.MontyMul(mr); ms.Add(mh); mk.Decode(k); mk.Invert(); ms.ToMonty(); ms.MontyMul(mk); byte[] sig = new byte[q.Length << 1]; mr.Encode(sig, 0, q.Length); ms.Encode(sig, q.Length, q.Length); return(sig); } }
internal override void Set(MutableECPoint Q) { MutableECPointPrime R = SameCurve(Q); mx.Set(R.mx); my.Set(R.my); mz.Set(R.mz); affine = R.affine; }
internal override void Set(MutableECPoint Q, uint ctl) { MutableECPointPrime R = SameCurve(Q); mx.CondCopy(R.mx, ctl); my.CondCopy(R.my, ctl); mz.CondCopy(R.mz, ctl); affine ^= ctl & (affine ^ R.affine); }
MutableECPointCurve25519 SameCurve(MutableECPoint Q) { MutableECPointCurve25519 R = Q as MutableECPointCurve25519; if (R == null) { throw new CryptoException("Mixed curves"); } return(R); }
/* * Multiply the provided (encoded) point G by a scalar x. Scalar * encoding is big-endian. The scalar value shall be non-zero and * lower than the subgroup order (exception: some curves allow * larger ranges). * * The result is written in the provided D[] array, using either * compressed or uncompressed format (for some curves, output is * always compressed). The array shall have the appropriate length. * Returned value is -1 on success, 0 on error. If 0 is returned * then the array contents are indeterminate. * * G and D need not be distinct arrays. */ public uint Mul(byte[] G, byte[] x, byte[] D, bool compressed) { MutableECPoint P = MakeZero(); uint good = P.DecodeCT(G); good &= ~P.IsInfinityCT; good &= P.MulSpecCT(x); good &= P.Encode(D, compressed); return(good); }
MutableECPointPrime SameCurve(MutableECPoint Q) { MutableECPointPrime R = Q as MutableECPointPrime; if (R == null || !curve.Equals(R.curve)) { throw new CryptoException("Mixed curves"); } return(R); }
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)); }
/* * CheckValid() runs the validity tests on the curve, and * verifies that provided point is part of a subgroup with * the advertised subgroup order. */ public void CheckValid() { curve.CheckValid(); MutableECPoint P = iPub.Dup(); if (P.MulSpecCT(curve.SubgroupOrder) == 0 || !P.IsInfinity) { throw new CryptoException( "Public key point not on the defined subgroup"); } }
/* * Create a new instance with the provided elements. The * constructor verifies that the provided point is part of * the curve. */ public ECPublicKey(ECCurve curve, byte[] Pub) { this.curve = curve; this.pub = Pub; iPub = curve.Decode(Pub); if (iPub.IsInfinity) { throw new CryptoException( "Public key point is infinity"); } hashCode = curve.GetHashCode() ^ (int)BigInt.HashInt(iPub.X) ^ (int)BigInt.HashInt(iPub.Y); }
internal override uint AddCT(MutableECPoint Q) { MutableECPointPrime P2 = SameCurve(Q); if (P2.affine != 0) { ms4.Set(P2.mx); ms5.Set(P2.my); ms6.Set(P2.mz); ms4.ToMonty(); ms5.ToMonty(); ms6.SetMonty(~ms6.IsZeroCT); return(AddCTInner(ms4, ms5, ms6, true)); } else { return(AddCTInner(P2.mx, P2.my, P2.mz, false)); } }
/* * Given points A and B, and scalar x and y, return x*A+y*B. This * is used for ECDSA. Scalars use big-endian encoding and must be * non-zero and lower than the subgroup order. * * The result is written in the provided D[] array, using either * compressed or uncompressed format (for some curves, output is * always compressed). The array shall have the appropriate length. * Returned value is -1 on success, 0 on error. If 0 is returned * then the array contents are indeterminate. * * Not all curves support this operation; if the curve does not, * then an exception is thrown. * * A, B and D need not be distinct arrays. */ public uint MulAdd(byte[] A, byte[] x, byte[] B, byte[] y, byte[] D, bool compressed) { MutableECPoint P = MakeZero(); MutableECPoint Q = MakeZero(); /* * Decode both points. */ uint good = P.DecodeCT(A); good &= Q.DecodeCT(B); good &= ~P.IsInfinityCT & ~Q.IsInfinityCT; /* * Perform both point multiplications. */ good &= P.MulSpecCT(x); good &= Q.MulSpecCT(y); good &= ~P.IsInfinityCT & ~Q.IsInfinityCT; /* * Perform addition. The AddCT() function may fail if * P = Q, in which case we must compute 2Q and use that * value instead. */ uint z = P.AddCT(Q); Q.DoubleCT(); P.Set(Q, ~z); /* * Encode the result. The Encode() function will report * an error if the addition result is infinity. */ good &= P.Encode(D, compressed); return(good); }
/* * Set this instance to the same contents as the provided point, * but only if ctl == 0xFFFFFFFFF. If ctl == 0x00000000, then * this instance is unmodified. The operand Q must be part of * the same curve. */ internal abstract void Set(MutableECPoint Q, uint ctl);
internal override void Set(MutableECPoint Q) { MutableECPointCurve25519 R = SameCurve(Q); x.Set(R.x); }
internal override void SetMux(uint ctl, MutableECPoint P1, MutableECPoint P2) { SetMuxInner(ctl, SameCurve(P1), SameCurve(P2)); }
internal override void Set(MutableECPoint Q, uint ctl) { MutableECPointCurve25519 R = SameCurve(Q); x.CondCopy(R.x, ctl); }
internal override uint AddCT(MutableECPoint Q) { throw new CryptoException("Not implemented for Curve25519"); }
internal bool Eq(MutableECPoint Q) { return(EqCT(Q) != 0); }
/* * Compare this point to another. This method throws an * exception if the provided point is not on the same curve as * this instance. It otherwise returns 0xFFFFFFFF if both points * are equal, 0x00000000 otherwise. This method is constant-time * (its execution time may depend on whether this and/or the * other point is normalized or not, but not on the actual * values). */ internal abstract uint EqCT(MutableECPoint Q);
/* * AddCT() computes P+Q (P is this instance, Q is the operand). * It may assume that P != Q. If P = Q and the method could not * compute the correct result, then it shall set this instance to * 0 (infinity) and return 0x00000000. In all other cases, it must * compute the correct point and return 0xFFFFFFFF. In particular, * it should properly handle cases where P = 0 or Q = 0. This * function is allowed to handle doubling cases as well, if it * can. * * This method may be more efficient if the operand is * normalized. Execution time and memory access may depend on * whether this instance or the other operand is normalized, * but not on the actual point values (including if the points * do not fulfill the properties above). */ internal abstract uint AddCT(MutableECPoint Q);
internal override uint EqCT(MutableECPoint Q) { MutableECPointCurve25519 R = SameCurve(Q); return(x.EqCT(R.x)); }
/* * Set this instance to the same contents as the provided point. * The operand Q must be part of the same curve. */ internal abstract void Set(MutableECPoint Q);
/* * Set this instance to the same contents as point P1 if * ctl == 0xFFFFFFFF, or point P2 if ctl == 0x00000000. * Both operands must use the same curve as this instance. */ internal abstract void SetMux(uint ctl, MutableECPoint P1, MutableECPoint P2);
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); } }