Пример #1
0
        static void Main(string[] args)
        {
            // ---------------------------------------------------------

            // You only have to share one address with the world (called StealthAddress) without leaking any privacy.
            // If you share one BitcoinAddress with everybody, then all can see your balance by consulting the blockchain.
            // A better name than "dark" would've been "One Address".
            // The Payer can use the StealthAddress to generate many new addresses.
            // All the coins distributed among these throwaway addresses will be spendable by the Receiver.
            // Only the Payer and the Receiver knows that the addresses generated are related, a third party investigating the blockchain doesn't.

            // The Payer knows the StealthAddress of the Receiver.
            // The Receiver knows the Spend Key, a secret that will allow him to spend the coins received.
            // The Scanner knows the Scan key, a secret that allows him to detect the transactions that belong to the Receiver.

            // Underneath, the StealthAddress is composed of one or several SpendPubKeys and one ScanPubKey.

            var scanKey  = new Key();
            var spendKey = new Key();
            BitcoinStealthAddress stealthAddress = new BitcoinStealthAddress(
                scanKey.PubKey,
                new[] { spendKey.PubKey },
                signatureCount: 1,
                bitfield: null,
                network: Network.Main
                );

            Console.ReadLine();
        }
Пример #2
0
 public StealthCoin(OutPoint outpoint, TxOut txOut, Script redeem, StealthMetadata stealthMetadata, BitcoinStealthAddress address)
     : base(outpoint, txOut)
 {
     StealthMetadata = stealthMetadata;
     Address         = address;
     Redeem          = redeem;
 }
Пример #3
0
        static Transaction SenderCreateTransaction(BitcoinStealthAddress address)
        {
            Transaction transaction = new Transaction();

            address.SendTo(transaction, new Money(3, MoneyUnit.BTC));
            return(transaction);
        }
        private void FormDetails_Load(object sender, EventArgs e)
        {
            string address        = "";
            string bitcoinAddress = "";
            string hash           = "";
            string script         = "";
            string base58Type     = "";
            Type   type           = Address.GetType();

            using (new HourGlass())
            {
                switch (type.ToString())
                {
                case "NBitcoin.BitcoinScriptAddress":
                    BitcoinScriptAddress bsa = Address as BitcoinScriptAddress;
                    bitcoinAddress = bsa.ToString();
                    hash           = bsa.Hash.ToString();
                    script         = bsa.ScriptPubKey.ToString();
                    base58Type     = bsa.Type.ToString();
                    break;

                case "NBitcoin.BitcoinAddress":
                    BitcoinAddress ba = Address as BitcoinAddress;
                    bitcoinAddress = ba.ToString();
                    hash           = ba.Hash.ToString();
                    script         = ba.ScriptPubKey.ToString();
                    base58Type     = ba.Type.ToString();
                    break;

                case "NBitcoin.Stealth.BitcoinStealthAddress":
                    BitcoinStealthAddress stealth = Address as BitcoinStealthAddress;
                    bitcoinAddress = stealth.ToString();
                    hash           = stealth.ScanPubKey.Hash.ToString();
                    script         = stealth.ScanPubKey.ScriptPubKey.ToString();
                    base58Type     = stealth.Type.ToString();
                    break;

                case "NBitcoin.BitcoinColoredAddress":
                    BitcoinColoredAddress colored = Address as BitcoinColoredAddress;
                    address        = colored.ToString();
                    bitcoinAddress = colored.Address.ToString();
                    hash           = colored.Address.Hash.ToString();
                    script         = colored.ScriptPubKey.ToString();
                    base58Type     = colored.Type.ToString();
                    break;

                default:
                    textBoxType.Text = type.ToString();
                    break;
                }
            }

            textBoxAddress.Text        = address;
            textBoxBitcoinAddress.Text = bitcoinAddress;
            textBoxPubHash.Text        = hash;
            textBoxScriptPubKey.Text   = script;
            textBoxType.Text           = base58Type;

            textBoxBitcoinAddress.Focus();
        }
Пример #5
0
        private static void PlaySplit()
        {
            var scan = new Key(TestUtils.ParseHex("cc411aab02edcd3bccf484a9ba5280d4a774e6f81eac8ebec9cb1c2e8f73020a"));
            var addr = new BitcoinStealthAddress("waPYjXyrTrvXjZHmMGdqs9YTegpRDpx97H5G3xqLehkgyrrZKsxGCmnwKexpZjXTCskUWwYywdUvrZK7L2vejeVZSYHVns61gm8VfU", Network.TestNet);

            var sender   = new BitcoinSecret("privatekey", Network.TestNet);
            var receiver = new BitcoinSecret("privatekey", Network.TestNet);

            MakePayment(sender, receiver, Money.Parse("1.00"));
        }
Пример #6
0
        /// <summary>
        /// Scan the Transaction for StealthCoin given address and scan key
        /// </summary>
        /// <param name="tx">The transaction to scan</param>
        /// <param name="address">The stealth address</param>
        /// <param name="scan">The scan private key</param>
        /// <returns></returns>
        public static StealthCoin Find(Transaction tx, BitcoinStealthAddress address, Key scan)
        {
            var payment = address.GetPayments(tx, scan).FirstOrDefault();

            if (payment == null)
            {
                return(null);
            }
            var txId  = tx.GetHash();
            var txout = tx.Outputs.First(o => o.ScriptPubKey == payment.ScriptPubKey);

            return(new StealthCoin(new OutPoint(txId, tx.Outputs.IndexOf(txout)), txout, payment.Redeem, payment.Metadata, address));
        }
Пример #7
0
 public StealthPaymentScanner(BitcoinStealthAddress address, Key scan)
 {
     if (address == null)
     {
         throw new ArgumentNullException("address");
     }
     if (scan == null)
     {
         throw new ArgumentNullException("scan");
     }
     _Address = address;
     _Scan    = scan;
 }
        public void CanParseStealthAddress()
        {
            var tests = new[]
            {
                //Test vector created with sx
                //sx stealth-newkey -> ScanSecret,SpendSecret,StealthAddress
                //sx stealth-show-addr StealthAddress -> ScanPubKey,SpendPubKey,RequiredSignature...
                new
                {
                    ScanSecret   = "9ac9fdee7c2c19611bcbed8959e1c61d00cdc27cf17bb50a1f4d29db7f953632",
                    SpendSecrets = new[] {
                        "4e2fa767cc241c3fa4c512d572b2758a3960a06d374f2c819fe409b161d72ad4"
                    },
                    StealthAddress = "vJmsmwE8cVt9ytJxBuY2jayh8RAfvpG42CyNVYpeVZAkHaiwASobUEzskpXMwbH1TZNBLoxWWYem5WuZewTL8xz3upJ75zKcdVmTfg",
                    ScanPubKey     = "021ce89be99a229d123e8bc13ffbcb66722d6200bbeb1d90ddddbf97df82ed2672",
                    SpendPubKeys   = new[]
                    {
                        "03c197525241d3d70bbf33bb2b54d41e6b9595a92a2c6b7bf7157727c017f0154a"
                    },
                    RequiredSignature = 1,
                    Options           = 0,
                    PrefixLength      = 0,
                    PrefixValue       = "",
                }
            };

            foreach (var test in tests)
            {
                var scanSecret = new Key(TestUtils.ParseHex(test.ScanSecret));
                AssertEx.CollectionEquals(scanSecret.PubKey.ToBytes(), TestUtils.ParseHex(test.ScanPubKey));

                var stealth = new BitcoinStealthAddress(test.StealthAddress, Network.Main);
                Assert.Equal(test.RequiredSignature, stealth.SignatureCount);
                Assert.Equal(test.PrefixLength, stealth.Prefix.BitCount);
                AssertEx.CollectionEquals(stealth.Prefix.GetRawForm(), TestUtils.ParseHex(test.PrefixValue));
                Assert.Equal(test.Options, stealth.Options);

                AssertEx.CollectionEquals(stealth.ScanPubKey.ToBytes(),
                                          TestUtils.ParseHex(test.ScanPubKey));
                for (int i = 0; i < test.SpendPubKeys.Length; i++)
                {
                    AssertEx.CollectionEquals(stealth.SpendPubKeys[i].ToBytes(),
                                              TestUtils.ParseHex(test.SpendPubKeys[i]));

                    var spendSecret = new Key(TestUtils.ParseHex(test.SpendSecrets[i]));
                    AssertEx.CollectionEquals(stealth.SpendPubKeys[i].ToBytes(), TestUtils.ParseHex(test.SpendPubKeys[i]));
                }
            }
        }
Пример #9
0
        public void CanBuildStealthTransaction()
        {
            var stealthKeys = Enumerable.Range(0, 3).Select(_ => new Key()).ToArray();
            var scanKey     = new Key();

            var darkSatoshi = new BitcoinStealthAddress(scanKey.PubKey, stealthKeys.Select(k => k.PubKey).ToArray(), 2, new BitField(3, 5), NBitcoin.Networks.NetworkRegistration.GetNetworks().FirstOrDefault());

            Console.WriteLine("darkSatoshi " + darkSatoshi);

            var bob = new Key();

            Console.WriteLine("bob wif" + bob.GetWif(NBitcoin.Networks.NetworkRegistration.GetNetworks().FirstOrDefault()));
            var coins = new Coin[] {
                new Coin()
                {
                    Outpoint = RandOutpoint(),
                    TxOut    = new TxOut("1.00", bob.PubKey.Hash)
                }
            };

            //Bob sends money to satoshi
            TransactionBuilder builder = new TransactionBuilder(NBitcoin.Networks.NetworkRegistration.GetNetworks().FirstOrDefault());
            var tx =
                builder
                .AddCoins(coins)
                .AddKeys(bob)
                .Send(darkSatoshi, "1.00")
                .BuildTransaction(true);

            Console.WriteLine(tx);
            //		Assert.True(builder.Verify(tx));

            //Satoshi scans a StealthCoin in the transaction with his scan key
            var stealthCoin = StealthCoin.Find(tx, darkSatoshi, scanKey);

            //		Assert.NotNull(stealthCoin);

            //Satoshi sends back the money to Bob
            builder = new TransactionBuilder(NBitcoin.Networks.NetworkRegistration.GetNetworks().FirstOrDefault());
            tx      =
                builder
                .AddCoins(stealthCoin)
                .AddKeys(stealthKeys)
                .AddKeys(scanKey)
                .Send(bob.PubKey.Hash, "1.00")
                .BuildTransaction(true);

            //	Assert.True(builder.Verify(tx)); //Signed !
        }
Пример #10
0
        static BitcoinStealthAddress ReceiverCreateStealthAddress()
        {
            var scanKey  = new Key();
            var spendKey = new Key();
            BitcoinStealthAddress stealthAddress
                = new BitcoinStealthAddress
                  (
                      scanKey: scanKey.PubKey,
                      pubKeys: new[] { spendKey.PubKey },
                      signatureCount: 1,
                      bitfield: null,
                      network: Network.Main);

            return(stealthAddress);
        }
Пример #11
0
        private void Code11()
        {
            var scanKey  = new Key();
            var spendKey = new Key();
            BitcoinStealthAddress stealthAddress
                = new BitcoinStealthAddress
                  (
                      scanKey: scanKey.PubKey,
                      pubKeys: new[] { spendKey.PubKey },
                      signatureCount: 1,
                      bitfield: null,
                      network: Network.Main);


            var            ephem   = new Key();
            StealthPayment payment = stealthAddress.CreatePayment(ephem);

            Transaction transaction = new Transaction();

            payment.AddToTransaction(transaction, Money.Coins(1.0m));
            Console.WriteLine(transaction);

            payment = stealthAddress.GetPayments(transaction, scanKey).FirstOrDefault();

            //Optional check (GetPayment already do it)
            BitcoinAddress expectedAddress = payment.StealthKeys[0].GetAddress(Network.Main);
            bool           hasPayment      = transaction
                                             .Outputs
                                             .Any(o => o.ScriptPubKey.GetDestinationAddress(Network.Main) == expectedAddress);

            Console.WriteLine(hasPayment);
            ////

            payment = stealthAddress.GetPayments(transaction, scanKey).FirstOrDefault();
            Key privateKey = spendKey.Uncover(scanKey, payment.Metadata.EphemKey);

            expectedAddress = privateKey.PubKey.GetAddress(Network.Main);
            bool isRightKey = transaction
                              .Outputs
                              .Any(o => o.ScriptPubKey.GetDestinationAddress(Network.Main) == expectedAddress);

            Console.WriteLine(isRightKey);
        }
Пример #12
0
        static void BookExamples()
        {
            var scanKey  = new Key();
            var spendKey = new Key();
            BitcoinStealthAddress stealthAddress
                = new BitcoinStealthAddress
                  (
                      scanKey: scanKey.PubKey,
                      pubKeys: new[] { spendKey.PubKey },
                      signatureCount: 1,
                      bitfield: null,
                      network: Network.Main);

            var         ephemKey    = new Key();
            Transaction transaction = new Transaction();

            stealthAddress.SendTo(transaction, Money.Coins(1.0m), ephemKey);
            UnityEngine.Debug.Log(transaction);
        }
Пример #13
0
        public static void Execute()
        {
            // Dark Wallets are not in use anymore
            var scanKey  = new Key();
            var spendKey = new Key();
            BitcoinStealthAddress stealthAddress
                = new BitcoinStealthAddress(
                      scanKey: scanKey.PubKey,
                      pubKeys: new[] { spendKey.PubKey },
                      signatureCount: 1,
                      bitfield: null,
                      network: Network.Main);

            var         ephemKey    = new Key();
            Transaction transaction = new Transaction();

            stealthAddress.SendTo(transaction, Money.Coins(1.0m), ephemKey);
            Console.WriteLine(transaction);

            //Transaction transaction = new Transaction();
            stealthAddress.SendTo(transaction, Money.Coins(1.0m));
            Console.WriteLine(transaction);
        }
Пример #14
0
        private static void PlaySplit()
        {
            var scan = new Key(TestUtils.ParseHex("cc411aab02edcd3bccf484a9ba5280d4a774e6f81eac8ebec9cb1c2e8f73020a"));
            var addr = new BitcoinStealthAddress("waPYjXyrTrvXjZHmMGdqs9YTegpRDpx97H5G3xqLehkgyrrZKsxGCmnwKexpZjXTCskUWwYywdUvrZK7L2vejeVZSYHVns61gm8VfU", Network.TestNet);

            var sender = new BitcoinSecret("cRjSUV1LqN2F8MsGnLE2JKfCP75kbWGFRroNQeXHC429jqVFgmW3", Network.TestNet);
            var tx     = new Transaction();

            tx.Version = 1;

            RPCClient client = RPCClientTests.CreateRPCClient();
            var       coins  = client.ListUnspent();

            foreach (var unspent in coins)
            {
                tx.Inputs.Add(new TxIn(unspent.OutPoint));
            }
            var amount = coins.Select(c => c.Amount).Sum();

            var perOut = (long)(amount.Satoshi / 13);

            while (amount > 0)
            {
                var toSend = Math.Min(perOut, (long)amount);
                amount -= toSend;

                var tout = new TxOut(toSend, sender.GetAddress());
                if (!tout.IsDust)
                {
                    tx.Outputs.Add(tout);
                }
            }

            tx.SignAll(sender);
            client.SendRawTransaction(tx);
        }
Пример #15
0
        private static void PlaySplit()
        {
            var scan = new Key(TestUtils.ParseHex("cc411aab02edcd3bccf484a9ba5280d4a774e6f81eac8ebec9cb1c2e8f73020a"));
            var addr = new BitcoinStealthAddress("waPYjXyrTrvXjZHmMGdqs9YTegpRDpx97H5G3xqLehkgyrrZKsxGCmnwKexpZjXTCskUWwYywdUvrZK7L2vejeVZSYHVns61gm8VfU", Network.TestNet);

            var sender = new BitcoinSecret("cRjSUV1LqN2F8MsGnLE2JKfCP75kbWGFRroNQeXHC429jqVFgmW3", Network.TestNet);
            var tx = new Transaction();
            tx.Version = 1;

            RPCClient client = RPCClientTests.CreateRPCClient();
            var coins = client.ListUnspent();
            foreach(var unspent in coins)
            {
                tx.Inputs.Add(new TxIn(unspent.OutPoint));
            }
            var amount = coins.Select(c => c.Amount).Sum();

            var perOut = (long)(amount.Satoshi / 13);

            while(amount > 0)
            {
                var toSend = Math.Min(perOut, (long)amount);
                amount -= toSend;

                var tout = new TxOut(toSend, sender.GetAddress());
                if(!tout.IsDust)
                    tx.Outputs.Add(tout);
            }

            tx.SignAll(sender);
            client.SendRawTransaction(tx);
        }
Пример #16
0
        static void Main()
        {
            /* Create a fake transaction */
            var bob     = new Key();
            var alice   = new Key();
            var satoshi = new Key();

            Script bobAlice =
                PayToMultiSigTemplate.Instance.GenerateScriptPubKey(
                    2,
                    bob.PubKey, alice.PubKey);

            var init = new Transaction();

            init.Outputs.Add(new TxOut(Money.Coins(1m), bob.PubKey));        // P2PK
            init.Outputs.Add(new TxOut(Money.Coins(1m), alice.PubKey.Hash)); // P2PKH
            init.Outputs.Add(new TxOut(Money.Coins(1m), bobAlice));

            /* Get the coins of the initial transaction */
            Coin[] coins = init.Outputs.AsCoins().ToArray();

            Coin bobCoin      = coins[0];
            Coin aliceCoin    = coins[1];
            Coin bobAliceCoin = coins[2];

            /* Build the transaction */
            var         builder = new TransactionBuilder();
            Transaction tx      = builder
                                  .AddCoins(bobCoin)
                                  .AddKeys(bob)
                                  .Send(satoshi, Money.Coins(0.2m))
                                  .SetChange(bob)
                                  .Then()
                                  .AddCoins(aliceCoin)
                                  .AddKeys(alice)
                                  .Send(satoshi, Money.Coins(0.3m))
                                  .SetChange(alice)
                                  .Then()
                                  .AddCoins(bobAliceCoin)
                                  .AddKeys(bob, alice)
                                  .Send(satoshi, Money.Coins(0.5m))
                                  .SetChange(bobAlice)
                                  .SendFees(Money.Coins(0.0001m))
                                  .BuildTransaction(sign: true);


            /* Verify you did not screw up */
            Console.WriteLine(builder.Verify(tx)); // True



            /* ScriptCoin */
            init = new Transaction();
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), bobAlice.Hash));

            coins = init.Outputs.AsCoins().ToArray();
            ScriptCoin bobAliceScriptCoin = coins[0].ToScriptCoin(bobAlice);

            builder = new TransactionBuilder();
            tx      = builder
                      .AddCoins(bobAliceScriptCoin)
                      .AddKeys(bob, alice)
                      .Send(satoshi, Money.Coins(0.9m))
                      .SetChange(bobAlice.Hash)
                      .SendFees(Money.Coins(0.0001m))
                      .BuildTransaction(true);
            Console.WriteLine(builder.Verify(tx)); // True



            /* STEALTH COIN */

            Key scanKey = new Key();
            BitcoinStealthAddress darkAliceBob =
                new BitcoinStealthAddress
                (
                    scanKey: scanKey.PubKey,
                    pubKeys: new[] { alice.PubKey, bob.PubKey },
                    signatureCount: 2,
                    bitfield: null,
                    network: Network.Main
                );

            //Someone sent to darkAliceBob
            init = new Transaction();
            darkAliceBob
            .SendTo(init, Money.Coins(1.0m));

            //Get the stealth coin with the scanKey
            StealthCoin stealthCoin
                = StealthCoin.Find(init, darkAliceBob, scanKey);

            //Spend it
            tx = builder
                 .AddCoins(stealthCoin)
                 .AddKeys(bob, alice, scanKey)
                 .Send(satoshi, Money.Coins(0.9m))
                 .SetChange(bobAlice.Hash)
                 .SendFees(Money.Coins(0.0001m))
                 .BuildTransaction(true);
            Console.WriteLine(builder.Verify(tx)); // True

            Console.ReadLine();
        }
Пример #17
0
        private static void KeyGenerationAndEncryption()
        {
            // 02.01. Key Generation
            RandomUtils.AddEntropy("hello");
            RandomUtils.AddEntropy(new byte[] { 1, 2, 3 });
            var nsaProofKey = new Key();

            Console.WriteLine("Key with entropy " + nsaProofKey.GetBitcoinSecret(Network.TestNet));

            var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 });

            RandomUtils.AddEntropy(derived);

            var privateKey = new Key();
            var privateKeyBitcoinSecret = privateKey.GetWif(Network.TestNet);

            Console.WriteLine(privateKeyBitcoinSecret); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r
            BitcoinEncryptedSecret bitcoinEncryptedSecret = privateKeyBitcoinSecret.Encrypt("password");

            Console.WriteLine(bitcoinEncryptedSecret); // 6PYKYQQgx947Be41aHGypBhK6TA5Xhi9TdPBkatV3fHbbKrdDoBoXFCyLK
            var decryptedBitcoinPrivateKey = bitcoinEncryptedSecret.GetSecret("password");

            Console.WriteLine(decryptedBitcoinPrivateKey); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r

            //02.02 BIP38 and HD (Hierarchical Deterministic) Wallet
            var passphraseCode = new BitcoinPassphraseCode("my secret", Network.TestNet, null);
            // we give this passphraseCode to 3rd party
            EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret();
            var generatedAddress     = encryptedKeyResult.GeneratedAddress;
            var encryptedKeySecretEc = encryptedKeyResult.EncryptedKey;
            var confirmationCode     = encryptedKeyResult.ConfirmationCode;

            Console.WriteLine(confirmationCode.Check("my secret", generatedAddress)); // True
            var privateKeyBitcoinSecret1 = encryptedKeySecretEc.GetSecret("my secret");

            Console.WriteLine(privateKeyBitcoinSecret1.GetAddress() == generatedAddress); // True
            Console.WriteLine(privateKeyBitcoinSecret1);                                  // KzzHhrkr39a7upeqHzYNNeJuaf1SVDBpxdFDuMvFKbFhcBytDF1R

            ExtKey masterKey = new ExtKey();

            Console.WriteLine("Master key : " + masterKey.ToString(Network.TestNet));
            for (int i = 0; i < 5; i++)
            {
                ExtKey extKey1 = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + extKey1.ToString(Network.TestNet));
            }

            ExtKey extKey = new ExtKey();

            byte[] chainCode = extKey.ChainCode;
            Key    key       = extKey.PrivateKey;

            ExtKey newExtKey = new ExtKey(key, chainCode);

            ExtPubKey masterPubKey = masterKey.Neuter();

            for (int i = 0; i < 5; i++)
            {
                ExtPubKey pubkey = masterPubKey.Derive((uint)i);
                Console.WriteLine("PubKey " + i + " : " + pubkey.ToString(Network.TestNet));
            }

            ExtKey key1 = masterKey.Derive(4);

            //Check it is legit
            var generatedAddr = masterPubKey.Derive(4).PubKey.GetAddress(Network.TestNet);
            var expectedAddr  = key1.PrivateKey.PubKey.GetAddress(Network.TestNet);

            Console.WriteLine("Generated address : " + generatedAddr);
            Console.WriteLine("Expected address : " + expectedAddr);

            ExtKey parent      = new ExtKey();
            ExtKey child11     = parent.Derive(1).Derive(1);
            ExtKey sameChild11 = parent.Derive(new KeyPath("1/1"));

            Console.WriteLine("child11 : " + child11.PrivateKey.PubKey.GetAddress(Network.TestNet));
            Console.WriteLine("child11.PrivateKey == sameChild11.PrivateKey : " +
                              (child11.PrivateKey == sameChild11.PrivateKey));

            ExtKey ceoKey = new ExtKey();

            Console.WriteLine("CEO: " + ceoKey.ToString(Network.TestNet));
            ExtKey notHardenedAccountingKey = ceoKey.Derive(0, hardened: false);

            ExtPubKey ceoPubkey = ceoKey.Neuter();

            //Recover ceo key with accounting private key and ceo public key
            ExtKey ceoKeyRecovered = notHardenedAccountingKey.GetParentExtKey(ceoPubkey);

            Console.WriteLine("CEO recovered: " + ceoKeyRecovered.ToString(Network.TestNet));

            ExtKey hardenedAccountingKey = ceoKey.Derive(0, hardened: true);
            // ExtKey ceoKeyRecovered2 = hardenedAccountingKey.GetParentExtKey(ceoPubkey); => //throws exception

            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve); // generate random 12 words list
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            mnemo = new Mnemonic("minute put grant neglect anxiety case globe win famous correct turn link",
                                 Wordlist.English);
            hdRoot = mnemo.DeriveExtKey("my password");
            Console.WriteLine(mnemo);
            Console.WriteLine(hdRoot.ToString(Network.TestNet));

            var scanKey  = new Key();
            var spendKey = new Key();
            BitcoinStealthAddress stealthAddress
                = new BitcoinStealthAddress
                  (
                      scanKey: scanKey.PubKey,
                      pubKeys: new[] { spendKey.PubKey },
                      signatureCount: 1,
                      bitfield: null,
                      network: Network.TestNet);

            Transaction transaction = new Transaction();

            stealthAddress.SendTo(transaction, Money.Coins(1.0m));
            Console.WriteLine(transaction);

            // personal tests Mycelium
            mnemo  = new Mnemonic("artist tiger always access sport major donkey coil scale carry laptop ticket", Wordlist.English);
            hdRoot = mnemo.DeriveExtKey();//leave the password null as sample
            Console.WriteLine(hdRoot.ToString(Network.Main));
            var hardened2 = new KeyPath("44'/0'/0'/0/1");

            ExtKey paymentKey2 = hdRoot.Derive(hardened2);

            Console.WriteLine(hardened2 + ": " + paymentKey2.ScriptPubKey.GetDestinationAddress(Network.Main));
            Console.WriteLine(hardened2 + ": private " + paymentKey2.ToString(Network.Main));

            var    hardened1   = new KeyPath("44'/0'/0'/0/0");
            ExtKey paymentKey1 = hdRoot.Derive(hardened1);

            Console.WriteLine(hardened1 + ": " + paymentKey1.ScriptPubKey.GetDestinationAddress(Network.Main));
            Console.WriteLine(hardened1 + ": private " + paymentKey1.ToString(Network.Main));
        }
Пример #18
0
        static void Main()
        {
            //===========================================================================================
            //Chapter8. Using the TransactionBuilder

            //You have seen how the TransactionBuilder works when you have signed your first P2SH and multi-sig transaction.
            //We will see how you can harness its full power, for signing more complicated transactions.
            //With the TransactionBuilder you can:
            //1.Spend any
            //P2PK, P2PKH,
            //multi-sig,
            //P2WPK, P2WSH.
            //2.Spend any P2SH on the previous redeem script.
            //3.Spend Stealth Coin(DarkWallet).
            //4.Issue and transfer Colored Coins(open asset, following chapter).
            //5.Combine partially signed transactions.
            //6.Estimate the final size of an unsigned transaction and its fees.
            //7.Verify if a transaction is fully signed.

            //The goal of the TransactionBuilder is to take Coins and Keys as input, and return back a signed or partially signed transaction.
            //Picture depiction:
            //Coins -> Signed transaction(or it could be a signed transactions) <-Keys.


            //The TransactionBuilder will figure out what Coin to use and what to sign by itself.
            //Examine TransactionBuilder class containing lots of properties and methods.


            //The usage of the builder is done in four steps:
            //1.You gather the Coins that spent,
            //2.You gather the Keys that you own,
            //3.You enumerate how much Money you want to send to where scriptPubKey indicates,
            //4.You build and sign the transaction,
            //5.Optional: you give the transaction to somebody else, then he will sign or continue to build it.


            //Now let’s gather some Coins.
            //For that, let us create a fake transaction with some funds on it.
            //Let’s say that the transaction has a P2PKH, P2PK, and multi-sig coin of Bob and Alice.
            RandomUtils.Random = new UnsecureRandom();


            //Private key generator.
            Key           privateKeyGenerator = new Key();
            BitcoinSecret bitcoinSecretFromPrivateKeyGenerator = privateKeyGenerator.GetBitcoinSecret(Network.Main);
            Key           privateKeyFromBitcoinSecret          = bitcoinSecretFromPrivateKeyGenerator.PrivateKey;

            Console.WriteLine($"privateKeyFromBitcoinSecret.ToString(Network.Main): {privateKeyFromBitcoinSecret.ToString(Network.Main)}");
            //L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo is for Alice
            //KxMrK5EJeUZ1z3Jyo2zPkurRVtYFefab4WQitV5CyjKApHsWfWg9 is for Bob
            //KyStsAHgSehHvewS5YfGwhQGfEWYd8qY2XZg6q2M6TqaM8Q8rayg is for Satoshi
            //L2f9Ntm8UUeTLZFv25oZ8WoRW8kAofUjdUdtCq9axCp1hZrsLZja is for Nico

            BitcoinSecret bitcoinSecretForAlice   = new BitcoinSecret("L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo", Network.Main);
            BitcoinSecret bitcoinSecretForBob     = new BitcoinSecret("KxMrK5EJeUZ1z3Jyo2zPkurRVtYFefab4WQitV5CyjKApHsWfWg9", Network.Main);
            BitcoinSecret bitcoinSecretForSatoshi = new BitcoinSecret("KyStsAHgSehHvewS5YfGwhQGfEWYd8qY2XZg6q2M6TqaM8Q8rayg", Network.Main);
            BitcoinSecret bitcoinSecretForScanKey = new BitcoinSecret("L2f9Ntm8UUeTLZFv25oZ8WoRW8kAofUjdUdtCq9axCp1hZrsLZja", Network.Main);


            Key bobPrivateKey        = bitcoinSecretForAlice.PrivateKey;
            Key alicePrivateKey      = bitcoinSecretForBob.PrivateKey;
            Key satoshiPrivateKey    = bitcoinSecretForSatoshi.PrivateKey;
            Key privateKeyForScanKey = bitcoinSecretForScanKey.PrivateKey;



            Script scriptPubKeyOfBobAlice =
                PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, bobPrivateKey.PubKey, alicePrivateKey.PubKey);

            //This transaction will send money to Bob and Alice.
            //The thing you should notice is that this transaction is added by various types of scriptPubKey, such as P2PK(bobPrivateKey.PubKey), P2PKH(alicePrivateKey.PubKey.Hash), and multi-sig ScriptPubKey(scriptPubKeyOfBobAlice).
            var txGettingCoinForBobAlice = new Transaction();

            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), bobPrivateKey.PubKey));        // P2PK
            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), alicePrivateKey.PubKey.Hash)); // P2PKH
            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), scriptPubKeyOfBobAlice));

            //Now let’s say they want to use the coins of this transaction to pay Satoshi.

            //First they have to get their coins.
            Coin[] coins = txGettingCoinForBobAlice.Outputs.AsCoins().ToArray();

            Coin bobCoin      = coins[0];
            Coin aliceCoin    = coins[1];
            Coin bobAliceCoin = coins[2];

            //Now let’s say Bob wants to send 0.2 BTC, Alice 0.3 BTC, and they agree to use bobAlice to send 0.5 BTC.
            //Build the transaction by using the features of the TransactionBuilder class.
            var         builderForSendingCoinToSatoshi = new TransactionBuilder();
            Transaction txForSpendingCoinToSatoshi     = builderForSendingCoinToSatoshi
                                                         .AddCoins(bobCoin)
                                                         //PriveteKey of Bob to be used for signing.
                                                         .AddKeys(bobPrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.2m))
                                                         .SetChange(bobPrivateKey)
                                                         .Then()
                                                         .AddCoins(aliceCoin)
                                                         .AddKeys(alicePrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.3m))
                                                         .SetChange(alicePrivateKey)
                                                         .Then()
                                                         .AddCoins(bobAliceCoin)
                                                         .AddKeys(bobPrivateKey, alicePrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.5m))
                                                         .SetChange(scriptPubKeyOfBobAlice)
                                                         .SendFees(Money.Coins(0.0001m))
                                                         .BuildTransaction(sign: true);

            Console.WriteLine(txForSpendingCoinToSatoshi);

            //Then you can verify it is fully signed and ready to send to the network.
            //Verify you did not screw up.
            Console.WriteLine(builderForSendingCoinToSatoshi.Verify(txForSpendingCoinToSatoshi)); // True



            //============================================================================================
            //Do with a ScriptCoin.

            //The nice thing about this model is that it works the same way for P2SH, P2WSH, P2SH(P2WSH), and P2SH(P2PKH) except you need to create ScriptCoin.

            //Illustration:
            //Coin-> ScriptCoin <-RedeemScript.

            var txGettingScriptCoinForBobAlice = new Transaction();

            txGettingScriptCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1.0m), scriptPubKeyOfBobAlice.Hash));

            coins = txGettingScriptCoinForBobAlice.Outputs.AsCoins().ToArray();
            ScriptCoin bobAliceScriptCoin = coins[0].ToScriptCoin(scriptPubKeyOfBobAlice);

            //Then the signature:
            var builderForSendingScriptCoinToSatoshi = new TransactionBuilder();
            var txForSendingScriptCoinToSatoshi      = builderForSendingScriptCoinToSatoshi
                                                       .AddCoins(bobAliceScriptCoin)
                                                       .AddKeys(bobPrivateKey, alicePrivateKey)
                                                       .Send(satoshiPrivateKey, Money.Coins(0.9m))
                                                       .SetChange(scriptPubKeyOfBobAlice.Hash)
                                                       .SendFees(Money.Coins(0.0001m))
                                                       .BuildTransaction(true);

            Console.WriteLine(builderForSendingScriptCoinToSatoshi.Verify(txForSendingScriptCoinToSatoshi));
            //Output:
            //True


            //============================================================================================
            //Do with a StealthCoin.

            //For Stealth Coin, this is basically the same thing except that, if you remember our introduction on Dark Wallet, you need a ScanKey to see the StealthCoin.

            //Illustration:
            //ScanKey + Transaction + StealthAddress => StealthCoin.

            //Let’s create darkAliceBob stealth address as in previous chapter:


            BitcoinStealthAddress bitcoinStealthAddressForBobAlice =
                new BitcoinStealthAddress
                (
                    scanKey: privateKeyForScanKey.PubKey,
                    pubKeys: new[] { alicePrivateKey.PubKey, bobPrivateKey.PubKey },
                    signatureCount: 2,
                    bitfield: null,
                    network: Network.Main
                );


            //Let’s say someone sent the coin to this transaction via the darkAliceBob which is a BitcoinStealthAddress:
            var txGettingCoinForBobAliceToBitcoinStealthAddress = new Transaction();

            bitcoinStealthAddressForBobAlice
            .SendTo(txGettingCoinForBobAliceToBitcoinStealthAddress, Money.Coins(1.0m));

            //The scanner will detect the StealthCoin:
            //Get the stealth coin with the scanKey.
            StealthCoin stealthCoin
                = StealthCoin.Find(txGettingCoinForBobAliceToBitcoinStealthAddress, bitcoinStealthAddressForBobAlice, privateKeyForScanKey);

            //And forward it to Bob and Alice, who will sign:
            //Let Bob and Alice sign and spend the coin.
            TransactionBuilder builderForBobAliceToBitcoinStealthAddress = new TransactionBuilder();

            txGettingCoinForBobAliceToBitcoinStealthAddress = builderForBobAliceToBitcoinStealthAddress
                                                              .AddCoins(stealthCoin)
                                                              .AddKeys(bobPrivateKey, alicePrivateKey, privateKeyForScanKey)
                                                              .Send(satoshiPrivateKey, Money.Coins(0.9m))
                                                              .SetChange(scriptPubKeyOfBobAlice.Hash)
                                                              .SendFees(Money.Coins(0.0001m))
                                                              .BuildTransaction(true);
            Console.WriteLine(builderForBobAliceToBitcoinStealthAddress.Verify(txGettingCoinForBobAliceToBitcoinStealthAddress));
            //Output:
            //True

            //Note: You need the scanKey for spending a StealthCoin
        }
Пример #19
0
 public StealthPaymentScanner(BitcoinStealthAddress address, Key scan)
     : this(address.Prefix, address.SpendPubKeys, scan)
 {
 }
Пример #20
0
        private static void Main(string[] args)
        {
            // add entropy before creating key
            RandomUtils.AddEntropy("hello");
            RandomUtils.AddEntropy(new byte[] { 1, 2, 3 });

            // key created with added entropy
            var nsaProofKey = new Key();

            // What NBitcoin does when you call AddEntropy(data) is:
            // additionalEntropy = SHA(SHA(data) ^ additionalEntropy)

            // Then when you generate a new number:
            // result = SHA(PRNG() ^ additionalEntropy)

            // Key Derivation Function is a way to have a stronger key, even if your entropy is low
            // KDF is a hash function that wastes computing resources on purpose.

            var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 });

            RandomUtils.AddEntropy(derived);

            // even if attacker knows that your source of entropy contains 5 letters,
            // they will need to run Scrypt to check each possibility

            // standard for encrypting private key with a password using kdf is BIP38

            var privateKey        = new Key();
            var bitcoinPrivateKey = privateKey.GetWif(Network.Main);

            Console.WriteLine(bitcoinPrivateKey);

            BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password");

            Console.WriteLine(encryptedBitcoinPrivateKey);

            var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetKey("password");

            Console.WriteLine(decryptedBitcoinPrivateKey);

            Key keyFromIncorrectPassword = null;

            Exception error = null;

            try
            {
                keyFromIncorrectPassword = encryptedBitcoinPrivateKey.GetKey("lahsdlahsdlakhslkdash");
            }
            catch (Exception e)
            {
                error = e;
            }

            var result = keyFromIncorrectPassword != null
                ? keyFromIncorrectPassword.ToString()
                : $"{error?.GetType().Name ?? "Error"}: icorrect password";

            Console.WriteLine(result);


            // BIP 38
            // how to delegate Key and Address creation to an untrusted peer

            // create pass phrase code
            BitcoinPassphraseCode passphraseCode = new BitcoinPassphraseCode("my secret", Network.Main, null);

            Console.WriteLine(passphraseCode);

            // then give passPhraseCode to 3rd party key generator
            // third party can generate encrypted keys on your behalf
            // without knowing your password and private key.
            EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret();
            var generatedAddress = encryptedKeyResult.GeneratedAddress;
            var encryptedKey     = encryptedKeyResult.EncryptedKey;

            // used by 3rd party to confirm generated key and address correspond to password
            var confirmationCode = encryptedKeyResult.ConfirmationCode;

            // check
            var isValid = confirmationCode.Check("my secret", generatedAddress);

            Console.WriteLine(isValid);

            var bitcoinPrivateKeyFromPassphraseCode = encryptedKey.GetSecret("my secret");

            Console.WriteLine(bitcoinPrivateKeyFromPassphraseCode.GetAddress() == generatedAddress);

            Console.WriteLine(bitcoinPrivateKey);

            // BIP 32
            // hierarchical deterministic wallets
            // prevent outdated backups

            var masterKey = new ExtKey();


            Console.WriteLine($"Master Key: {masterKey.ToString(Network.Main)}");

            for (uint i = 0; i < 5; i++)
            {
                ExtKey nextKey = masterKey.Derive(i);
                Console.WriteLine($"Key {i} : {nextKey.ToString(Network.Main)}");
            }

            // go back from a Key to ExtKey by supplying the Key and the ChainCode to the ExtKey constructor.

            var extKey = new ExtKey();

            byte[] chainCode = extKey.ChainCode;
            Key    key       = extKey.PrivateKey;

            var newExtKey = new ExtKey(key, chainCode);

            // the base58 type equivalent of ExtKey is BitcoinExtKey


            // "neuter" master key so 3rd party can generate public keys without knowing private key
            ExtPubKey masterPubKey = masterKey.Neuter();

            for (uint i = 0; i < 5; i++)
            {
                ExtPubKey pubKey = masterPubKey.Derive(i);
                Console.WriteLine($"PubKey {i} : {pubKey.ToString(Network.Main)}");
            }

            // get corresponding private key with master key
            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            // 3rd party generates pubkey1
            ExtPubKey pubKey1 = masterPubKey.Derive(1);

            // get privatekey of pubKey1
            ExtKey key1 = masterKey.Derive(1);

            Console.WriteLine($"Generated address: {pubKey1.PubKey.GetAddress(Network.Main)}");
            Console.WriteLine($"Expected address: {key1.PrivateKey.PubKey.GetAddress(Network.Main)}");

            // deterministic keys

            // derive the 1st child of the 1st child

            ExtKey parent = new ExtKey();

            // method 1:
            ExtKey child11 = parent.Derive(1).Derive(1);

            // method 2:
            child11 = parent.Derive(new KeyPath("1/1"));

            // why use HD wallets ?
            // easier control, easier to classify keys for multiple accounts

            // but child keys can recover parent key (non-hardened)

            ExtKey ceoExtKey = new ExtKey();

            Console.WriteLine($"CEO: {ceoExtKey.ToString(Network.Main)}");
            ExtKey accountingKey = ceoExtKey.Derive(0, hardened: false);

            ExtPubKey ceoPubKey = ceoExtKey.Neuter();

            // recover ceo key with accounting private key and ceo public key
            ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubKey);

            Console.WriteLine($"CEO recovered: {ceoKeyRecovered.ToString(Network.Main)}");

            // create a hardened key
            var privateCeoExtKey = new ExtKey();

            Console.WriteLine($"Private CEO: {privateCeoExtKey.ToString(Network.Main)}");
            var assitantExtKey = privateCeoExtKey.Derive(1, hardened: true);

            ExtPubKey privateCeoPubKey = privateCeoExtKey.Neuter();

            ExtKey privateCeoKeyRecovered = null;

            try
            {
                privateCeoKeyRecovered = assitantExtKey.GetParentExtKey(privateCeoPubKey);
            }
            catch (Exception e)
            {
                Console.WriteLine($"{e.Message}");
            }

            // creating hardened keys via keypath
            var isNonHardened = new KeyPath("1/2/3").IsHardened;

            Console.WriteLine(isNonHardened);

            var isHardened = new KeyPath("1/2/3'").IsHardened;

            Console.WriteLine(isHardened);

            // imagine that the Accounting Department generates 1 parent key for each customer, and a child for each of the customer’s payments.
            // As the CEO, you want to spend the money on one of these addresses.

            var     accountingCeoKey = new ExtKey();
            string  accounting       = "1'"; // hardened with apostrophe
            int     customerId       = 5;
            int     paymentId        = 50;
            KeyPath path             = new KeyPath($"{accounting}/{customerId}/{paymentId}");

            // path: 1/5/50
            ExtKey paymentKey = accountingCeoKey.Derive(path);

            Console.WriteLine(paymentKey);


            // mnemonic code for HD keys BIP 39
            // used for easy to write keys
            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(mnemo);

            // recover hdRoot with mnemonic and password
            mnemo = new Mnemonic(mnemo.ToString(), Wordlist.English);
            ExtKey recoverdHdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(hdRoot.PrivateKey == recoverdHdRoot.PrivateKey);


            // dark wallet
            // Prevent outdated backups
            // Delegate key / address generation to an untrusted peer

            // bonus feature: only share one address (StealthAddress)

            var scanKey        = new Key();
            var spendKey       = new Key();
            var stealthAddress = new BitcoinStealthAddress(
                scanKey: scanKey.PubKey,
                pubKeys: new[] { spendKey.PubKey },
                signatureCount: 1,
                bitfield: null,
                network: Network.Main
                );

            // payer will take StealthAddress and generate temp key called Ephem Key, and generate a Stealth Pub Key
            // then they package the Ephem PubKey in Stealth Metadata obj embedded in OP_RETURN
            // they will also add the output to the generated bitcoin address (Stealth pub key)

            //The creation of the EphemKey is an implementation detail
            // it can be omitted as NBitcoin will generate one automatically:
            var ephemKey    = new Key();
            var transaction = new Transaction();

            stealthAddress.SendTo(transaction, Money.Coins(1.0m), ephemKey);
            Console.WriteLine(transaction);

            // the Scanner knows the StealthAddress
            // and recovers the Stealth PubKey and Bitcoin Address with the Scan Key

            // scanner then checks if if one of the tx corresponds to the address
            // if true, Scanner notifies the Receiver about tx

            // the receiver can get the private key of the address with their spend key

            // note: a StealthAddress can have mulitple spend pubkeys 9multi sig)

            // limit: use of OP_RETURN makes embedding data in tx difficult
            // OP_RETURN limit is 40 bytes

            Console.ReadLine();
        }
Пример #21
0
 public void UpdateAddress()
 {
     Address = new BitcoinStealthAddress(Scan.PubKey, new PubKey[] { Spend.PubKey }, 1, Prefix, Network.TestNet);
     Scanner = new StealthPaymentScanner(Address, Scan);
 }
Пример #22
0
		public TransactionBuilder Send(BitcoinStealthAddress address, Money amount, Key ephemKey = null)
		{
			if(amount < Money.Zero)
				throw new ArgumentOutOfRangeException("amount", "amount can't be negative");

			if(_OpReturnUser == null)
				_OpReturnUser = "******";
			else
				throw new InvalidOperationException("Op return already used for " + _OpReturnUser);

			CurrentGroup.Builders.Add(ctx =>
			{
				var payment = address.CreatePayment(ephemKey);
				payment.AddToTransaction(ctx.Transaction, amount);
				return amount;
			});
			return this;
		}
        public void CanCreatePayment()
        {
            var tests = new[]
            {
                new CanCreatePaymentData
                {
                    //sx stealth-newkey
                    StealthAddress = "vJmtjxSDxNPXL4RNapp9ARdqKz3uJyf1EDGjr1Fgqs9c8mYsVH82h8wvnA4i5rtJ57mr3kor1EVJrd4e5upACJd588xe52yXtzumxj",

                    ScanSecret = "3e49e7257cb31db997edb1cf8299af0f37e2663e2260e4b8033e49d39a6d02f2",
                    ScanPubKey = "025e58a31122b38c86abc119b9379fe247410aee87a533f9c07b189aef6c3c1f52",

                    SpendSecret = "aa3db0cfb3edc94de4d10f873f8190843f2a17484f6021a95a7742302c744748",
                    SpendPubKey = "03616562c98e7d7b74be409a787cec3a912122f3fb331a9bee9b0b73ce7b9f50af",

                    //sx newkey | sx wif-to-secret
                    EphemSecret = "9e63abaf8dcd5ea3919e6de0b6c544e00bf51bf92496113a01d6e369944dc091",
                    EphemPubKey = "03403d306ec35238384c7e340393335f9bc9bb4a2e574eb4e419452c4ea19f14b0",

                    //sx steatlh-uncover-secret [EphemPubKey] [ScanSecret] [SpendSecret]
                    StealthSecret = "4e422fb1e5e1db6c1f6ab32a7706d368ceb385e7fab098e633c5c5949c3b97cd",
                    //sx stealth-initiate [EphemSecret] [ScanPubKey] [SpendPubKey] (for sender)
                    //or
                    //sx stealth-uncover [EphemPubKey] [ScanSecret] [SpendPubKey]  (for receiver)
                    StealthPubKey = "02726112ad39cb6bf848b1b1ef30b88e35286bf99f746c2be575f96c0e02a9357c",
                },

                //Need padding for to find the stealth secret
                new CanCreatePaymentData {
                    StealthAddress = "vJmyTEybwCKz7W8y6vP62jo7RoyfLneiANcPLBBNYwn98EXzQRStMKqKGRiZhqscuQ6WKy2J3U3zfx72V3b2J6YvxxBcxUj4XMDsw7",
                    ScanSecret     = "2f517d81cf30e47dbf4809321275bbfd92192af81a6141a17aa53e40bd28fe36",
                    ScanPubKey     = "039d91ae0eebea6dc500fb57b704abce3d3fa700cc762a52bc5dcaee27770a8402",
                    SpendSecret    = "71e33219884fc27011f8da9adcc730f0c2e940759bdb1b615764492bce04fcea",
                    SpendPubKey    = "021a3d5b40ec83fc58b5a23207eb9c99b741d8f0e9f8b80f04f49cec915b540c40",
                    EphemSecret    = "578ffe42c0fbfb324a31f41dbbcd8b1f910ce2f4d803444a83b18ae9f8ccd97e",
                    EphemPubKey    = "03c190be0a1c6e50577b3dd637b1fff9344de31c2544ff3d815535c0515711150f",
                    StealthSecret  = "006d138b4bcef0f09c8784c0cc68f2be4497a1a822d8d7b0519c5c0378b5cb45",
                    StealthPubKey  = "0223a99278a5279ea93718503a42377067e72960eb808d8bff6defdd95d4feff76"
                }
            };

            foreach (var test in tests)
            {
                var scan    = AssertKeys(test.ScanSecret, test.ScanPubKey);
                var spend   = AssertKeys(test.SpendSecret, test.SpendPubKey);
                var ephem   = AssertKeys(test.EphemSecret, test.EphemPubKey);
                var stealth = AssertKeys(test.StealthSecret, test.StealthPubKey);

                var address = spend.PubKey.CreateStealthAddress(scan.PubKey, Network.Main);
                Assert.Equal(test.StealthAddress, address.ToString());
                //Try roundtrip
                address = new BitcoinStealthAddress(address.ToBytes(), Network.Main);
                Assert.Equal(test.StealthAddress, address.ToString());

                var payment      = address.CreatePayment(ephem);
                var generatedKey = spend.Uncover(scan, payment.Metadata.EphemKey);
                if (stealth != null)
                {
                    Assert.Equal(stealth.PubKey.Hash, payment.StealthKeys[0].ID);
                    Assert.Equal(stealth.ToBytes(), generatedKey.ToBytes());
                }
                var uncoveredSender    = spend.PubKey.UncoverSender(ephem, scan.PubKey);
                var uncovertedReceiver = spend.PubKey.UncoverReceiver(scan, ephem.PubKey);

                AssertEx.CollectionEquals(uncoveredSender.ToBytes(), uncovertedReceiver.ToBytes());
                AssertEx.CollectionEquals(generatedKey.PubKey.ToBytes(), uncovertedReceiver.ToBytes());

                var transaction = new Transaction();
                payment.AddToTransaction(transaction, 100);
            }
        }
Пример #24
0
 public void UpdateAddress()
 {
     Address = new BitcoinStealthAddress(Scan.PubKey, new PubKey[] { Spend.PubKey }, 1, Prefix, Network.TestNet);
     Scanner = new StealthPaymentScanner(Address, Scan);
 }
        static void Main()
        {
            //===========================================================================================
            //Chapter8. Using the TransactionBuilder

            RandomUtils.Random = new UnsecureRandom();


            //Private key generator.
            Key           privateKeyGenerator = new Key();
            BitcoinSecret bitcoinSecretFromPrivateKeyGenerator = privateKeyGenerator.GetBitcoinSecret(Network.Main);
            Key           privateKeyFromBitcoinSecret          = bitcoinSecretFromPrivateKeyGenerator.PrivateKey;

            Console.WriteLine($"privateKeyFromBitcoinSecret.ToString(Network.Main): {privateKeyFromBitcoinSecret.ToString(Network.Main)}");
            //L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo is for Alice
            //KxMrK5EJeUZ1z3Jyo2zPkurRVtYFefab4WQitV5CyjKApHsWfWg9 is for Bob
            //KyStsAHgSehHvewS5YfGwhQGfEWYd8qY2XZg6q2M6TqaM8Q8rayg is for Satoshi
            //L2f9Ntm8UUeTLZFv25oZ8WoRW8kAofUjdUdtCq9axCp1hZrsLZja is for ScanKey

            BitcoinSecret bitcoinSecretForAlice   = new BitcoinSecret("L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo", Network.Main);
            BitcoinSecret bitcoinSecretForBob     = new BitcoinSecret("KxMrK5EJeUZ1z3Jyo2zPkurRVtYFefab4WQitV5CyjKApHsWfWg9", Network.Main);
            BitcoinSecret bitcoinSecretForSatoshi = new BitcoinSecret("KyStsAHgSehHvewS5YfGwhQGfEWYd8qY2XZg6q2M6TqaM8Q8rayg", Network.Main);
            BitcoinSecret bitcoinSecretForScanKey = new BitcoinSecret("L2f9Ntm8UUeTLZFv25oZ8WoRW8kAofUjdUdtCq9axCp1hZrsLZja", Network.Main);


            Key bobPrivateKey        = bitcoinSecretForBob.PrivateKey;
            Key alicePrivateKey      = bitcoinSecretForAlice.PrivateKey;
            Key satoshiPrivateKey    = bitcoinSecretForSatoshi.PrivateKey;
            Key privateKeyForScanKey = bitcoinSecretForScanKey.PrivateKey;


            Script scriptPubKeyOfBobAlice =
                PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, bobPrivateKey.PubKey, alicePrivateKey.PubKey);

            //This transaction will send money to Bob and Alice.
            //The thing you should notice is that this transaction is added by various types of scriptPubKey, such as P2PK(bobPrivateKey.PubKey), P2PKH(alicePrivateKey.PubKey.Hash), and multi-sig ScriptPubKey(scriptPubKeyOfBobAlice).
            var txGettingCoinForBobAlice = new Transaction();

            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), bobPrivateKey.PubKey));
            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), alicePrivateKey.PubKey.Hash));
            txGettingCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1m), scriptPubKeyOfBobAlice));

            //Now let’s say they want to use the coins of this transaction to pay Satoshi.
            //First they have to get their coins.
            Coin[] coins = txGettingCoinForBobAlice.Outputs.AsCoins().ToArray();

            Coin bobCoin      = coins[0];
            Coin aliceCoin    = coins[1];
            Coin bobAliceCoin = coins[2];

            //Now let’s say Bob wants to send 0.2 BTC, Alice 0.3 BTC, and they agree to use bobAlice to send 0.5 BTC.
            //Build the transaction by using the features of the TransactionBuilder class.
            var         builderForSendingCoinToSatoshi = new TransactionBuilder();
            Transaction txForSpendingCoinToSatoshi     = builderForSendingCoinToSatoshi
                                                         .AddCoins(bobCoin)
                                                         .AddKeys(bobPrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.2m))
                                                         .SetChange(bobPrivateKey)
                                                         .Then()
                                                         .AddCoins(aliceCoin)
                                                         .AddKeys(alicePrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.3m))
                                                         .SetChange(alicePrivateKey)
                                                         .Then()
                                                         .AddCoins(bobAliceCoin)
                                                         .AddKeys(bobPrivateKey, alicePrivateKey)
                                                         .Send(satoshiPrivateKey, Money.Coins(0.5m))
                                                         .SetChange(scriptPubKeyOfBobAlice)
                                                         .SendFees(Money.Coins(0.0001m))
                                                         .BuildTransaction(sign: true);

            Console.WriteLine(txForSpendingCoinToSatoshi);

            //Then you can verify it is fully signed and ready to send to the network.
            //Verify you did not screw up.
            Console.WriteLine(builderForSendingCoinToSatoshi.Verify(txForSpendingCoinToSatoshi));



            //============================================================================================
            //Do with a ScriptCoin.

            var txGettingScriptCoinForBobAlice = new Transaction();

            txGettingScriptCoinForBobAlice.Outputs.Add(new TxOut(Money.Coins(1.0m), scriptPubKeyOfBobAlice.Hash));

            coins = txGettingScriptCoinForBobAlice.Outputs.AsCoins().ToArray();
            ScriptCoin bobAliceScriptCoin = coins[0].ToScriptCoin(scriptPubKeyOfBobAlice);

            //Then the signature:
            var builderForSendingScriptCoinToSatoshi = new TransactionBuilder();
            var txForSendingScriptCoinToSatoshi      = builderForSendingScriptCoinToSatoshi
                                                       .AddCoins(bobAliceScriptCoin)
                                                       .AddKeys(bobPrivateKey, alicePrivateKey)
                                                       .Send(satoshiPrivateKey, Money.Coins(0.9m))
                                                       .SetChange(scriptPubKeyOfBobAlice.Hash)
                                                       .SendFees(Money.Coins(0.0001m))
                                                       .BuildTransaction(true);

            Console.WriteLine(builderForSendingScriptCoinToSatoshi.Verify(txForSendingScriptCoinToSatoshi));


            //============================================================================================
            //Do with a StealthCoin.

            //Let’s create a Bitcoin stealth address for Bob and Alice as in previous chapter:
            BitcoinStealthAddress bitcoinStealthAddressForBobAlice =
                new BitcoinStealthAddress
                (
                    scanKey: privateKeyForScanKey.PubKey,
                    pubKeys: new[] { alicePrivateKey.PubKey, bobPrivateKey.PubKey },
                    signatureCount: 2,
                    bitfield: null,
                    network: Network.Main
                );


            //Let’s say someone sent the coin to this transaction via the txGettingCoinForBobAliceToBitcoinStealthAddress which is a BitcoinStealthAddress:
            var txGettingCoinForBobAliceToBitcoinStealthAddress = new Transaction();

            bitcoinStealthAddressForBobAlice
            .SendTo(txGettingCoinForBobAliceToBitcoinStealthAddress, Money.Coins(1.0m));

            //The scanner will detect the StealthCoin:
            StealthCoin stealthCoin
                = StealthCoin.Find(txGettingCoinForBobAliceToBitcoinStealthAddress, bitcoinStealthAddressForBobAlice, privateKeyForScanKey);

            //And forward it to Bob and Alice, who will sign:
            //Let Bob and Alice sign and spend the coin.
            TransactionBuilder builderForBobAliceToBitcoinStealthAddress = new TransactionBuilder();

            txGettingCoinForBobAliceToBitcoinStealthAddress = builderForBobAliceToBitcoinStealthAddress
                                                              .AddCoins(stealthCoin)
                                                              .AddKeys(bobPrivateKey, alicePrivateKey, privateKeyForScanKey)
                                                              .Send(satoshiPrivateKey, Money.Coins(0.9m))
                                                              .SetChange(scriptPubKeyOfBobAlice.Hash)
                                                              .SendFees(Money.Coins(0.0001m))
                                                              .BuildTransaction(true);
            Console.WriteLine(builderForBobAliceToBitcoinStealthAddress.Verify(txGettingCoinForBobAliceToBitcoinStealthAddress));

            Console.ReadLine();
        }
Пример #26
0
        static void TransactionBuilder()
        {
            // TRANSACTION BUILDER
            // the goal of transaction builder is to take Coins and Keys as input, and return back a signed or partially signed transaction
            // the TransactionBuilder will figure out what Coin to use and what to sign by itself
            // 4 steps: 1) gather the Coins to be spent 2) gather Keys that you own 3) enumerate how much money to send to what scriptPubKey 4) build and sign the transaction 5)(optional) you give the tx to somebody else to sign or continue to build it

            // create fake transaction; has a p2pkh, p2pk, and multi-sig of alice and bob
            var alice = new Key();
            var bob   = new Key();

            Script aliceBob = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, alice.PubKey, bob.PubKey);
            var    init     = new Transaction();

            init.Outputs.Add(new TxOut(Money.Coins(1.0m), alice.PubKey.Hash)); // p2pkh
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), bob.PubKey));        // p2pk
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), aliceBob));

            var satoshi = new Key();

            Coin[] coins        = init.Outputs.AsCoins().ToArray();
            Coin   aliceCoin    = coins[0];
            Coin   bobCoin      = coins[1];
            Coin   aliceBobCoin = coins[2];

            // let's say alice wants to send 0.3btc, bob wants to send 0.2btc, and they agree to use aliceBob to send 0.5btc
            var         builder = new TransactionBuilder();
            Transaction tx      = builder
                                  .AddCoins(aliceCoin)
                                  .AddKeys(alice)
                                  .Send(satoshi, Money.Coins(0.3m))
                                  .SetChange(alice)
                                  .Then()
                                  .AddCoins(bobCoin)
                                  .AddKeys(bob)
                                  .Send(satoshi, Money.Coins(0.2m))
                                  .SetChange(bob)
                                  .Then()
                                  .AddCoins(aliceBobCoin)
                                  .AddKeys(alice, bob)
                                  .Send(satoshi, Money.Coins(0.5m))
                                  .SetChange(aliceBob)
                                  .SendFees(Money.Coins(0.0001m))
                                  .BuildTransaction(sign: true);

            Console.WriteLine(builder.Verify(tx)); // True

            // TransactionBuilder works the same way for p2sh, p2wsh, p2sh(p2wsh), and p2sh(p2pkh) except you need to create ScriptCoin
            init = new Transaction();
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), aliceBob.Hash));
            coins = init.Outputs.AsCoins().ToArray();
            ScriptCoin aliceBobScriptCoin = coins[0].ToScriptCoin(aliceBob);

            builder = new TransactionBuilder();
            tx      = builder
                      .AddCoins(aliceBobScriptCoin)
                      .AddKeys(alice, bob)
                      .Send(satoshi, Money.Coins(0.9m))
                      .SetChange(aliceBob.Hash)
                      .SendFees(Money.Coins(0.0001m))
                      .BuildTransaction(true);

            Console.WriteLine(builder.Verify(tx)); // True

            // need a ScanKey to see the StealthCoin
            Key scanKey = new Key();
            BitcoinStealthAddress darkAliceBob =
                new BitcoinStealthAddress
                (
                    scanKey: scanKey.PubKey,
                    pubKeys: new[] { alice.PubKey, bob.PubKey },
                    signatureCount: 2,
                    bitfield: null,
                    network: Network.Main
                );

            // someone sent this tx to darkAliceBob
            init = new Transaction();
            darkAliceBob.SendTo(init, Money.Coins(1.0m));
            // the scanner will detect the StealthCoin
            StealthCoin stealthCoin = StealthCoin.Find(init, darkAliceBob, scanKey);

            // and forward it to alice and bob who sign:
            tx = builder
                 .AddCoins(stealthCoin)
                 .AddKeys(alice, bob, scanKey)    // note: you need the scanKey for spending a StealthCoin
                 .Send(satoshi, Money.Coins(0.9m))
                 .SetChange(aliceBob.Hash)
                 .SendFees(Money.Coins(0.0001m))
                 .BuildTransaction(true);
            Console.WriteLine(builder.Verify(tx));
        }
Пример #27
0
		public StealthCoin(OutPoint outpoint, TxOut txOut, Script redeem, StealthMetadata stealthMetadata, BitcoinStealthAddress address)
			: base(outpoint, txOut)
		{
			StealthMetadata = stealthMetadata;
			Address = address;
			Redeem = redeem;
		}
Пример #28
0
		/// <summary>
		/// Scan the Transaction for StealthCoin given address and scan key
		/// </summary>
		/// <param name="tx">The transaction to scan</param>
		/// <param name="address">The stealth address</param>
		/// <param name="scan">The scan private key</param>
		/// <returns></returns>
		public static StealthCoin Find(Transaction tx, BitcoinStealthAddress address, Key scan)
		{
			var payment = address.GetPayments(tx, scan).FirstOrDefault();
			if(payment == null)
				return null;
			var txId = tx.GetHash();
			var txout = tx.Outputs.First(o => o.ScriptPubKey == payment.ScriptPubKey);
			return new StealthCoin(new OutPoint(txId, tx.Outputs.IndexOf(txout)), txout, payment.Redeem, payment.Metadata, address);
		}
Пример #29
0
        private void Code17()
        {
            var bob      = new Key();
            var alice    = new Key();
            var bobAlice = PayToMultiSigTemplate
                           .Instance
                           .GenerateScriptPubKey(2, bob.PubKey, alice.PubKey);

            Transaction init = new Transaction();

            init.Outputs.Add(new TxOut(Money.Coins(1.0m), alice.PubKey));
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), bob.PubKey.Hash));
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), bobAlice));


            var satoshi = new Key();

            Coin[] coins = init.Outputs.AsCoins().ToArray();

            Coin aliceCoin    = coins[0];
            Coin bobCoin      = coins[1];
            Coin bobAliceCoin = coins[2];

            var         builder = new TransactionBuilder();
            Transaction tx      = builder
                                  .AddCoins(bobCoin)
                                  .AddKeys(bob)
                                  .Send(satoshi, Money.Coins(0.2m))
                                  .SetChange(bob)
                                  .Then()
                                  .AddCoins(aliceCoin)
                                  .AddKeys(alice)
                                  .Send(satoshi, Money.Coins(0.3m))
                                  .SetChange(alice)
                                  .Then()
                                  .AddCoins(bobAliceCoin)
                                  .AddKeys(bob, alice)
                                  .Send(satoshi, Money.Coins(0.5m))
                                  .SetChange(bobAlice)
                                  .SendFees(Money.Coins(0.0001m))
                                  .BuildTransaction(sign: true);


            Console.WriteLine(builder.Verify(tx));

            init = new Transaction();
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), bobAlice.Hash));

            coins = init.Outputs.AsCoins().ToArray();
            ScriptCoin bobAliceScriptCoin = coins[0].ToScriptCoin(bobAlice);

            builder = new TransactionBuilder();
            tx      = builder
                      .AddCoins(bobAliceScriptCoin)
                      .AddKeys(bob, alice)
                      .Send(satoshi, Money.Coins(1.0m))
                      .SetChange(bobAlice.Hash)
                      .BuildTransaction(true);
            Console.WriteLine(builder.Verify(tx));

            Key scanKey = new Key();
            BitcoinStealthAddress darkAliceBob =
                new BitcoinStealthAddress
                (
                    scanKey: scanKey.PubKey,
                    pubKeys: new[] { alice.PubKey, bob.PubKey },
                    signatureCount: 2,
                    bitfield: null,
                    network: Network.Main
                );

            //Fake transaction
            init = new Transaction();
            darkAliceBob
            .CreatePayment()
            .AddToTransaction(init, Money.Coins(1.0m));

            //Get the stealth coin with the scanKey
            StealthCoin stealthCoin
                = StealthCoin.Find(init, darkAliceBob, scanKey);

            //Spend it
            tx = builder
                 .AddCoins(stealthCoin)
                 .AddKeys(bob, alice, scanKey)
                 .Send(satoshi, Money.Coins(1.0m))
                 .SetChange(bobAlice.Hash)
                 .BuildTransaction(true);
            Console.WriteLine(builder.Verify(tx));
        }
Пример #30
0
        public static void Execute()
        {
            /*
             * With the TransactionBuilder you can:
             * -Spend any
             * -P2PK, P2PKH,
             * -multi - sig,
             * -P2WPK, P2WSH.
             * -Spend any P2SH on the previous redeem script.
             * -Spend Stealth Coin(DarkWallet).
             * -Issue and transfer Colored Coins(open asset, following chapter).
             * -Combine partially signed transactions.
             * -Estimate the final size of an unsigned transaction and its fees.
             * -Verify if a transaction is fully signed.
             */

            //Goal: take Coins and Keys as input, and return back a signed or partially signed transaction

            /*
             * The usage of the TransactionBuilder is done in four steps:
             * -You gather the Coins that will be spent
             * -You gather the Keys that you own
             * -You enumerate how much Money you want to send to what scriptPubKey
             * -You build and sign the transaction
             * Optional: you give the transaction to somebody else, then he will sign or continue to build it
             */

            // Create a fake transaction
            Key bob   = new Key();
            Key alice = new Key();

            PubKey[] multiSig     = new PubKey[] { bob.PubKey, alice.PubKey };
            Script   bobAliceMSig = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(2, multiSig);

            Transaction init = new Transaction();

            init.Outputs.Add(new TxOut(Money.Coins(1m), bob.PubKey));        // P2PK
            init.Outputs.Add(new TxOut(Money.Coins(1m), alice.PubKey.Hash)); // P2PKH
            init.Outputs.Add(new TxOut(Money.Coins(1m), bobAliceMSig));

            // Now let’s say they want to use the coins of this transaction to pay Satoshi.
            Key satoshi = new Key();

            // First they have to get their Coins.
            Coin[] coins        = init.Outputs.AsCoins().ToArray();
            Coin   bobCoin      = coins[0];
            Coin   aliceCoin    = coins[1];
            Coin   bobAliceCoin = coins[2];

            // let’s say bob wants to send 0.2 BTC, alice 0.3 BTC,
            // and they agree to use bobAlice to send 0.5 BTC
            TransactionBuilder builder = new TransactionBuilder();
            Transaction        tx      = builder.AddCoins(bobCoin)
                                         .AddKeys(bob)
                                         .Send(satoshi, Money.Coins(0.2m))
                                         .SetChange(bob)
                                         .Then()
                                         .AddCoins(aliceCoin)
                                         .AddKeys(alice)
                                         .Send(satoshi, Money.Coins(0.3m))
                                         .SetChange(alice)
                                         .Then()
                                         .AddCoins(bobAliceCoin)
                                         .AddKeys(bob, alice)
                                         .Send(satoshi, Money.Coins(0.5m))
                                         .SetChange(bobAliceMSig)
                                         .SendFees(Money.Coins(0.0001m))
                                         .BuildTransaction(sign: true);

            // you can verify it is fully signed and ready to send to the network.
            Console.WriteLine("Verify Txn is fully Signed: " + builder.Verify(tx)); // True

            // it works the same way for P2SH, P2WSH, P2SH(P2WSH), and P2SH(P2PKH)
            // except you need to create ScriptCoin
            init = new Transaction();
            init.Outputs.Add(new TxOut(Money.Coins(1.0m), bobAliceMSig.Hash));

            coins = init.Outputs.AsCoins().ToArray();
            ScriptCoin bobAliceScriptCoin = coins[0].ToScriptCoin(bobAliceMSig);

            // Then the signature:
            builder = new TransactionBuilder();
            tx      = builder.AddCoins(bobAliceScriptCoin)
                      .AddKeys(bob, alice)
                      .Send(satoshi, Money.Coins(0.9m))
                      .SetChange(bobAliceMSig.Hash)
                      .SendFees(Money.Coins(0.0001m))
                      .BuildTransaction(true);

            Console.WriteLine("Verify Txn is fully Signed: " + builder.Verify(tx)); // True

            // Stealth Coin - you need a ScanKey to see the StealthCoin
            // create darkAliceBob stealth address as in previous chapter:
            Key scanKey = new Key();
            BitcoinStealthAddress darkAliceBob =
                new BitcoinStealthAddress
                (
                    scanKey: scanKey.PubKey,
                    pubKeys: new[] { alice.PubKey, bob.PubKey },
                    signatureCount: 2,
                    bitfield: null,
                    network: Network.Main
                );

            // Someone sent to darkAliceBob
            init = new Transaction();
            darkAliceBob.SendTo(init, Money.Coins(1.0m));
            // scanner will detect the StealthCoin:
            // Get the stealth coin with the scanKey
            StealthCoin stealthCoin = StealthCoin.Find(init, darkAliceBob, scanKey);

            // And forward it to bob and alice, who will sign:
            // Spend it
            tx = builder.AddCoins(stealthCoin)
                 .AddKeys(bob, alice, scanKey)
                 .Send(satoshi, Money.Coins(0.9m))
                 .SetChange(bobAliceMSig.Hash)
                 .SendFees(Money.Coins(0.0001m))
                 .BuildTransaction(true);

            Console.WriteLine("Verify Txn is fully Signed: " + builder.Verify(tx)); // True
            // Note: You need the scanKey for spending a StealthCoin
        }
Пример #31
0
 //Same functionality with BookExamples by using 2 methods.
 static void EasyImplementation()
 {
     BitcoinStealthAddress address     = ReceiverCreateStealthAddress();
     Transaction           transaction = SenderCreateTransaction(address);
 }
Пример #32
0
        public void CanCreatePayment()
        {
            var tests = new[]
            {
                new CanCreatePaymentData
                {
                    //sx stealth-newkey
                    StealthAddress = "vJmtjxSDxNPXL4RNapp9ARdqKz3uJyf1EDGjr1Fgqs9c8mYsVH82h8wvnA4i5rtJ57mr3kor1EVJrd4e5upACJd588xe52yXtzumxj",

                    ScanSecret = "3e49e7257cb31db997edb1cf8299af0f37e2663e2260e4b8033e49d39a6d02f2",
                    ScanPubKey = "025e58a31122b38c86abc119b9379fe247410aee87a533f9c07b189aef6c3c1f52",

                    SpendSecret = "aa3db0cfb3edc94de4d10f873f8190843f2a17484f6021a95a7742302c744748",
                    SpendPubKey = "03616562c98e7d7b74be409a787cec3a912122f3fb331a9bee9b0b73ce7b9f50af",

                    //sx newkey | sx wif-to-secret
                    EphemSecret = "9e63abaf8dcd5ea3919e6de0b6c544e00bf51bf92496113a01d6e369944dc091",
                    EphemPubKey = "03403d306ec35238384c7e340393335f9bc9bb4a2e574eb4e419452c4ea19f14b0",

                    //sx steatlh-uncover-secret [EphemPubKey] [ScanSecret] [SpendSecret]
                    StealthSecret = "4e422fb1e5e1db6c1f6ab32a7706d368ceb385e7fab098e633c5c5949c3b97cd",
                    //sx stealth-initiate [EphemSecret] [ScanPubKey] [SpendPubKey] (for sender)
                    //or
                    //sx stealth-uncover [EphemPubKey] [ScanSecret] [SpendPubKey]  (for receiver)
                    StealthPubKey = "02726112ad39cb6bf848b1b1ef30b88e35286bf99f746c2be575f96c0e02a9357c",
                },

                //Need padding for to find the stealth secret
                new CanCreatePaymentData{
                    StealthAddress = "vJmyTEybwCKz7W8y6vP62jo7RoyfLneiANcPLBBNYwn98EXzQRStMKqKGRiZhqscuQ6WKy2J3U3zfx72V3b2J6YvxxBcxUj4XMDsw7",
                    ScanSecret = "2f517d81cf30e47dbf4809321275bbfd92192af81a6141a17aa53e40bd28fe36",
                    ScanPubKey = "039d91ae0eebea6dc500fb57b704abce3d3fa700cc762a52bc5dcaee27770a8402",
                    SpendSecret = "71e33219884fc27011f8da9adcc730f0c2e940759bdb1b615764492bce04fcea",
                    SpendPubKey = "021a3d5b40ec83fc58b5a23207eb9c99b741d8f0e9f8b80f04f49cec915b540c40",
                    EphemSecret = "578ffe42c0fbfb324a31f41dbbcd8b1f910ce2f4d803444a83b18ae9f8ccd97e",
                    EphemPubKey = "03c190be0a1c6e50577b3dd637b1fff9344de31c2544ff3d815535c0515711150f",
                    StealthSecret = "006d138b4bcef0f09c8784c0cc68f2be4497a1a822d8d7b0519c5c0378b5cb45",
                    StealthPubKey = "0223a99278a5279ea93718503a42377067e72960eb808d8bff6defdd95d4feff76"
                }
            };

            foreach(var test in tests)
            {
                var scan = AssertKeys(test.ScanSecret, test.ScanPubKey);
                var spend = AssertKeys(test.SpendSecret, test.SpendPubKey);
                var ephem = AssertKeys(test.EphemSecret, test.EphemPubKey);
                var stealth = AssertKeys(test.StealthSecret, test.StealthPubKey);

                var address = spend.PubKey.CreateStealthAddress(scan.PubKey, Network.Main);
                Assert.Equal(test.StealthAddress, address.ToString());
                //Try roundtrip
                address = new BitcoinStealthAddress(address.ToBytes(), Network.Main);
                Assert.Equal(test.StealthAddress, address.ToString());

                var payment = address.CreatePayment(ephem);
                var generatedKey = spend.Uncover(scan, payment.Metadata.EphemKey);
                if(stealth != null)
                {
                    Assert.Equal(stealth.PubKey.ID, payment.StealthKeys[0].ID);
                    Assert.Equal(stealth.ToBytes(), generatedKey.ToBytes());
                }
                var uncoveredSender = spend.PubKey.UncoverSender(ephem, scan.PubKey);
                var uncovertedReceiver = spend.PubKey.UncoverReceiver(scan, ephem.PubKey);

                AssertEx.CollectionEquals(uncoveredSender.ToBytes(), uncovertedReceiver.ToBytes());
                AssertEx.CollectionEquals(generatedKey.PubKey.ToBytes(), uncovertedReceiver.ToBytes());

                var transaction = new Transaction();
                payment.AddToTransaction(transaction, 100);
            }
        }
Пример #33
0
        static void BookExamples()
        {
            RandomUtils.Random = new UnsecureRandom();

            var scanKey  = new Key();
            var spendKey = new Key();
            BitcoinStealthAddress stealthAddress
                = new BitcoinStealthAddress
                  (
                      scanKey: scanKey.PubKey,
                      pubKeys: new[] { spendKey.PubKey },
                      signatureCount: 1,
                      bitfield: null,
                      network: Network.Main);



            //The Payer will take your StealthAddress. And on the other side, He generates a temporary key called Ephem Key and generates a Ephem PubKey from the Ephem Key.
            //And he generates a Stealth PubKey by the StealthAddress and the Ephem PubKey.

            //And finally, a Bitcoin address is generated from the Stealth PubKey.

            //Illustration:
            //1.StealthAddress->Stealth PubKey < -Ephem PubKey < -Ephem Key
            //2.Stealth PubKey->Bitcoin Address



            //Then, they will package the Ephem PubKey in a Stealth Metadata object embedded in the OP_RETURN of the transaction as we did for the first challenge.

            //They will also add the output to the generated bitcoin address, the address of the Stealth pub key.

            //Illustration:
            //Stealth Metadata object <- Ephem PubKey



            var         ephemKey    = new Key();
            Transaction transaction = new Transaction();

            stealthAddress.SendTo(transaction, Money.Coins(1.0m), ephemKey);
            Console.WriteLine(transaction);


            //The creation of the EphemKey is an implementation detail and you can omit it as NBitcoin will generate one automatically:
            Transaction transaction2 = new Transaction();

            //Notice that there is no passed ephemKey.
            stealthAddress.SendTo(transaction2, Money.Coins(1.0m));
            Console.WriteLine(transaction2);


            //{
            //  "hash": "7772b0ad19acd1bd2b0330238a898fe021486315bd1e15f4154cd3931a4940f9",
            //  "ver": 1,
            //  "vin_sz": 0,
            //  "vout_sz": 2,
            //  "lock_time": 0,
            //  "size": 93,
            //  "in": [],
            //  "out": [
            //    {
            //      "value": "0.00000000",
            //      "scriptPubKey": "OP_RETURN 060000000002b9266f15e8c6598e7f25d3262969a774df32b9b0b50fea44fc8d914c68176f3e"
            //    },
            //    {
            //      "value": "1.00000000",
            //      "scriptPubKey": "OP_DUP OP_HASH16051f68af989f5bf24259c519829f46c7f2935b756 OP_EQUALVERIFY OP_CHECKSIG"
            //    }
            //  ]
            //}



            //Then the payer adds and signs the inputs, then sends the transaction on the network.

            //The Scanner knowing the StealthAddress and the Scan Key can recover the Stealth PubKey and the expected BitcoinAddress payment.

            //Illustration:
            //Scan Key + StealthAddress + StealtMetadata + Bitcoin Address => Stealth PubKey



            //Then the scanner checks if one of the outputs of the transaction corresponds to that address. If it does, then Scanner notifies the Receiver about the transaction.

            //The Receiver can then get the private key of the address with their Spend Key.

            //Illustration:
            //Scan Key + Stealth Metadata + Spend Key => Stealth Key



            //The code explaining how, as a Scanner, to scan a transaction and how, as a Receiver, to uncover the private key, will be explained later in the TransactionBuilder(Other types of ownership) section.

            //It should be noted that a StealthAddress can have multiple spend pubkeys, in which case, the address represents a multi sig.

            //One limit of Dark Wallet is the use of OP_RETURN, so we can’t easily embed arbitrary data in the transaction as we did in the Bitcoin transfer section.
            //Current bitcoin rules allow only one OP_RETURN of 40 bytes, soon 80, per transaction.



            //(Stackoverflow) As I understand it, the "stealth address" is intended to address a very specific problem. If you wish to solicit payments from the public, say by posting a donation address on your website, then everyone can see on the block chain that all those payments went to you, and perhaps try to track how you spend them.



            //With a stealth address, you ask payers to generate a unique address in such a way that you(using some additional data which is attached to the transaction) can deduce the corresponding private key.So although you publish a single "stealth address" on your website, the block chain sees all your incoming payments as going to separate addresses and has no way to correlate them. (Of course, any individual payer knows their payment went to you, and can trace how you spend it, but they don't learn anything about other people's payments to you.)

            //But you can get the same effect another way: just give each payer a unique address.Rather than posting a single public donation address on your website, have a button that generates a new unique address and saves the private key, or selects the next address from a long list of pre-generated addresses(whose private keys you hold somewhere safe). Just as before, the payments all go to separate addresses and there is no way to correlate them, nor for one payer to see that other payments went to you.

            //So the only difference with stealth addresses is essentially to move the chore of producing a unique address from the server to the client. Indeed, in some ways stealth addresses may be worse, since very few people use them, and if you are known to be one of them, it will be easier to connect stealth transactions with you.


            //It doesn't provide "100% anonymity". The fundamental anonymity weakness of Bitcoin remains - that everyone can follow the chain of payments, and if you know something about one transaction or the parties to it, you can deduce something about where those coins came from or where they went.
        }
Пример #34
0
 public StealthPaymentScanner(BitcoinStealthAddress address, Key scan)
     : this(address.Prefix, address.SpendPubKeys, scan)
 {
 }
Пример #35
0
        public void CanParseStealthAddress()
        {
            var tests = new[]
            {
                //Test vector created with sx
                //sx stealth-newkey -> ScanSecret,SpendSecret,StealthAddress
                //sx stealth-show-addr StealthAddress -> ScanPubKey,SpendPubKey,RequiredSignature...
                new
                {
                    ScanSecret = "9ac9fdee7c2c19611bcbed8959e1c61d00cdc27cf17bb50a1f4d29db7f953632",
                    SpendSecrets = new[]{
                                            "4e2fa767cc241c3fa4c512d572b2758a3960a06d374f2c819fe409b161d72ad4"
                                        },
                    StealthAddress = "vJmsmwE8cVt9ytJxBuY2jayh8RAfvpG42CyNVYpeVZAkHaiwASobUEzskpXMwbH1TZNBLoxWWYem5WuZewTL8xz3upJ75zKcdVmTfg",
                    ScanPubKey = "021ce89be99a229d123e8bc13ffbcb66722d6200bbeb1d90ddddbf97df82ed2672",
                    SpendPubKeys = new[]
                                        {
                                            "03c197525241d3d70bbf33bb2b54d41e6b9595a92a2c6b7bf7157727c017f0154a"
                                        },
                    RequiredSignature = 1,
                    Options = 0,
                    PrefixLength = 0,
                    PrefixValue = "",
                }
            };
            foreach(var test in tests)
            {
                var scanSecret = new Key(TestUtils.ParseHex(test.ScanSecret));
                AssertEx.CollectionEquals(scanSecret.PubKey.ToBytes(), TestUtils.ParseHex(test.ScanPubKey));

                var stealth = new BitcoinStealthAddress(test.StealthAddress, Network.Main);
                Assert.Equal(test.RequiredSignature, stealth.SignatureCount);
                Assert.Equal(test.PrefixLength, stealth.Prefix.BitCount);
                AssertEx.CollectionEquals(stealth.Prefix.GetRawForm(), TestUtils.ParseHex(test.PrefixValue));
                Assert.Equal(test.Options, stealth.Options);

                AssertEx.CollectionEquals(stealth.ScanPubKey.ToBytes(),
                                              TestUtils.ParseHex(test.ScanPubKey));
                for(int i = 0 ; i < test.SpendPubKeys.Length ; i++)
                {
                    AssertEx.CollectionEquals(stealth.SpendPubKeys[i].ToBytes(),
                                              TestUtils.ParseHex(test.SpendPubKeys[i]));

                    var spendSecret = new Key(TestUtils.ParseHex(test.SpendSecrets[i]));
                    AssertEx.CollectionEquals(stealth.SpendPubKeys[i].ToBytes(), TestUtils.ParseHex(test.SpendPubKeys[i]));
                }
            }
        }