예제 #1
0
        public static bool Verify(Curve curve, byte[] hash, ECSignature signature, Point q)
        {
            // 1.4.2 H = Hash(M), already done by the user
            // 1.4.3 e = H
            var e = BigInteger.FromBuffer(hash);

            return(VerifyRaw(curve, e, signature, q));
        }
예제 #2
0
        private static bool VerifyRaw(Curve curve, BigInteger e, ECSignature signature, Point q)
        {
            var n = curve.N;
            var g = curve.G;
            var r = signature.R;
            var s = signature.S;

            // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1]
            if (r.Sign <= 0 || r.CompareTo(n) >= 0)
            {
                return(false);
            }
            if (s.Sign <= 0 || s.CompareTo(n) >= 0)
            {
                return(false);
            }

            // c = s^-1 mod n
            var c = s.ModuloInverse(n);

            // 1.4.4 Compute u1 = es^−1 mod n
            //               u2 = rs^−1 mod n
            var u1 = e.Multiply(c).Modulo(n);
            var u2 = r.Multiply(c).Modulo(n);

            // 1.4.5 Compute R = (xR, yR) = u1G + u2Q
            var R = g.MultiplyTwo(u1, q, u2);

            // 1.4.5 (cont.) Enforce R is not at infinity
            if (curve.IsInfinity(R))
            {
                return(false);
            }

            // 1.4.6 Convert the field element R.x to an integer
            var xR = R.AffineX;

            // 1.4.7 Set v = xR mod n
            var v = xR.Modulo(n);

            // 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
            return(v.Equals(r));
        }
예제 #3
0
        public static Point RecoverPublicKey(Curve curve, BigInteger e, ECSignature signature, byte i)
        {
            Assert.Equal(i & 3, i, "Recovery param is more than two bits");

            var n = curve.N;
            var g = curve.G;
            var r = signature.R;
            var s = signature.S;

            Assert.Check(r.Sign > 0 && r.CompareTo(n) < 0, "Invalid r value");
            Assert.Check(s.Sign > 0 && s.CompareTo(n) < 0, "Invalid s value");

            // A set LSB signifies that the y-coordinate is odd
            var isYOdd = (i & 1) != 0;

            // The more significant bit specifies whether we should use the
            // first or second candidate key.
            var isSecondKey = (i >> 1) != 0;

            // 1.1 Let x = r + jn
            var x = isSecondKey ? r.Addition(n) : r.Clone();
            var R = curve.PointFromX(isYOdd, x);

            // 1.4 Check that nR is at infinity
            var nR = R.Multiply(n);

            Assert.Check(curve.IsInfinity(nR), "nR is not a valid curve point");

            // Compute -e from e
            var eNegate = e.Negate.Modulo(n);

            // 1.6.1 Compute q = r^-1 (sR -  eG)
            //               q = r^-1 (sR + -eG)
            var rInverse = r.ModuloInverse(n);

            var q = R.MultiplyTwo(s, g, eNegate).Multiply(rInverse);

            curve.Validate(q);

            return(q);
        }
예제 #4
0
        private static Signature SignBufferSha256(byte[] bufferSha256, PrivateKey privateKey)
        {
            if (bufferSha256.Length != 32)
            {
                throw new ArgumentException("bufferSha256: 32 byte buffer requred");
            }
            var         nonce       = uint.MinValue;
            var         e           = BigInteger.FromBuffer(bufferSha256);
            ECSignature ecSignature = null;
            var         i           = byte.MinValue;

            while (true)
            {
                ecSignature?.Dispose();
                ecSignature = ECDSA.Sign(Curve.SecP256k1, bufferSha256, privateKey.D, nonce++);
                var der     = ecSignature.ToDER();
                var lengthR = der[3];
                var lengthS = der[5 + lengthR];
                der.Clear();
                if (lengthR == 32 && lengthS == 32)
                {
                    i  = ECDSA.CalculatePublicKeyRecoveryParameter(Curve.SecP256k1, e, ecSignature, privateKey.PublicKey.Q);
                    i += 4;  // compressed
                    i += 27; // compact  //  24 or 27 :( forcing odd-y 2nd key candidate)
                    break;
                }
                if (nonce % 10 == 0)
                {
                    CustomTools.Console.DebugWarning(nonce, "attempts to find canonical signature");
                }
            }
            e.Dispose();
            var result = new Signature(ecSignature.R.Clone(), ecSignature.S.Clone(), i);

            ecSignature.Dispose();
            return(result);
        }
예제 #5
0
 public Compact(bool compressed, byte i, ECSignature signature)
 {
     this.compressed = compressed;
     this.i          = i;
     this.signature  = signature;
 }
예제 #6
0
        public static byte CalculatePublicKeyRecoveryParameter(Curve curve, BigInteger e, ECSignature signature, Point q)
        {
            for (var i = 0; i < 4; i++)
            {
                var qPrime = RecoverPublicKey(curve, e, signature, (byte)i);

                // 1.6.2 Verify q
                if (qPrime.Equals(q))
                {
                    return((byte)i);
                }
            }
            throw new InvalidOperationException("Unable to find valid recovery factor");
        }