public void MultipleSignatureWays() { var privKeyStr = Encoders.Hex.DecodeData("8e812436a0e3323166e1f0e8ba79e19e217b2c4a53c970d4cca0cfb1078979df"); Key key = new Key(privKeyStr); Assert.AreEqual("04a5bb3b28466f578e6e93fbfd5f75cee1ae86033aa4bbea690e3312c087181eb366f9a1d1d6a437a9bf9fc65ec853b9fd60fa322be3997c47144eb20da658b3d1", key.PubKey.Decompress().ToHex()); var messageToSign = "159817a085f113d099d3d93c051410e9bfe043cc5c20e43aa9a083bf73660145"; var messageBytes = Encoders.Hex.DecodeData(messageToSign); ECDSASignature signature = key.Sign(new uint256(messageBytes), true); SecpECDSASignature.TryCreateFromDer(signature.ToDER(), out SecpECDSASignature sig); var(r, s) = sig; var R = r.ToBytes(); var S = s.ToBytes(); Assert.AreEqual("38b7dac5ee932ac1bf2bc62c05b792cd93c3b4af61dc02dbb4b93dacb758123f", R.ToHexString()); Assert.AreEqual("08bf123eabe77480787d664ca280dc1f20d9205725320658c39c6c143fd5642d", S.ToHexString()); // Compact signature byte[] signatureCompact = key.SignCompact(new uint256(messageBytes), true); if (signatureCompact.Length != 65) { throw new ArgumentException(paramName: nameof(signatureCompact), message: "Signature truncated, expected 65"); } var ss = signatureCompact.AsSpan(); int recid = (ss[0] - 27) & 3; if (!( SecpRecoverableECDSASignature.TryCreateFromCompact(ss.Slice(1), recid, out SecpRecoverableECDSASignature sigR) && sigR is SecpRecoverableECDSASignature ) ) { throw new InvalidOperationException("Impossible to recover the public key"); } // V from comapct signature var(r1, s1, v1) = sigR; Assert.AreEqual(v1, 0); // Recoverable signature with Secp256k1 lib NBitcoin.Secp256k1.ECPrivKey privKey = Context.Instance.CreateECPrivKey(new Scalar(key.ToBytes())); Assert.AreEqual(key.PubKey.ToBytes(), privKey.CreatePubKey().ToBytes()); privKey.TrySignRecoverable(messageBytes, out SecpRecoverableECDSASignature sigRec); var(r2, s2, v2) = sigRec; Assert.AreEqual(r2, r); Assert.AreEqual(s2, s); Assert.AreEqual(v2, v1); }
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 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}"); }