/// Generates an HD public key derived from an extended public key. /// </summary> /// <param name="accountExtPubKey">The extended public key used to generate child keys.</param> /// <param name="index">The index of the child key to generate.</param> /// <param name="isChange">A value indicating whether the public key to generate corresponds to a change address.</param> /// <returns> /// An HD public key derived from an extended public key. /// </returns> public Script GeneratePublicKey(int hdPathIndex, Network network, bool isChange = false) { List <PubKey> derivedPubKeys = new List <PubKey>(); foreach (var xpub in this.MultisigScheme.XPubs) { derivedPubKeys.Add(HdOperations.GeneratePublicKey(xpub, hdPathIndex, isChange, network)); } var sortedkeys = LexographicalSort(derivedPubKeys); Script redeemScript = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(this.MultisigScheme.Threashold, sortedkeys.ToArray()); return(redeemScript); }
/// <summary> /// Creates a number of additional addresses in the current account. /// </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 at least one transaction. /// </remarks> /// <param name="network">The network these addresses will be for.</param> /// <param name="addressesQuantity">The number of addresses to create.</param> /// <param name="isChange">Whether the addresses added are change (internal) addresses or receiving (external) addresses.</param> /// <returns>The created addresses.</returns> public IEnumerable <HdAddress> CreateAddresses(Network network, int addressesQuantity, bool isChange = false) { ICollection <HdAddress> addresses = isChange ? this.InternalAddresses : this.ExternalAddresses; // Get the index of the last address. int firstNewAddressIndex = 0; if (addresses.Any()) { firstNewAddressIndex = addresses.Max(add => add.Index) + 1; } var addressesCreated = new List <HdAddress>(); for (int i = firstNewAddressIndex; i < firstNewAddressIndex + addressesQuantity; i++) { // Retrieve the pubkey associated with the private key of this address index. PubKey pubkey = HdOperations.GeneratePublicKey(this.ExtendedPubKey, i, isChange); // Generate the P2PKH address corresponding to the pubkey. BitcoinPubKeyAddress address = pubkey.GetAddress(network); BitcoinWitPubKeyAddress witAddress = pubkey.GetSegwitAddress(network); // Add the new address details to the list of addresses. var newAddress = new HdAddress { Index = i, HdPath = HdOperations.CreateHdPath((int)this.GetCoinType(), this.Index, isChange, i), ScriptPubKey = address.ScriptPubKey, Pubkey = pubkey.ScriptPubKey, Bech32Address = witAddress.ToString(), Address = address.ToString(), }; addresses.Add(newAddress); addressesCreated.Add(newAddress); } if (isChange) { this.InternalAddresses = addresses; } else { this.ExternalAddresses = addresses; } return(addressesCreated); }
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); }