/// <inheritdoc cref="AddNewAccount(string, string, byte[], Network, DateTimeOffset)"/>
        /// <summary>
        /// Adds an account to the current account root using extended public key and account index.
        /// </summary>
        /// <param name="accountExtPubKey">The extended public key for the account.</param>
        /// <param name="accountIndex">The zero-based account index.</param>
        public HdAccount AddNewAccount(ExtPubKey accountExtPubKey, int accountIndex, Network network, DateTimeOffset accountCreationTime)
        {
            ICollection <HdAccount> hdAccounts = this.Accounts.ToList();

            if (hdAccounts.Any(a => a.Index == accountIndex))
            {
                throw new WalletException("There is already an account in this wallet with index: " + accountIndex);
            }

            if (hdAccounts.Any(x => x.ExtendedPubKey == accountExtPubKey.ToString(network)))
            {
                throw new WalletException("There is already an account in this wallet with this xpubkey: " +
                                          accountExtPubKey.ToString(network));
            }

            string accountHdPath = HdOperations.GetAccountHdPath((int)this.CoinType, accountIndex);

            var newAccount = new HdAccount
            {
                Index             = accountIndex,
                ExtendedPubKey    = accountExtPubKey.ToString(network),
                ExternalAddresses = new List <HdAddress>(),
                InternalAddresses = new List <HdAddress>(),
                Name         = $"account {accountIndex}",
                HdPath       = accountHdPath,
                CreationTime = accountCreationTime
            };

            hdAccounts.Add(newAccount);
            this.Accounts = hdAccounts;

            return(newAccount);
        }
        /// <summary>
        /// Adds an account to the current account root using encrypted seed and password.
        /// </summary>
        /// <remarks>The name given to the account is of the form "account (i)" by default, where (i) is an incremental index starting at 0.
        /// According to BIP44, an account at index (i) can only be created when the account at index (i - 1) contains transactions.
        /// <seealso cref="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki"/></remarks>
        /// <param name="password">The password used to decrypt the wallet's encrypted seed.</param>
        /// <param name="encryptedSeed">The encrypted private key for this wallet.</param>
        /// <param name="chainCode">The chain code for this wallet.</param>
        /// <param name="network">The network for which this account will be created.</param>
        /// <param name="accountCreationTime">Creation time of the account to be created.</param>
        /// <returns>A new HD account.</returns>
        public HdAccount AddNewAccount(string password, string encryptedSeed, byte[] chainCode, Network network, DateTimeOffset accountCreationTime)
        {
            Guard.NotEmpty(password, nameof(password));
            Guard.NotEmpty(encryptedSeed, nameof(encryptedSeed));
            Guard.NotNull(chainCode, nameof(chainCode));

            int newAccountIndex = 0;
            ICollection <HdAccount> hdAccounts = this.Accounts.ToList();

            if (hdAccounts.Any())
            {
                newAccountIndex = hdAccounts.Max(a => a.Index) + 1;
            }

            // Get the extended pub key used to generate addresses for this account.
            string    accountHdPath    = HdOperations.GetAccountHdPath((int)this.CoinType, newAccountIndex);
            Key       privateKey       = HdOperations.DecryptSeed(encryptedSeed, password, network);
            ExtPubKey accountExtPubKey = HdOperations.GetExtendedPublicKey(privateKey, chainCode, accountHdPath);

            var newAccount = new HdAccount
            {
                Index             = newAccountIndex,
                ExtendedPubKey    = accountExtPubKey.ToString(network),
                ExternalAddresses = new List <HdAddress>(),
                InternalAddresses = new List <HdAddress>(),
                Name         = $"account {newAccountIndex}",
                HdPath       = accountHdPath,
                CreationTime = accountCreationTime
            };

            hdAccounts.Add(newAccount);
            this.Accounts = hdAccounts;

            return(newAccount);
        }
        /// <summary>
        /// Create an account for a specific account index and account name pattern.
        /// </summary>
        /// <param name="password">The password used to decrypt the wallet's encrypted seed.</param>
        /// <param name="encryptedSeed">The encrypted private key for this wallet.</param>
        /// <param name="chainCode">The chain code for this wallet.</param>
        /// <param name="network">The network for which this account will be created.</param>
        /// <param name="accountCreationTime">Creation time of the account to be created.</param>
        /// <param name="newAccountIndex">The optional account index to use.</param>
        /// <param name="newAccountName">The optional account name to use.</param>
        /// <returns>A new HD account.</returns>
        public HdAccount CreateAccount(string password, string encryptedSeed, byte[] chainCode,
                                       Network network, DateTimeOffset accountCreationTime,
                                       int newAccountIndex, string newAccountName = null)
        {
            if (string.IsNullOrEmpty(newAccountName))
            {
                newAccountName = string.Format(Wallet.AccountNamePattern, newAccountIndex);
            }

            // Get the extended pub key used to generate addresses for this account.
            string    accountHdPath    = HdOperations.GetAccountHdPath((int)this.CoinType, newAccountIndex);
            Key       privateKey       = HdOperations.DecryptSeed(encryptedSeed, password, network);
            ExtPubKey accountExtPubKey = HdOperations.GetExtendedPublicKey(privateKey, chainCode, accountHdPath);

            return(new HdAccount
            {
                Index = newAccountIndex,
                ExtendedPubKey = accountExtPubKey.ToString(network),
                ExternalAddresses = new List <HdAddress>(),
                InternalAddresses = new List <HdAddress>(),
                Name = newAccountName,
                HdPath = accountHdPath,
                CreationTime = accountCreationTime
            });
        }
Exemple #4
0
        public DerivationStrategyBase CreateDerivationStrategy(ExtPubKey pubKey, bool p2sh)
        {
            pubKey = pubKey ?? new ExtKey().Neuter();
            string suffix = this.RPC.Capabilities.SupportSegwit ? "" : "-[legacy]";

            suffix += p2sh ? "-[p2sh]" : "";
            return(new DerivationStrategyFactory(this.Network).Parse($"{pubKey.ToString(this.Network)}{suffix}"));
        }
Exemple #5
0
        public void CanRoundTripExtKeyBase58Data()
        {
            var       key    = new ExtKey();
            ExtPubKey pubkey = key.Neuter();

            Assert.True(ExtKey.Parse(key.ToString(this.networkMain)).ToString(this.networkMain) == key.ToString(this.networkMain));
            Assert.True(ExtPubKey.Parse(pubkey.ToString(this.networkMain)).ToString(this.networkMain) == pubkey.ToString(this.networkMain));
        }
        public DerivationStrategyBase CreateDerivationStrategy(ExtPubKey pubKey, bool p2sh)
        {
            key    = key ?? new ExtKey();
            pubKey = pubKey ?? key.Neuter();
            string suffix = this.RPC.Capabilities.SupportSegwit ? "" : "-[legacy]";

            suffix          += p2sh ? "-[p2sh]" : "";
            scriptPubKeyType = p2sh ? ScriptPubKeyType.SegwitP2SH : ScriptPubKeyType.Segwit;
            return(NBXplorerNetwork.DerivationStrategyFactory.Parse($"{pubKey.ToString(this.Network)}{suffix}"));
        }
Exemple #7
0
        private void btnCalculate_Click(object sender, RoutedEventArgs e)
        {
            var functions = new Functions();

            wordList = functions.SelectedLanguage(cboLanguage.SelectedValue.ToString());
            Mnemonic  mnemo  = new Mnemonic(txtMnemonic.Text, wordlist: wordList);
            ExtKey    hdRoot = new ExtKey();
            ExtKey    key32;
            ExtPubKey pubKey32;

            hdRoot       = mnemo.DeriveExtKey(txtPasswort.Text);
            txtRoot.Text = hdRoot.ToString(Network.Main);

            var wallet = new Wallet(txtMnemonic.Text, txtPasswort.Text);

            txtSeed.Text = wallet.Seed;

            switch (cboCoin.SelectedValue)
            {
            case "BTC - Bitcoin (BIP-44)":
                ExtKey    key44    = hdRoot.Derive(new NBitcoin.KeyPath("m/44'/0'/" + cboAccount.SelectedValue + "'/" + Convert.ToString(cboType.SelectedValue).Substring(0, 1) + "/" + cboIndex.SelectedValue));
                ExtPubKey pubKey44 = key44.Neuter();
                txtAddress.Text      = key44.PrivateKey.PubKey.ToString(Network.Main);
                txtPublicKey.Text    = Convert.ToString(pubKey44.PubKey.ScriptPubKey).Substring(0, 66);
                txtExtPublicKey.Text = pubKey44.ToString(Network.Main);
                txtPrivateKey.Text   = key44.PrivateKey.ToString(Network.Main);
                key32    = hdRoot.Derive(new NBitcoin.KeyPath("m/44'/0'/" + cboAccount.SelectedValue + "'/" + Convert.ToString(cboType.SelectedValue).Substring(0, 1)));
                pubKey32 = key32.Neuter();
                txt32ExtPublicKey.Text = pubKey32.ToString(Network.Main);
                break;

            case "ETH - Ethereum (BIP-44)":
                int index   = Convert.ToInt32(cboIndex.SelectedValue);
                var account = wallet.GetAccount(index);
                txtAddress.Text      = account.Address;
                txtPublicKey.Text    = "";
                txtExtPublicKey.Text = "";
                txtPrivateKey.Text   = account.PrivateKey;
                break;

            case "BTC - Bitcoin (BIP-49)":
                ExtKey    key49    = hdRoot.Derive(new NBitcoin.KeyPath("m/49'/0'/" + cboAccount.SelectedValue + "'/" + Convert.ToString(cboType.SelectedValue).Substring(0, 1) + "/" + cboIndex.SelectedValue));
                ExtPubKey pubKey49 = key49.Neuter();
                txtAddress.Text      = key49.PrivateKey.PubKey.WitHash.GetAddress(Network.Main).GetScriptAddress().ToString();
                txtPublicKey.Text    = Convert.ToString(pubKey49.PubKey.ScriptPubKey).Substring(0, 66);
                txtExtPublicKey.Text = pubKey49.ToString(Network.Main);
                txtPrivateKey.Text   = key49.PrivateKey.ToString(Network.Main);
                key32    = hdRoot.Derive(new NBitcoin.KeyPath("m/49'/0'/" + cboAccount.SelectedValue + "'/" + Convert.ToString(cboType.SelectedValue).Substring(0, 1)));
                pubKey32 = key32.Neuter();
                txt32ExtPublicKey.Text = pubKey32.ToString(Network.Main);
                break;
            }
        }
        public void GeneratePubkey()
        {
            var network = Network.RegTest;

            ExtKey masterKey = new ExtKey();

            Console.WriteLine("Master key : " + masterKey.ToString(network));
            ExtPubKey masterPubKey = masterKey.Neuter();

            ExtPubKey pubkey = masterPubKey.Derive(0);

            Console.WriteLine("PubKey " + 0 + " : " + pubkey.ToString(network));
        }
Exemple #9
0
        public void pubKeysDerivedFromExtendedPrivateAndPublicKeysMatch()
        {
            string password   = "******";
            string passphrase = password;

            string mnemonic = "chalk call anger chase endless level slow sleep coast left sand enter save bind curious puzzle stadium volume mixture shuffle hurry gas borrow believe";

            ExtKey extendedKey = HdOperations.GetExtendedKey(mnemonic, passphrase);

            string encryptedSeed = extendedKey.PrivateKey.GetEncryptedBitcoinSecret(password, this.Network).ToWif();
            Key    privateKey    = HdOperations.DecryptSeed(encryptedSeed, password, this.Network);

            string accountHdPath = HdOperations.GetAccountHdPath(COINTYPE, 0);
            string path          = HdOperations.CreateHdPath(COINTYPE, 0, false, 0);

            ExtPubKey accountExtPubKey = HdOperations.GetExtendedPublicKey(privateKey, extendedKey.ChainCode, accountHdPath);
            var       subjectPubKey    = HdOperations.GeneratePublicKey(accountExtPubKey.ToString(this.Network), 0, false, this.Network);

            var subjectPrivKey = HdOperations.GetExtendedPrivateKey(privateKey, extendedKey.ChainCode, path, this.Network);

            Assert.Equal(subjectPubKey.ScriptPubKey, subjectPrivKey.PrivateKey.PubKey.ScriptPubKey);
        }
Exemple #10
0
        /// <inheritdoc />
        public HdAccount CreateNewAccount(Wallet wallet, string password)
        {
            Guard.NotNull(wallet, nameof(wallet));
            Guard.NotEmpty(password, nameof(password));

            // get the accounts for this type of coin
            var accounts = wallet.AccountsRoot.Single(a => a.CoinType == this.coinType).Accounts.ToList();

            int newAccountIndex = 0;

            if (accounts.Any())
            {
                newAccountIndex = accounts.Max(a => a.Index) + 1;
            }

            // get the extended pub key used to generate addresses for this account
            var       privateKey       = Key.Parse(wallet.EncryptedSeed, password, wallet.Network);
            var       seedExtKey       = new ExtKey(privateKey, wallet.ChainCode);
            var       accountHdPath    = $"m/44'/{(int)this.coinType}'/{newAccountIndex}'";
            KeyPath   keyPath          = new KeyPath(accountHdPath);
            ExtKey    accountExtKey    = seedExtKey.Derive(keyPath);
            ExtPubKey accountExtPubKey = accountExtKey.Neuter();

            var newAccount = new HdAccount
            {
                Index             = newAccountIndex,
                ExtendedPubKey    = accountExtPubKey.ToString(wallet.Network),
                ExternalAddresses = new List <HdAddress>(),
                InternalAddresses = new List <HdAddress>(),
                Name         = $"account {newAccountIndex}",
                HdPath       = accountHdPath,
                CreationTime = DateTimeOffset.Now
            };

            accounts.Add(newAccount);
            wallet.AccountsRoot.Single(a => a.CoinType == this.coinType).Accounts = accounts;

            return(newAccount);
        }
Exemple #11
0
        static void Test(string [] args)
        {
            ExtKey masterKey = new ExtKey();

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

            //Going from Key to ExtKey

            ExtKey extKey = new ExtKey();

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

            ExtKey newExtKey = new ExtKey(privateKey, chainCode);

            //Allowing a third party generate public keys(addresses) without knowing your private key
            ExtPubKey masterPubKey = masterKey.Neuter();

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

            //Testing using one value
            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            //Payment server generate pubKey1
            ExtPubKey pubKey1 = masterPubKey.Derive((uint)184757585);

            //You get the private key
            ExtKey key1 = masterKey.Derive((uint)184757585);

            //Check if it is legit
            Console.WriteLine("Generated address : " + pubKey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));

            //Parent Key and Child Keys
            ExtKey    parentExtKey    = new ExtKey();
            ExtPubKey parentExtPubKey = parentExtKey.Neuter();

            ExtKey childExtKey   = parentExtKey.Derive(0);
            ExtKey childExtKey2  = parentExtKey.Derive(2);
            ExtKey child2ExtKey  = parentExtKey.Derive(1).Derive(2);
            string childAddress  = childExtKey.PrivateKey.PubKey.GetAddress(Network.Main).ToString();
            string child2Address = child2ExtKey.PrivateKey.PubKey.GetAddress(Network.Main).ToString();

            ExtKey parentKey1Recovered = childExtKey.GetParentExtKey(parentExtPubKey);
            ExtKey parentKey2Recovered = childExtKey2.GetParentExtKey(parentExtPubKey);



            //Mnemonic Code for HD Keys
            Mnemonic mnemonic    = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot      = mnemonic.DeriveExtKey("my password");
            var      mnemonicStr = mnemonic.ToString();

            Console.WriteLine(mnemonic);

            //If you have the mnemonic and the password you can recover the hdRoot Key
            mnemonic = new Mnemonic(mnemonicStr, Wordlist.English);
            hdRoot   = mnemonic.DeriveExtKey("my password");

            Console.ReadKey();
        }
        private static void Main()
        {
            RandomUtils.Random = new UnsecureRandom();


            //==========================================================================================
            //Chapter. HD Wallet(BIP 32)

            //Let’s keep in mind the problems that we want to resolve:
            //1.Prevent outdated backups
            //2.Delegating key / address generation to an untrusted peer
            //A “Deterministic” wallet would fix our backup problem. With such a wallet, you would have to save only the seed.From this seed, you can generate the same series of private keys over and over.
            //This is what the “Deterministic” stands for.
            //As you can see, from the master key, I can generate new keys:

            //Create a masterKey.
            ExtKey masterKey = new ExtKey();

            Console.WriteLine("Master key : " + masterKey.ToString(Network.Main));
            //Output:
            //xprv9s21ZrQH143K46gx2C5V4o9iEn52h9y2Y7LykXSTVPFLM28kyMuj8BkicTd3uAiqrVPxb3BZ4fVkzKDwzxVpkEhsqS5HD6vrGDf5D613Lwt

            //Create 5 derived keys based on the masterKey.
            for (int i = 0; i < 5; i++)
            {
                ExtKey key = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + key.ToString(Network.Main));
            }
            //Output:
            //Key 0 : xprv9uvuViKQnT4vo8rSWEtXYXxDLMvt4SrSToHVs3ZpzKXpHd5deZNDKj57XnrQ8rRZSANm3oZBjXN245oy161otLGddxch46UrtTH3tB5fMKQ
            //Key 1 : xprv9uvuViKQnT4vqG7czoZ1VYGPmK9yhXBLGYKgZpiB271L6ekwbzyPo9fHE3F4cAay6qbwczt1K35cEF3HrykPGR9agzmHNhBPDSZtyoxhMbh
            //Key 2 : xprv9uvuViKQnT4vs7GpRKcouP8TP8ERksBG5GdNmocVDp6R8nHGTYH4qwG8PY75hHGKsTKQdQmRAiQnZim6UuYguiaUx1dpqGXafM1Lr1WEkzy
            //Key 3 : xprv9uvuViKQnT4vwDWmEvSEae5nLGbKLMmeMLLCc5MDD9iVSDhDqNpzSErHBYm1TRZGfDM2YbHZyCtmas1d2JRSWMYLKbJMGhyB9ynSbyLTh14
            //Key 4 : xprv9uvuViKQnT4vxgXFvxk6FhKYgzU8NgW3xMfqciveTWKpJDkdCmQiJjAdGUij7QckJ1ZBqKuY1RSyw9JeGM7P6cTMPZqVZBu9SCAfHEpp8SS



            //You only need to save the masterKey, since you can generate the same suite of private keys over and over.
            //As you can see, these keys are ExtKey and not Key as you are used to. However, this should not stop you since you have the real private key inside of these keys:


            //You can go back from a Key to an ExtKey by supplying the Key and the ChainCode to the ExtKey constructor. This works as follows:

            //Create extKey.
            ExtKey extKey = new ExtKey();

            //Get ChainCode from extKey.
            byte[] chainCode = extKey.ChainCode;
            //Get a PrivateKey from extKey.
            Key privateKeyFromExtKey = extKey.PrivateKey;
            //Supply a private key and ChainCode to the ExtKey constructor to go back from a Key to an ExtKey.
            ExtKey newExtKey = new ExtKey(privateKeyFromExtKey, chainCode);


            //The Base58 type equivalent of ExtKey is called BitcoinExtKey.
            //But how can we solve our second problem: Delegating address creation to a peer that can potentially be hacked like a payment server?
            //The trick is that you can “neuter” your master key, then you have a public (without private key) version of the master key.From this neutered version, a third party can generate public keys without knowing the private key.

            //Neuter the master key, then you get a master public key.
            ExtPubKey masterPubKey = masterKey.Neuter();

            //Genarate 5 derived public keys from the master public key.
            for (int i = 0; i < 5; i++)
            {
                ExtPubKey pubkey = masterPubKey.Derive((uint)i);
                Console.WriteLine("PubKey " + i + " : " + pubkey.ToString(Network.Main));
            }

            //So imagine that your payment server generates pubkey1, and then you can get the corresponding private key with your private master key.
            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            //The payment server generates pubkey1.
            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);

            //You get the private key of pubkey1
            ExtKey key1 = masterKey.Derive((uint)1);

            //Check if it is legit
            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));
            //Generated address: 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX
            //Expected address:	 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX

            //ExtPubKey is similar to ExtKey except that it holds a public key and not a private key.



            //Now we have seen how Deterministic keys solve our problems, let’s speak about what the “hierarchical” is for.

            //In the previous exercise, we have seen that by combining master key + index we could generate another key.We call this process Derivation, the master key is the parent key, and any generated keys are called child keys.

            //However, you can also derivate children from the child key.This is what the “hierarchical” stands for.

            //This is why conceptually more generally you can say: Parent Key + KeyPath => Child Key



            //Now that we have seen how Deterministic keys solve our problems, let’s speak about what the “hierarchical” is for.
            //In the previous exercise, we have seen that we could generate another derived keys based on a master key by invoking Derive() method on the master key passing integer numbers into an argument.
            //We call this process a Derivation. And in this scheme, a master key is a parent key, and any generated keys based on the master key are called child keys.
            //However, I can also derivate children from the "child key". This is what the “Hierarchical” stands for.
            //This is why conceptually more generally you can say: Parent Key + KeyPath => Child Key

            //Just suppose the scenario that there is a parent key, "Parent".
            //And there can be child keys derived from "Parent". => Child(1),Child(2),Child(3),Child(4).
            //And there can be child keys derived from Child(1). => Child(1, 1), Child(1, 2).

            //In this diagram, you can derivate Child(1,1) from a parent in two different way:
            //First generate a parent key.
            ExtKey parent = new ExtKey();

            ExtKey child11ByFirstWay = parent.Derive(1).Derive(1);

            Console.WriteLine(child11ByFirstWay);

            //Or above code can be expressed in this way, resulting in an identical output.
            ExtKey child11BySecondWay = parent.Derive(new KeyPath("1/1"));

            Console.WriteLine(child11BySecondWay);

            //Remember that Ancestor ExtKey + KeyPath = Child ExtKey.

            //This process works indenticaly for ExtPubKey.

            //Why do you need hierarchical keys? It's because it might be a nice way to classify the type of my keys for multiple accounts. This point is more neat than on BIP44. It also permits segmenting account rights across an organization.

            //Imagine you are the CEO of a company. You want control over all wallets, but you don’t want the Accounting department to spend the money from the Marketing department.

            //So, for implementing this constraint, your first idea would be to generate one hierarchy for each department.

            //CEO Key(the master key)-> derived child Keys from a master key(the CEO key) : Marketing(0), Accounting(0).
            //Marketing(0)->Child Keys:Marketing(0, 1), Marketing(0, 2).
            //Accounting(0)->Child Keys:Accounting(0, 2), Accounting(0, 2).

            //However, in such a case, Accounting and Marketing would be able to recover the CEO’s private key, because we defined such child keys as non-hardened.

            //Parent ExtPubKey + Child ExtKey(non hardened) => Parent ExtKey.


            ExtKey ceoKey = new ExtKey();

            Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main));
            //Note the hardened is false.
            ExtKey accountingKey = ceoKey.Derive(0, hardened: false);

            ExtPubKey ceoPubkey = ceoKey.Neuter();

            //Recover the CEO key by the accounting private key and the CEO public key.
            ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubkey);

            Console.WriteLine("CEO recovered: " + ceoKeyRecovered.ToString(Network.Main));
            //CEO: xprv9s21ZrQH143K2XcJU89thgkBehaMqvcj4A6JFxwPs6ZzGYHYT8dTchd87TC4NHSwvDuexuFVFpYaAt3gztYtZyXmy2hCVyVyxumdxfDBpoC
            //CEO recovered: xprv9s21ZrQH143K2XcJU89thgkBehaMqvcj4A6JFxwPs6ZzGYHYT8dTchd87TC4NHSwvDuexuFVFpYaAt3gztYtZyXmy2hCVyVyxumdxfDBpoC

            //In other words, a non-hardened key can “climb” the hierarchy. Non-hardened keys should only be used for categorizing accounts that belong to a point of single control.

            //So in our case, the CEO should create child keys as hardened ones, so the accounting department will not be able to climb the hierarchy.



            //Identical process to above code except for hardened is true.
            Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main));
            ExtKey accountingKeyHardened = ceoKey.Derive(0, hardened: true);

            Console.WriteLine(accountingKeyHardened);
            //Generate derived child accountKeys from ceoKey
            //However, since accountKeys are hardened, they can't climb hierarchy towards ceoKey.
            ExtPubKey ceoPubkeyToTestForHardened = ceoKey.Neuter();

            Console.WriteLine(ceoPubkeyToTestForHardened);
            ////At this point, it'll be crashed by this climbing attempt.
            //ExtKey ceoKeyRecovered = accountingKeyHardened.GetParentExtKey(ceoPubkeyToTestForHardened);



            //You can also create hardened keys via the ExtKey.Derivate(KeyPath), by using an apostrophe(') after a child’s index such as "1/2/3'"
            var nonHardenedChildKey = new KeyPath("1/2/3");
            var hardenedChildKey    = new KeyPath("1/2/3'");

            Console.WriteLine(nonHardenedChildKey);
            Console.WriteLine(hardenedChildKey);


            //So let’s 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.Here is how you would proceed.
            ceoKey = new ExtKey();
            //Child key is generated as hardened, so it can't climb hierarchy upwards to a parent key.
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            //Path will be "1'/5/50"
            ExtKey paymentKey = ceoKey.Derive(path);

            Console.WriteLine(paymentKey);


            //===========================================================================================
            //Chapter. Mnemonic Code for HD Keys (BIP39)


            //As you have seen, generating HD keys is easy.However, what if we want an easy way to transmit such a key by telephone or hand writing?

            //Cold wallets like Trezor, generate the HD Keys from a sentence that can easily be written down. They call such a sentence “the seed” or “mnemonic”. And it can eventually be protected by a password or a PIN.



            //The language that you use to generate your 'easy to write' sentence is called a Wordlist.


            //Wordlist + mnemonic + password => HD Root key.


            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(mnemo);
            Console.WriteLine(hdRoot);

            //Now, if you have the mnemonic and the password, you can recover the hdRoot key.
            mnemo = new Mnemonic("minute put grant neglect anxiety case globe win famous correct turn link", Wordlist.English);
            ExtKey hdRoot1 = mnemo.DeriveExtKey("my password");

            Console.WriteLine(hdRoot1);

            //Currently supported languages for wordlist are, English, Japanese, Spanish, Chinese (simplified and traditional).
        }
        private static void Main()
        {
            ExtKey masterKey = new ExtKey();

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

            ExtPubKey masterPubKey = masterKey.Neuter();

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

            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            //The payment server generate pubkey1
            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);

            //You get the private key of pubkey1
            ExtKey key1 = masterKey.Derive((uint)1);

            //Check it is legit
            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));

            ExtKey parent  = new ExtKey();
            ExtKey child11 = parent.Derive(1).Derive(1);

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

            ExtKey ceoKey = new ExtKey();

            Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main));
            ExtKey accountingKey = ceoKey.Derive(0, hardened: true);

            ExtPubKey ceoPubkey = ceoKey.Neuter();

            //ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubkey); //Crash

            var nonHardened = new KeyPath("1/2/3");
            var hardened    = new KeyPath("1/2/3'");

            ceoKey = new ExtKey();
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            //Path : "1'/5/50"
            ExtKey paymentKey = ceoKey.Derive(path);

            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(mnemo);

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

            Console.ReadLine();
        }
        public static void Execute()
        {
            // HD Wallet (BIP 32)
            // from the master key, I can generate new keys:
            ExtKey masterKey = new ExtKey();

            Console.WriteLine("---------------------HD Wallet (BIP 32)---------------------");
            Console.WriteLine("Master key : " + masterKey.ToString(Network.Main));
            for (int i = 0; i < 5; i++)
            {
                ExtKey childKey = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + childKey.ToString(Network.Main));
            }

            // go back from a Key to an ExtKey by supplying the Key and the ChainCode
            ExtKey extKey = new ExtKey();
            Key    key    = extKey.PrivateKey;

            byte[] chainCode = extKey.ChainCode;

            ExtKey newExtKey = new ExtKey(key, chainCode);

            Console.WriteLine("extKey==newExtKey: " +
                              (extKey.ToString(Network.Main) == newExtKey.ToString(Network.Main)));

            // delegating address creation to a peer
            // third party can generate public keys without knowing the private key
            ExtPubKey masterPubKey = masterKey.Neuter();

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

            // payment server generates pubkey1
            // we can get the corresponding private key with our private master key
            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();

            //The payment server generate pubkey1
            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);

            //You get the private key of pubkey1
            ExtKey key1 = masterKey.Derive((uint)1);

            //Check it is legit
            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));
            // Generated address : 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX
            // Expected address: 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX

            // “hierarchical”:  Parent Key + KeyPath => Child Key (and so on..)
            // derivate Child(1,1) from parent in two different way
            ExtKey parent = new ExtKey();
            ExtKey child1 = parent.Derive(1);
            ExtKey child11;

            child11 = child1.Derive(1);           //Or
            child11 = parent.Derive(1).Derive(1); //Or
            child11 = parent.Derive(new KeyPath("1/1"));

            // generate one hierarchy for each department.
            // non-hardened key, accounting department can “climb” the hierarchy
            // hardened key, so the marketing department will not be able to climb the hierarchy.
            ExtKey    ceoKey        = new ExtKey();
            ExtKey    accountingKey = ceoKey.Derive(0, hardened: false);
            ExtKey    marketingKey  = ceoKey.Derive(0, hardened: true);
            ExtPubKey ceoPubkey     = ceoKey.Neuter();

            //Recover ceo key with accounting private key and ceo public key
            ExtKey ceoKeyRecovered    = accountingKey.GetParentExtKey(ceoPubkey);
            ExtKey ceoKeyNotRecovered = marketingKey.GetParentExtKey(ceoPubkey); //Crash

            Console.WriteLine();
            Console.WriteLine("CEO Key: " + ceoKey.ToString(Network.Main));
            Console.WriteLine("CEO recovered: " + ceoKeyRecovered.ToString(Network.Main));
            Console.WriteLine("CEO Not recovered: " + ceoKeyNotRecovered.ToString(Network.Main));

            //Or
            KeyPath nonHardened = new KeyPath("1/2/3");
            KeyPath hardened    = new KeyPath("1/2/3'");

            ceoKey = new ExtKey();
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            ExtKey  paymentKey = ceoKey.Derive(path); //Path : "1'/5/50"
        }
Exemple #15
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));
        }
Exemple #16
0
        public static void HDWallets()
        {
            // Deterministic wallet means you only have to save the seed.
            // From the seed, you can generate the same series of private keys over and over.

            ExtKey masterKey = new ExtKey();

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

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

            ExtKey extKey = new ExtKey();

            byte[] chainCode = extKey.ChainCode;
            Key    key       = extKey.PrivateKey;
            ExtKey newExtKey = new ExtKey(key, chainCode);

            // BitcoinExtKey is a base58 type equivalent
            // You can get a Public version of the master key and generate public keys without knowing the private.

            ExtPubKey masterPubKey = masterKey.Neuter();

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

            // Then you can get the corresponding private keys with the private master key.
            ExtPubKey pubKey1 = masterPubKey.Derive((uint)1);
            ExtKey    key1    = masterKey.Derive((uint)1);

            // Check its legitimacy
            Console.WriteLine("Generated address : " + pubKey1.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main));

            // However, the hierarchical side of the wallet comes in when you start deriving grandchild keys from the child keys.
            ExtKey key12 = key1.Derive((uint)2);
            // Or
            ExtKey key11 = masterKey.Derive(new KeyPath("1/1"));

            // Hierarchical keys are a nice way to classify the type of your keys for multiple accounts.
            // You can also securely separate off different people within these specific classifications.
            // However, you can normally get the master private key from the master public key and child private key

            ExtKey ceoKey = new ExtKey();

            Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main));

            ExtKey    accountingKey = ceoKey.Derive(0, false);
            ExtPubKey ceoPubKey     = ceoKey.Neuter();

            ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubKey);

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

            // In other words, it's a 2-way path for non-hardened keys.
            // Non-hardened keys should only be used for categorizing accounts that belong to a point of single control.
            // If you try to recover a parent's private key with a hardened child key, the program will crash.
            // You can also harden a childKey with the KeyPath by using an apostrophe after the child's index.

            var nonHardened = new KeyPath("1/2/3");
            var hardened    = new KeyPath("1/2/3'");

            // Let's imagine that Accounting generates 1 parent key for each customer and a child for each payment.

            string  accounting = "1'";
            int     custoemrId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + custoemrId + "/" + paymentId);
            // Path: "1'/5/50"
            ExtKey paymentKey = ceoKey.Derive(path);

            // Cold wallets like Trezor generator the HD Keys from a sentence that can easily be written down.
            // This sentence is referred to as "the seed" or "mnemonic".
            // It can eventually be protected by a password or a PIN.
            // The language that you use to generate your 'easy to write' sentence is called a Wordlist.

            Mnemonic mnemo  = new Mnemonic(Wordlist.English, WordCount.Twelve);
            ExtKey   hdRoot = mnemo.DeriveExtKey("my password");

            Console.WriteLine(mnemo);
            Mnemonic mnemoRecovered  = new Mnemonic("minute put grant neglect anxiety case globe win famous correct turn link", Wordlist.English);
            ExtKey   hdRootRecovered = mnemo.DeriveExtKey("my password");
        }
 public string GetMasterPublicKey()
 {
     return(_masterPubKey.ToString(network));
 }
Exemple #18
0
        public static void CreateWallet()
        {
            var         secret    = new BitcoinSecret("L3E7oUgKrmF4ED4xTSKem3NjduRcCVNmfG59wTG3p28YGkY9a5og");
            ExtKey      masterKey = new ExtKey();
            Transaction tx;
            var         input = new TxIn();
            //input.PrevOut = new OutPoint(new uint256("1CxZnG2Mb31YHcsoKx18yshWdbcM9Y1mb5"),0);
            Coin y = new Coin();

            y.Amount = 5;

            //ColoredTransaction coloredTransaction = new ColoredTransaction();
            Console.WriteLine("Address: " + secret.PubKey.GetAddress(Network.Main));
            Console.WriteLine("Key: " + masterKey.GetWif(Network.Main));
            Console.WriteLine("Master key : " + masterKey.ToString(Network.Main));
            for (int i = 0; i < 5; i++)
            {
                ExtKey key2 = masterKey.Derive((uint)i);
                Console.WriteLine("Key " + i + " : " + key2.ToString(Network.Main));
            }

            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.Main));
            }

            masterKey    = new ExtKey();
            masterPubKey = masterKey.Neuter();


            ExtPubKey pubkey1 = masterPubKey.Derive((uint)1);


            ExtKey key1 = masterKey.Derive((uint)1);


            Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main));
            Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main));

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

            ExtKey Key = new ExtKey();

            Console.WriteLine("Key: " + Key.ToString(Network.Main));
            ExtKey accountingKey = Key.Derive(0, hardened: false);

            ExtPubKey ceoPubkey = Key.Neuter();

            ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubkey);

            Console.WriteLine("Key recovered: " + ceoKeyRecovered.ToString(Network.Main));
            var nonHardened = new KeyPath("1/2/3");
            var hardened    = new KeyPath("1/2/3'");

            Key = new ExtKey();
            string  accounting = "1'";
            int     customerId = 5;
            int     paymentId  = 50;
            KeyPath path       = new KeyPath(accounting + "/" + customerId + "/" + paymentId);
            ExtKey  paymentKey = Key.Derive(path);
        }
Exemple #19
0
 private static DirectDerivationStrategy CreateDerivationStrategy(ExtPubKey pubKey = null)
 {
     pubKey = pubKey ?? new ExtKey().Neuter();
     return((DirectDerivationStrategy) new DerivationStrategyFactory(Network.RegTest).Parse($"{pubKey.ToString(Network.RegTest)}-[legacy]"));
 }
Exemple #20
0
 private static P2SHDerivationStrategy CreateP2SHDerivationStrategy(ExtPubKey pubKey = null)
 {
     pubKey = pubKey ?? new ExtKey().Neuter();
     return((P2SHDerivationStrategy) new DerivationStrategyFactory(Network.RegTest).Parse($"{pubKey.ToString(Network.RegTest)}-[p2sh]"));
 }
 public ClientDestinationWallet(BitcoinExtPubKey extPubKey, KeyPath derivationPath, IRepository repository, Network network)
 {
     if (derivationPath == null)
     {
         throw new ArgumentNullException("derivationPath");
     }
     if (extPubKey == null)
     {
         throw new ArgumentNullException("extPubKey");
     }
     if (repository == null)
     {
         throw new ArgumentNullException("repository");
     }
     if (network == null)
     {
         throw new ArgumentNullException("network");
     }
     _Network        = network;
     _Repository     = repository;
     _ExtPubKey      = extPubKey.ExtPubKey.Derive(derivationPath);
     _DerivationPath = derivationPath;
     _WalletId       = "Wallet_" + Encoders.Base58.EncodeData(Hashes.Hash160(Encoding.UTF8.GetBytes(_ExtPubKey.ToString() + "-" + derivationPath.ToString())).ToBytes());
 }
Exemple #22
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();
        }