public void TrySign(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath, SigHash sigHash = SigHash.All) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } if (accountHDScriptPubKey == null) { throw new ArgumentNullException(nameof(accountHDScriptPubKey)); } var cache = accountKey.AsHDKeyCache(); accountHDScriptPubKey = accountHDScriptPubKey.AsHDKeyCache(); foreach (var hdk in this.HDKeysFor(accountHDScriptPubKey, cache, accountKeyPath)) { if (((HDKeyCache)cache.Derive(hdk.AddressKeyPath)).Inner is ISecret k) { Sign(k.PrivateKey, sigHash); } else { throw new ArgumentException(paramName: nameof(accountKey), message: "This should be a private key"); } } }
/// <summary> /// Rebase the keypaths. /// If a PSBT updater only know the child HD public key but not the root one, another updater knowing the parent master key it is based on /// can rebase the paths. /// </summary> /// <param name="accountKey">The current account key</param> /// <param name="newRoot">The KeyPath with the fingerprint of the new root key</param> /// <returns>This PSBT</returns> public PSBT RebaseKeyPaths(IHDKey accountKey, RootedKeyPath newRoot) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } if (newRoot == null) { throw new ArgumentNullException(nameof(newRoot)); } accountKey = accountKey.AsHDKeyCache(); var accountKeyFP = accountKey.GetPublicKey().GetHDFingerPrint(); foreach (var o in HDKeysFor(accountKey).GroupBy(c => c.Coin)) { foreach (var keyPath in o) { o.Key.HDKeyPaths.Remove(keyPath.PubKey); o.Key.HDKeyPaths.Add(keyPath.PubKey, newRoot.Derive(keyPath.RootedKeyPath.KeyPath)); } } foreach (var xpub in GlobalXPubs.ToList()) { if (xpub.Key.ExtPubKey.PubKey == accountKey.GetPublicKey()) { GlobalXPubs.Remove(xpub.Key); GlobalXPubs.Add(xpub.Key, newRoot.Derive(xpub.Value.KeyPath)); } } return(this); }
/// <summary> /// Derive keyPaths as fast as possible using caching and parallelism /// </summary> /// <param name="hdkey">The hdKey to derive</param> /// <param name="keyPaths">keyPaths to derive</param> /// <returns>An array of keyPaths.Length size with the derived keys</returns> public static IHDKey[] Derive(this IHDKey hdkey, KeyPath[] keyPaths) { if (hdkey == null) { throw new ArgumentNullException(nameof(hdkey)); } if (keyPaths == null) { throw new ArgumentNullException(nameof(keyPaths)); } var result = new IHDKey[keyPaths.Length]; var cache = (HDKeyCache)hdkey.AsHDKeyCache(); #if !NOPARALLEL Parallel.For(0, keyPaths.Length, i => { result[i] = hdkey.Derive(keyPaths[i]); }); #else for (int i = 0; i < keyPaths.Length; i++) { result[i] = hdkey.Derive(keyPaths[i]); } #endif return(result); }
/// <summary> /// Filter the keys which contains the <paramref name="accountKey"/> and <paramref name="accountKeyPath"/>. /// </summary> /// <param name="accountKey">The account key that will be used to sign (ie. 49'/0'/0')</param> /// <param name="accountKeyPath">The account key path</param> /// <returns>HD Keys matching master root key</returns> public IEnumerable <PSBTHDKeyMatch> HDKeysFor(IHDKey accountKey, RootedKeyPath accountKeyPath = null) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } accountKey = accountKey.AsHDKeyCache(); return(Inputs.HDKeysFor(accountKey, accountKeyPath).OfType <PSBTHDKeyMatch>().Concat(Outputs.HDKeysFor(accountKey, accountKeyPath))); }
/// <summary> /// Filter the coins which contains the <paramref name="accountKey"/> and <paramref name="accountKeyPath"/> in the HDKeys and derive /// the same scriptPubKeys as <paramref name="accountHDScriptPubKey"/>. /// </summary> /// <param name="accountHDScriptPubKey">The hdScriptPubKey used to generate addresses</param> /// <param name="accountKey">The account key that will be used to sign (ie. 49'/0'/0')</param> /// <param name="accountKeyPath">The account key path</param> /// <returns>Inputs with HD keys matching masterFingerprint and account key</returns> public IEnumerable <PSBTCoin> CoinsFor(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath = null) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } if (accountHDScriptPubKey == null) { throw new ArgumentNullException(nameof(accountHDScriptPubKey)); } accountHDScriptPubKey = accountHDScriptPubKey.AsHDKeyCache(); accountKey = accountKey.AsHDKeyCache(); return(Inputs.CoinsFor(accountHDScriptPubKey, accountKey, accountKeyPath).OfType <PSBTCoin>().Concat(Outputs.CoinsFor(accountHDScriptPubKey, accountKey, accountKeyPath).OfType <PSBTCoin>())); }
internal IEnumerable <PSBTHDKeyMatch <T> > GetHDKeys(HDFingerprint?masterFingerprint, IHDKey accountKey) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } accountKey = accountKey.AsHDKeyCache(); var accountFingerprint = accountKey.GetPublicKey().GetHDFingerPrint(); foreach (var c in this) { foreach (var match in c.HDKeysFor(masterFingerprint, accountKey, accountFingerprint)) { yield return((PSBTHDKeyMatch <T>)match); } } }
internal IEnumerable <PSBTHDKeyMatch <T> > GetHDKeys(IHDScriptPubKey hdScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath = null) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } accountKey = accountKey.AsHDKeyCache(); hdScriptPubKey = hdScriptPubKey?.AsHDKeyCache(); var accountFingerprint = accountKey.GetPublicKey().GetHDFingerPrint(); foreach (var c in this) { foreach (var match in c.HDKeysFor(hdScriptPubKey, accountKey, accountKeyPath, accountFingerprint)) { yield return((PSBTHDKeyMatch <T>)match); } } }
/// <summary> /// Add keypath information to this PSBT for each input or output involving it /// </summary> /// <param name="masterKey">The master key of the keypaths</param> /// <param name="paths">The path of the public keys with their expected scriptPubKey</param> /// <returns>This PSBT</returns> public PSBT AddKeyPath(IHDKey masterKey, params Tuple <KeyPath, Script>[] paths) { if (masterKey == null) { throw new ArgumentNullException(nameof(masterKey)); } if (paths == null) { throw new ArgumentNullException(nameof(paths)); } masterKey = masterKey.AsHDKeyCache(); foreach (var path in paths) { var key = masterKey.Derive(path.Item1); AddKeyPath(masterKey.GetPublicKey().GetHDFingerPrint(), key.GetPublicKey(), path.Item1, path.Item2); } return(this); }
/// <summary> /// Sign all inputs which derive addresses from <paramref name="accountHDScriptPubKey"/> and that need to be signed by <paramref name="accountKey"/>. /// </summary> /// <param name="accountHDScriptPubKey">The address generator</param> /// <param name="accountKey">The account key with which to sign</param> /// <param name="accountKeyPath">The account key path (eg. [masterFP]/49'/0'/0')</param> /// <param name="sigHash">The SigHash</param> /// <returns>This PSBT</returns> public PSBT SignAll(IHDScriptPubKey accountHDScriptPubKey, IHDKey accountKey, RootedKeyPath accountKeyPath, SigHash sigHash = SigHash.All) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } if (accountHDScriptPubKey == null) { throw new ArgumentNullException(nameof(accountHDScriptPubKey)); } accountHDScriptPubKey = accountHDScriptPubKey.AsHDKeyCache(); accountKey = accountKey.AsHDKeyCache(); Money total = Money.Zero; foreach (var o in Inputs.CoinsFor(accountHDScriptPubKey, accountKey, accountKeyPath)) { o.TrySign(accountHDScriptPubKey, accountKey, accountKeyPath, sigHash); } return(this); }
public void TrySign(IHDKey masterKey, SigHash sigHash = SigHash.All) { if (masterKey == null) { throw new ArgumentNullException(nameof(masterKey)); } var cache = masterKey.AsHDKeyCache(); foreach (var hdk in this.HDKeysFor(masterKey)) { if (((HDKeyCache)cache.Derive(hdk.KeyPath)).Inner is ExtKey k) { Sign(k.PrivateKey, sigHash); } else { throw new ArgumentException(paramName: nameof(masterKey), message: "This should be a private key"); } } }
public PSBT SignAll(IHDKey masterKey, SigHash sigHash = SigHash.All) { if (masterKey == null) { throw new ArgumentNullException(nameof(masterKey)); } var cache = masterKey.AsHDKeyCache(); foreach (var o in Inputs.HDKeysFor(masterKey)) { if (((HDKeyCache)cache.Derive(o.KeyPath)).Inner is ExtKey k) { o.Coin.Sign(k.PrivateKey, sigHash); } else { throw new ArgumentException(paramName: nameof(masterKey), message: "This should be a private key"); } } return(this); }
/// <summary> /// Rebase the keypaths. /// If a PSBT updater only know the child HD public key but not the root one, another updater knowing the parent master key it is based on /// can rebase the paths. /// </summary> /// <param name="accountKey">The current account key</param> /// <param name="accountKeyPath">The path from the master key to the accountKey</param> /// <param name="masterFingerprint">The master key fingerprint</param> /// <returns></returns> public PSBT RebaseKeyPaths(IHDKey accountKey, KeyPath accountKeyPath, HDFingerprint masterFingerprint) { if (accountKey == null) { throw new ArgumentNullException(nameof(accountKey)); } if (accountKeyPath == null) { throw new ArgumentNullException(nameof(accountKeyPath)); } accountKey = accountKey.AsHDKeyCache(); var accountKeyFP = accountKey.GetPublicKey().GetHDFingerPrint(); foreach (var o in HDKeysFor(null, accountKey).GroupBy(c => c.Coin)) { foreach (var keyPath in o) { o.Key.HDKeyPaths.Remove(keyPath.PubKey); o.Key.HDKeyPaths.Add(keyPath.PubKey, Tuple.Create(masterFingerprint, accountKeyPath.Derive(keyPath.KeyPath))); } } return(this); }