public PublicKey DerivePublickey(PublicKey basepoint, PublicKey perCommitmentPoint) { // TODO: pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G Span <byte> toHash = stackalloc byte[PublicKey.LENGTH * 2]; perCommitmentPoint.GetSpan().CopyTo(toHash); basepoint.GetSpan().CopyTo(toHash.Slice(PublicKey.LENGTH)); byte[] hashed = NBitcoin.Crypto.Hashes.SHA256(toHash); if (ECPubKey.TryCreate(basepoint, Context.Instance, out _, out ECPubKey? ecpubkey)) { if (ecpubkey.TryAddTweak(hashed.AsSpan(), out ECPubKey? ecpubkeytweaked)) { if (ecpubkeytweaked != null) { Span <byte> pub = stackalloc byte[33]; ecpubkeytweaked.WriteToSpan(true, pub, out _); return(new PublicKey(pub.ToArray())); } } } return(null); }
public PublicKey DeriveRevocationPublicKey(PublicKey basepoint, PublicKey perCommitmentPoint) { // TODO: revocationpubkey = revocation_basepoint * SHA256(revocation_basepoint || per_commitment_point) + per_commitment_point * SHA256(per_commitment_point || revocation_basepoint) Span <byte> toHash1 = stackalloc byte[PublicKey.LENGTH * 2]; basepoint.GetSpan().CopyTo(toHash1); perCommitmentPoint.GetSpan().CopyTo(toHash1.Slice(PublicKey.LENGTH)); byte[] hashed1 = NBitcoin.Crypto.Hashes.SHA256(toHash1); ECPubKey?revocationBasepointTweaked = null; if (ECPubKey.TryCreate(basepoint, Context.Instance, out _, out ECPubKey? ecbasepoint)) { if (ecbasepoint.TryMultTweak(hashed1.AsSpan(), out ECPubKey? ecpubkeytweaked)) { if (ecpubkeytweaked != null) { revocationBasepointTweaked = ecpubkeytweaked; } } } Span <byte> toHash2 = stackalloc byte[PublicKey.LENGTH * 2]; perCommitmentPoint.GetSpan().CopyTo(toHash2); basepoint.GetSpan().CopyTo(toHash2.Slice(PublicKey.LENGTH)); byte[] hashed2 = NBitcoin.Crypto.Hashes.SHA256(toHash2); ECPubKey?perCommitmentPointTweaked = null; if (ECPubKey.TryCreate(perCommitmentPoint, Context.Instance, out _, out ECPubKey? ecperCommitmentPoint)) { if (ecperCommitmentPoint.TryMultTweak(hashed2.AsSpan(), out ECPubKey? ecperCommitmentPointtweaked)) { if (ecperCommitmentPointtweaked != null) { perCommitmentPointTweaked = ecperCommitmentPointtweaked; } } } if (revocationBasepointTweaked != null && perCommitmentPointTweaked != null) { var keys = new ECPubKey[] { revocationBasepointTweaked, perCommitmentPointTweaked }; if (ECPubKey.TryCombine(Context.Instance, keys, out ECPubKey? revocationpubkey)) { if (revocationpubkey != null) { Span <byte> pub = stackalloc byte[33]; revocationpubkey.WriteToSpan(true, pub, out _); return(new PublicKey(pub.ToArray())); } } } return(null); }
public CompressedPubKey(ECPubKey ecPubKey) { if (ecPubKey == null) { throw new ArgumentNullException(nameof(ecPubKey)); } this.EcPubKey = ecPubKey; }
public void UseAdaptor(ECPubKey adaptor) { if (processed_nonce) { throw new InvalidOperationException("This function can only be called before MusigContext.Process"); } this.adaptor = adaptor; }
public static bool TryExtractPrivateKey(this ECPubKey pubKey, ReadOnlySpan <byte> msg1, SecpSchnorrSignature sig1, ReadOnlySpan <byte> msg2, SecpSchnorrSignature sig2, out ECPrivKey?key) { key = null; if (msg1.Length != 32) { return(false); } if (msg2.Length != 32) { return(false); } if (msg1.SequenceCompareTo(msg2) == 0) { return(false); } Span <byte> sig64 = stackalloc byte[64]; sig1.WriteToSpan(sig64); Span <byte> pk_buf = stackalloc byte[32]; Span <byte> buf = stackalloc byte[32]; pubKey.Q.x.WriteToSpan(pk_buf); using var sha = new SHA256(); sha.InitializeTagged(TAG_BIP0340Challenge); sha.Write(sig64.Slice(0, 32)); sha.Write(pk_buf); sha.Write(msg1); sha.GetHash(buf); var n1 = new Scalar(buf, out _); sig2.WriteToSpan(sig64); sha.InitializeTagged(TAG_BIP0340Challenge); sha.Write(sig64.Slice(0, 32)); sha.Write(pk_buf); sha.Write(msg2); sha.GetHash(buf); var n2 = new Scalar(buf, out _); var s = sig2.s + sig1.s.Negate(); var n = (n2 + n1.Negate()); var sk = s * n.Inverse(); if (pubKey.Q.y.IsOdd) { sk = sk.Negate(); } if (!pubKey.ctx.TryCreateECPrivKey(sk, out key)) { return(false); } return(true); }
public MusigPubNonce(Context?context, ReadOnlySpan <byte> in66) { if (!ECPubKey.TryCreate(in66.Slice(0, 33), context, out _, out var k1) || !ECPubKey.TryCreate(in66.Slice(33, 33), context, out _, out var k2)) { throw new ArgumentException("Invalid musig pubnonce"); } this.context = context ?? Context.Instance; this.k1 = k1; this.k2 = k2; }
public PublicKey PublicKeyFromPrivateKey(PrivateKey privateKey) { if (ECPrivKey.TryCreate(privateKey, Context.Instance, out ECPrivKey? ecprvkey)) { if (ecprvkey != null) { ECPubKey ecpubkey = ecprvkey.CreatePubKey(); Span <byte> pub = stackalloc byte[33]; ecpubkey.WriteToSpan(true, pub, out _); return(new PublicKey(pub.ToArray())); } } return(null); }
internal static void secp256k1_musig_compute_noncehash(Span <byte> noncehash, Span <GE> aggnonce, ReadOnlySpan <byte> agg_pk32, ReadOnlySpan <byte> msg) { Span <byte> buf = stackalloc byte[33]; using SHA256 sha = new SHA256(); sha.InitializeTagged("MuSig/noncecoef"); int i; for (i = 0; i < 2; i++) { ECPubKey.secp256k1_eckey_pubkey_serialize(buf, ref aggnonce[i], out _, true); sha.Write(buf); } sha.Write(agg_pk32.Slice(0, 32)); sha.Write(msg.Slice(0, 32)); sha.GetHash(noncehash); }
public void CreatePubKey() { Console.WriteLine(); uint256 N = uint256.Parse("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); Random rand = new Random(); byte[] privateKey = new byte[32]; uint256 candidateKey; do { rand.NextBytes(privateKey); candidateKey = new uint256(privateKey, false); } while (!(candidateKey > 0 && candidateKey < N)); // Public key privateKey = Encoders.Hex.DecodeData("da7639a9e2ed4e918b57151509ee34b3f80ad4ab60fb52de59cc3a7386b19007"); NBitcoin.Secp256k1.ECPrivKey privKey = Context.Instance.CreateECPrivKey(new Scalar(privateKey)); ECPubKey pubKey = privKey.CreatePubKey(); byte[] pubKeyBytes = pubKey.ToBytes(); // Console.WriteLine($"Pub key : {Encoders.Hex.EncodeData(pubKeyBytes)}"); var x = pubKey.Q.x.ToBytes(); var y = pubKey.Q.y.ToBytes(); Console.WriteLine($"Pub key x : {Encoders.Hex.EncodeData(x)}"); Console.WriteLine($"Pub key y : {string.Empty.PadLeft(16, '\t')}{Encoders.Hex.EncodeData(y)}"); var pubKeyUncomp = Helper.Concat(new byte[] { (04) }, x, y); Console.WriteLine($"Pub key (uncomp.) : {Encoders.Hex.EncodeData(pubKeyUncomp)}"); BigInteger yBig = new BigInteger(y, isUnsigned: true, isBigEndian: true); byte pubKeyPrefix = (byte)(yBig % 2 == 0 ? 02 : 03); var pubKeyComp = Helper.Concat(new byte[] { pubKeyPrefix }, x); Console.WriteLine($"Pub key (comp.) : {Encoders.Hex.EncodeData(pubKeyComp)}"); Assert.AreEqual(pubKeyBytes, pubKeyComp); }
public static bool SigVerify(this ECPubKey pubKey, SecpECDSAAdaptorSignature sig, SecpECDSAAdaptorProof proof, ReadOnlySpan <byte> msg32, ECPubKey adaptor) { if (pubKey == null) { throw new ArgumentNullException(nameof(pubKey)); } if (adaptor == null) { throw new ArgumentNullException(nameof(adaptor)); } if (msg32.Length < 32) { throw new ArgumentException(paramName: nameof(msg32), message: "msg32 should be at least 32 bytes"); } if (sig == null) { throw new ArgumentNullException(nameof(sig)); } var adaptor_ge = adaptor.Q; if (!secp256k1_dleq_verify(pubKey.ctx.EcMultContext, "ECDSAAdaptorSig", proof.s, proof.e, proof.rp, adaptor_ge, sig.r)) { return(false); } /* 2. return x_coord(R') == x_coord(s'⁻¹(H(m) * G + x_coord(R) * X)) */ var q = pubKey.Q; var msg = new Scalar(msg32); if (!pubKey.ctx.secp256k1_ecdsa_adaptor_sig_verify_helper(sig.r.x.ToScalar(), sig.sp, q, msg, out var rhs)) { return(false); } var lhs = proof.rp.ToGroupElementJacobian(); rhs = rhs.Negate(); lhs = lhs.AddVariable(rhs, out _); return(lhs.IsInfinity); }
public static bool TryComputeSigPoint(this ECXOnlyPubKey pubkey, ReadOnlySpan <byte> msg32, SchnorrNonce rx, out ECPubKey?sigpoint) { if (rx == null) { throw new ArgumentNullException(nameof(rx)); } if (msg32.Length != 32) { throw new ArgumentException("Msg should be 32 bytes", nameof(msg32)); } sigpoint = null; Span <byte> buf = stackalloc byte[32]; Span <byte> pk_buf = stackalloc byte[32]; pubkey.WriteXToSpan(pk_buf); /* tagged hash(r.x, pk.x, msg32) */ using var sha = new SHA256(); sha.InitializeTagged(TAG_BIP0340Challenge); rx.fe.WriteToSpan(buf); sha.Write(buf); sha.Write(pk_buf); sha.Write(msg32); sha.GetHash(buf); if (!pubkey.TryMultTweak(buf, out var pubkey_ge) || pubkey_ge is null) { return(false); } if (!GE.TryCreateXQuad(rx.fe, out var rx_ge)) { return(false); } var pubkey_gej = pubkey_ge.Q.ToGroupElementJacobian(); var sigpoint_gej = pubkey_gej + rx_ge; var sigpoint_ge = sigpoint_gej.ToGroupElement(); sigpoint = new ECPubKey(sigpoint_ge, pubkey.ctx); return(true); }
public void ShouldEncodeAddress() { var privateKey = Encoders.Hex.DecodeData("08089C24EC3BAEB34254DDF5297CF8FBB8E031496FF67B4EFACA738FF9EBD455"); NBitcoin.Secp256k1.ECPrivKey privKey = Context.Instance.CreateECPrivKey(new Scalar(privateKey)); ECPubKey pubKey = privKey.CreatePubKey(); var x = pubKey.Q.x.ToBytes(); var y = pubKey.Q.y.ToBytes(); var pubKeyUncomp = Helper.Concat(x, y); Assert.AreEqual( "ee63599802b5d31a29c95cc7df04f427e8f0a124bed9333f3a80404acfc3127659c540d0162dedb81ac5f74b2deb4962656efe112b252e54ac3ba1207cd1fb10", Encoders.Hex.EncodeData(pubKeyUncomp) ); var pubKeyHash = new Sha3Keccack().CalculateHash(pubKeyUncomp); Assert.AreEqual("0837725ba59e30e8e52ba5ab95679f3aaf5211991781d49b30525dddfe9a18de", pubKeyHash.ToHexString()); var sha3HashBytes = new byte[20]; Array.Copy(pubKeyHash, pubKeyHash.Length - 20, sha3HashBytes, 0, 20); byte[] PKHWithVersionBytes = Helper.Concat(new byte[] { 65 }, sha3HashBytes); var hexAddress = PKHWithVersionBytes.ToHexString(); Assert.AreEqual("4195679F3AAF5211991781D49B30525DDDFE9A18DE".ToLower(), hexAddress); var result = Encoders.Base58Check.EncodeData(PKHWithVersionBytes); Assert.AreEqual( "TPbBpRXnt6ztse8XkCLiJstZyqQZvxW2sx", result ); }
public void CreateAddress() { Console.WriteLine(); // Priv key length int KEY_SIZE = 32; // Max priv key value // 115792089237316195423570985008687907852837564279074904382605163141518161494337 uint256 N = uint256.Parse("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); // Randomizer Random rand = new Random(); byte[] privateKey = new byte[KEY_SIZE]; // Generate a valid random value uint256 candidateKey; do { rand.NextBytes(privateKey); candidateKey = new uint256(privateKey, false); } while (!(candidateKey > 0 && candidateKey < N)); Console.WriteLine($"Private key (hex) : { Encoders.Hex.EncodeData(privateKey) }"); // base58 encoded private key byte[] privKeyWithVersionBytes = Helper.Concat(new byte[] { 128 }, privateKey); string privKeyBase58 = Encoders.Base58Check.EncodeData(privKeyWithVersionBytes); Console.WriteLine($"Priv. key (Base58) : {privKeyBase58}"); // base58 encoded compressed private key byte[] compPrivKeyWithVersionBytes = Helper.Concat(privKeyWithVersionBytes, new byte[] { 01 }); var compPrivKeyBase58 = Encoders.Base58Check.EncodeData(compPrivKeyWithVersionBytes); Console.WriteLine($"Priv. key (Base58) : {compPrivKeyBase58} (Compressed)"); // Elliptic curve multiplication (with help of NBitcoin) // privateKey = Encoders.Hex.DecodeData("da7639a9e2ed4e918b57151509ee34b3f80ad4ab60fb52de59cc3a7386b19007"); // for testing NBitcoin.Secp256k1.ECPrivKey privKey = Context.Instance.CreateECPrivKey(new Scalar(privateKey)); ECPubKey pubKey = privKey.CreatePubKey(); // X, Y var x = pubKey.Q.x.ToBytes(); var y = pubKey.Q.y.ToBytes(); // Uncompressed public key var pubKeyUncomp = Helper.Concat(new byte[] { (04) }, x, y); Console.WriteLine($"Pub key (uncomp.) : {Encoders.Hex.EncodeData(pubKeyUncomp)}"); // Compressed public key BigInteger yBig = new BigInteger(y, isUnsigned: true, isBigEndian: true); var pubKeyComp = Helper.Concat(new byte[] { (byte)(yBig % 2 == 0 ? 02 : 03) }, x); Console.WriteLine($"Pub key (comp.) : {Encoders.Hex.EncodeData(pubKeyComp)}"); //// Uncompressed Public Key // Public key hash (pkh) var pubKeyHash = NBitcoin.Crypto.Hashes.SHA256(pubKeyUncomp); var pubKeyHash160 = NBitcoin.Crypto.Hashes.RIPEMD160(pubKeyHash, pubKeyHash.Length); Console.WriteLine($"Public key hash : {Encoders.Hex.EncodeData(pubKeyHash160)}"); // base58 encoded pkh : address byte[] PKHWithVersionBytes = Helper.Concat(new byte[] { 00 }, pubKeyHash160); var address = Encoders.Base58Check.EncodeData(PKHWithVersionBytes); Assert.DoesNotThrow(() => { BitcoinAddress.Create(str: address, Network.Main); }); Console.WriteLine($"Address : {address}"); //// Uncompressed Public Key (w/ checksum calculation) var hash1 = NBitcoin.Crypto.Hashes.SHA256(PKHWithVersionBytes); var hash2 = NBitcoin.Crypto.Hashes.SHA256(hash1); var checksum = hash2.Take(4).ToArray(); var pkhWithChecksum = Helper.Concat(PKHWithVersionBytes, checksum); var address1 = Encoders.Base58.EncodeData(pkhWithChecksum); Assert.AreEqual(address, address1); //// Compressed Public Key // Public key hash (Compressed) var pubKeyCompHash = NBitcoin.Crypto.Hashes.SHA256(pubKeyComp); var pubKeyCompHash160 = NBitcoin.Crypto.Hashes.RIPEMD160(pubKeyCompHash, pubKeyCompHash.Length); // base58 encoded compressed pkh : address byte[] compPKHWithVersionBytes = Helper.Concat(new byte[] { 00 }, pubKeyCompHash160); var addressComp = Encoders.Base58Check.EncodeData(compPKHWithVersionBytes); Assert.DoesNotThrow(() => { BitcoinAddress.Create(str: addressComp, Network.Main); }); Console.WriteLine($"Address (Comp.) : {addressComp}"); }
public static bool TrySignAdaptor(this ECPrivKey key, ReadOnlySpan <byte> msg32, ECPubKey adaptor, out SecpECDSAAdaptorSignature?adaptorSignature, out SecpECDSAAdaptorProof?proof) { if (key == null) { throw new ArgumentNullException(nameof(key)); } if (adaptor == null) { throw new ArgumentNullException(nameof(adaptor)); } if (msg32.Length < 32) { throw new ArgumentException(paramName: nameof(msg32), message: "msg32 should be at least 32 bytes"); } var adaptor_ge = adaptor.Q; var seckey32 = key.sec; SHA256 sha = new SHA256(); sha.Write(msg32.Slice(0, 32)); Span <byte> buf33 = stackalloc byte[33]; Internals.secp256k1_dleq_serialize_point(buf33, adaptor_ge); sha.Write(buf33); sha.GetHash(buf33); Span <byte> nonce32 = stackalloc byte[32]; nonce_function_dleq(buf33, key.sec, "ECDSAAdaptorNon", nonce32); var k = new Scalar(nonce32); if (k.IsZero) { adaptorSignature = default; proof = default; return(false); } var rpj = key.ctx.EcMultGenContext.MultGen(k); /* 2. R = k*Y; */ var rj = adaptor_ge.MultConst(k, 256); /* 4. [sic] proof = DLEQ_prove((G,R'),(Y, R)) */ if (!key.ctx.EcMultGenContext.secp256k1_dleq_proof("ECDSAAdaptorSig", k, adaptor_ge, out var dleq_proof_s, out var dleq_proof_e)) { adaptorSignature = default; proof = default; return(false); } /* 5. s' = k⁻¹(H(m) + x_coord(R)x) */ var r = rj.ToGroupElement(); var msg = new Scalar(msg32); if (!secp256k1_ecdsa_adaptor_sign_helper(msg, k, r, key.sec, out var sp)) { k = default; adaptorSignature = default; proof = default; return(false); } /* 6. return (R, R', s', proof) */ var rp = rpj.ToGroupElement(); proof = new SecpECDSAAdaptorProof(rp, dleq_proof_s, dleq_proof_e); adaptorSignature = new SecpECDSAAdaptorSignature(r, sp); k = default; return(true); }
internal MusigPubNonce(ECPubKey k1, ECPubKey k2) { this.k1 = k1; this.k2 = k2; this.context = k1.ctx; }