public Signature Sign(BigInteger z) { // Generate random number k (ephemeral private key) // TODO: this should be replaced with deterministic initialisation of k as shown here: // https://tools.ietf.org/html/rfc6979 BigInteger k; do { var bytes = new byte[32]; using (RandomNumberGenerator rng = new RNGCryptoServiceProvider()) { rng.GetBytes(bytes); } k = BigIntegerUtilities.CreateFromUnsignedBigEndianBytes(bytes); } while (k < 1 || k > Secp256k1Constants.N); // r is the x coordinate of the resulting point k*G (ephemeral public key) var r = BitcoinConstants.G.Multiply(k).X.Num; // 1/k = pow(k, N-2, N) var k_inv = BigInteger.ModPow(k, Secp256k1Constants.N - 2, Secp256k1Constants.N).Mod(Secp256k1Constants.N); // s = (z+r*prvKey) / k var s = ((z + (r * this.Value)) * k_inv).Mod(Secp256k1Constants.N); return(new Signature(r, s)); }
public Signature Sign(byte[] data) { var hash = HashUtilities.Sha256(data); var z = BigIntegerUtilities.CreateFromUnsignedBigEndianBytes(hash).Mod(Secp256k1Constants.N); return(Sign(z)); }
public bool Verify(byte[] data, Signature s) { var hash = HashUtilities.Sha256(data); var z = BigIntegerUtilities.CreateFromUnsignedBigEndianBytes(hash).Mod(Secp256k1Constants.N); return(Verify(z, s)); }
public static PublicKey Parse(byte[] bytes, bool testNet = false) { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } else if (bytes.Length == 33) { bool yIsEven; if (bytes[0] == 0x02) { yIsEven = true; } else if (bytes[0] == 0x03) { yIsEven = false; } else { throw new Exception(string.Format("Compressed public key found (33 bytes) with invalid prefix. Expected 0x02 or 0x03, found 0x{0:X2}", bytes[0])); } var buffer = new byte[32]; Buffer.BlockCopy(bytes, 1, buffer, 0, buffer.Length); var x = BigIntegerUtilities.CreateFromUnsignedBigEndianBytes(buffer); var y = Secp256k1Point.GetYCoordinate(new Secp256k1FieldElement(x), yIsEven); return(new PublicKey(x, y.Num, testNet, true)); } else if (bytes.Length == 65) { if (bytes[0] != 0x04) { throw new Exception(string.Format("Uncompressed public key found (65 bytes) with invalid prefix. Expected 0x04, found 0x{0:X2}", bytes[0])); } var buffer = new byte[32]; Buffer.BlockCopy(bytes, 1, buffer, 0, buffer.Length); var x = BigIntegerUtilities.CreateFromUnsignedBigEndianBytes(buffer); Buffer.BlockCopy(bytes, 33, buffer, 0, buffer.Length); var y = BigIntegerUtilities.CreateFromUnsignedBigEndianBytes(buffer); return(new PublicKey(x, y, testNet, false)); } else { throw new Exception(nameof(bytes) + " length is invalid, expected 33 bytes (compressed pub key) or 65 bytes (uncompressed pub key)"); } }
public static PrivateKey CreateFromWifString(string wifString) { bool testNet; bool wifCompressed; byte[] rawBytes = Base58Utilities.DecodeBase58Check(wifString); byte[] privateKeyBytes = new byte[32]; // Compressed is 34 bytes, uncompressed is 33 bytes if (rawBytes.Length == 34 || rawBytes.Length == 33) { Buffer.BlockCopy(rawBytes, 1, privateKeyBytes, 0, 32); if (rawBytes[0] == 0xEF) { testNet = true; } else if (rawBytes[0] == 0x80) { testNet = false; } else { throw new ArgumentException(nameof(wifString) + " prefix is invalid"); } wifCompressed = rawBytes.Length == 34; } else { throw new ArgumentException(nameof(wifString) + " is invalid"); } var val = BigIntegerUtilities.CreateFromUnsignedBigEndianBytes(privateKeyBytes); return(new PrivateKey(val, testNet, wifCompressed)); }