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 = ECDSA.Sign(Curve.SecP256k1, bufferSha256, privateKey.D, nonce++); var der = ecSignature.ToDER(); var lengthR = der[3]; var lengthS = der[5 + lengthR]; if (lengthR == 32 && lengthS == 32) { i = ECDSA.CalculatePublicKeyRecoveryParameter(Curve.SecP256k1, e, ecSignature, privateKey.ToPublicKey().Q); i += 4; // compressed i += 27; // compact // 24 or 27 :( forcing odd-y 2nd key candidate) break; } if (nonce % 10 == 0) { Unity.Console.Warning(nonce, "attempts to find canonical signature"); } } return(new Signature(ecSignature.R, ecSignature.S, i)); }
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)); }
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)); }
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; 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); }
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"); }
public Compact(bool compressed, byte i, ECSignature signature) { this.compressed = compressed; this.i = i; this.signature = signature; }