public ExtKey(Key key, byte[] chainCode, byte depth, byte[] fingerprint, uint child) { if (key == null) { throw new ArgumentNullException(nameof(key)); } if (chainCode == null) { throw new ArgumentNullException(nameof(chainCode)); } if (fingerprint == null) { throw new ArgumentNullException(nameof(fingerprint)); } if (fingerprint.Length != 4) { throw new ArgumentException(string.Format("The fingerprint must be {0} bytes.", 4), "fingerprint"); } if (chainCode.Length != ChainCodeLength) { throw new ArgumentException(string.Format("The chain code must be {0} bytes.", ChainCodeLength), "chainCode"); } this.key = key; this.nDepth = depth; this.nChild = child; parentFingerprint = new HDFingerprint(fingerprint); Buffer.BlockCopy(chainCode, 0, vchChainCode, 0, ChainCodeLength); }
/// <summary> /// Add keypath information to this PSBT /// </summary> /// <param name="fingerprint">The fingerprint of the master's key</param> /// <param name="pubkey">A public key to add</param> /// <param name="path">The key path</param> /// <param name="scriptPubKey">A specific scriptPubKey this pubkey is involved with</param> /// <returns>This PSBT</returns> public PSBT AddKeyPath(HDFingerprint fingerprint, PubKey pubkey, KeyPath path, Script scriptPubKey) { if (pubkey == null) { throw new ArgumentNullException(nameof(pubkey)); } if (path == null) { throw new ArgumentNullException(nameof(path)); } var txBuilder = CreateTransactionBuilder(); foreach (var o in this.Inputs.OfType <PSBTCoin>().Concat(this.Outputs)) { var coin = o.GetCoin(); if (coin == null) { continue; } if ((scriptPubKey != null && coin.ScriptPubKey == scriptPubKey) || ((o.GetSignableCoin() ?? coin.TryToScriptCoin(pubkey)) is Coin c && txBuilder.IsCompatibleKeyFromScriptCode(pubkey, c.GetScriptCode())) || txBuilder.IsCompatibleKeyFromScriptCode(pubkey, coin.ScriptPubKey)) { o.AddKeyPath(fingerprint, pubkey, path); } } return(this); }
public ExtPubKey(byte[] bytes, int offset, int length) { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } if (bytes.Length - offset != Length) { throw new FormatException($"An extpubkey should be {Length} bytes"); } int i = offset; nDepth = bytes[i]; i++; parentFingerprint = new HDFingerprint(bytes, i); i += 4; nChild = Utils.ToUInt32(bytes, i, false); i += 4; vchChainCode = new byte[32]; Array.Copy(bytes, i, vchChainCode, 0, 32); i += 32; var pk = new byte[33]; Array.Copy(bytes, i, pk, 0, 33); pubkey = new PubKey(pk); }
public ExtPubKey(ReadOnlySpan <byte> bytes) { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } if (bytes.Length != Length) { throw new FormatException($"An extpubkey should be {Length} bytes"); } int i = 0; nDepth = bytes[i]; i++; parentFingerprint = new HDFingerprint(bytes.Slice(i, 4)); i += 4; nChild = Utils.ToUInt32(bytes.Slice(i, 4), false); i += 4; vchChainCode = new byte[32]; bytes.Slice(i, 32).CopyTo(vchChainCode); i += 32; Span <byte> pk = stackalloc byte[33]; bytes.Slice(i, 33).CopyTo(pk); pubkey = new PubKey(pk); }
public void AddKeyPath(HDFingerprint fingerprint, PubKey key, KeyPath path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } }
private ExtKey(ReadOnlySpan <byte> bytes, bool isSeed) { if (isSeed) { key = CalculateKey(bytes, out var cc); this.vchChainCode = cc; } else { if (bytes.Length != Length) { throw new FormatException($"An extpubkey should be {Length} bytes"); } int i = 0; nDepth = bytes[i]; i++; parentFingerprint = new HDFingerprint(bytes.Slice(1, 4)); i += 4; nChild = Utils.ToUInt32(bytes.Slice(i, 4), false); i += 4; vchChainCode = new byte[32]; bytes.Slice(i, 32).CopyTo(vchChainCode); i += 32; if (bytes[i++] != 0) { throw new FormatException($"Invalid ExtKey"); } Span <byte> pk = stackalloc byte[32]; bytes.Slice(i, 32).CopyTo(pk); key = new Key(pk); } }
public static bool TryParse(string str, out RootedKeyPath result) { if (str == null) { throw new ArgumentNullException(nameof(str)); } result = null; var separator = str.IndexOf('/'); if (separator == -1) { if (!HDFingerprint.TryParse(str, out var fp)) { return(false); } result = new RootedKeyPath(fp, KeyPath.Empty); } else { if (!HDFingerprint.TryParse(str.Substring(0, separator), out var fp)) { return(false); } if (!NBitcoin.KeyPath.TryParse(str.Substring(separator + 1), out var keyPath)) { return(false); } result = new RootedKeyPath(fp, keyPath); } return(true); }
public RootedKeyPath(HDFingerprint masterFingerprint, KeyPath keyPath) { if (keyPath == null) { throw new ArgumentNullException(nameof(keyPath)); } _KeyPath = keyPath; _MasterFingerprint = masterFingerprint; }
public void ReadWrite(ref HDFingerprint fingerPrint) { var v = fingerPrint.ToUInt32(); ReadWrite(ref v); if (!this.Serializing) { fingerPrint = new HDFingerprint(v); } }
public HDFingerprint GetHDFingerPrint() { if (fp is HDFingerprint f) { return(f); } f = new HDFingerprint(this.Hash.ToBytes(), 0); fp = f; return(f); }
public void AddKeyPath(HDFingerprint fingerprint, PubKey key, KeyPath keyPath) { if (keyPath == null) { throw new ArgumentNullException(nameof(keyPath)); } if (key == null) { throw new ArgumentNullException(nameof(key)); } hd_keypaths.Add(key, new Tuple <HDFingerprint, KeyPath>(fingerprint, keyPath)); }
public static bool TryParse(string str, out HDFingerprint result) { if (str == null) { throw new ArgumentNullException(nameof(str)); } result = default; if (!HexEncoder.IsWellFormed(str) || str.Length != 4 * 2) { return(false); } result = new HDFingerprint(Encoders.Hex.DecodeData(str)); return(true); }
public void ReadWrite(ref HDFingerprint fingerPrint) { #if HAS_SPAN Span <byte> bytes = stackalloc byte[4]; fingerPrint.ToBytes(bytes); #else var bytes = fingerPrint.ToBytes(); #endif ReadWrite(ref bytes); if (!this.Serializing) { fingerPrint = new HDFingerprint(bytes); } }
/// <summary> /// Constructor. Creates an extended key from the public key and corresponding private key. /// </summary> /// <remarks> /// <para> /// The ExtPubKey has the relevant values for child number, depth, chain code, and fingerprint. /// </para> /// </remarks> public ExtKey(ExtPubKey extPubKey, Key privateKey) { if (extPubKey == null) { throw new ArgumentNullException(nameof(extPubKey)); } if (privateKey == null) { throw new ArgumentNullException(nameof(privateKey)); } this.nChild = extPubKey.nChild; this.nDepth = extPubKey.nDepth; this.vchChainCode = extPubKey.vchChainCode; this.parentFingerprint = extPubKey.parentFingerprint; this.key = privateKey; }
public ExtPubKey(PubKey pubkey, byte[] chainCode, byte depth, HDFingerprint fingerprint, uint child) { if (pubkey == null) { throw new ArgumentNullException(nameof(pubkey)); } if (chainCode == null) { throw new ArgumentNullException(nameof(chainCode)); } if (chainCode.Length != ChainCodeLength) { throw new ArgumentException(string.Format("The chain code must be {0} bytes.", ChainCodeLength), "chainCode"); } this.pubkey = pubkey; this.nDepth = depth; this.nChild = child; parentFingerprint = fingerprint; Buffer.BlockCopy(chainCode, 0, vchChainCode, 0, ChainCodeLength); }
/// <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="oldFingerprint">The old fingerprint</param> /// <param name="newFingerprint">The new fingerprint of the master key</param> /// <param name="newRoot">The root of the KeyPath who had the old fingerprint</param> /// <returns></returns> public PSBT RebaseKeyPaths(HDFingerprint oldFingerprint, HDFingerprint newFingerprint, KeyPath newRoot) { if (newRoot == null) { throw new ArgumentNullException(nameof(newRoot)); } foreach (var o in Inputs.OfType <PSBTCoin>().Concat(Outputs)) { foreach (var keypath in o.HDKeyPaths.ToList()) { if (keypath.Value.Item1 == oldFingerprint) { var newKeyPath = newRoot.Derive(keypath.Value.Item2); o.HDKeyPaths.Remove(keypath.Key); o.HDKeyPaths.Add(keypath.Key, Tuple.Create(newFingerprint, newKeyPath)); } } } return(this); }
/// <summary> /// Add keypath information to this PSBT /// </summary> /// <param name="fingerprint">The fingerprint of the master's key</param> /// <param name="pubkey">A public key to add</param> /// <param name="path">The key path</param> /// <param name="scriptPubKey">A specific scriptPubKey this pubkey is involved with</param> /// <returns>This PSBT</returns> public PSBT AddKeyPath(HDFingerprint fingerprint, PubKey pubkey, KeyPath path, Script scriptPubKey) { if (pubkey == null) { throw new ArgumentNullException(nameof(pubkey)); } if (path == null) { throw new ArgumentNullException(nameof(path)); } foreach (var input in this.Inputs) { if (scriptPubKey != null) { if (scriptPubKey == input.GetProbableScriptPubKey()) { input.AddKeyPath(fingerprint, pubkey, path); } } else if (input.IsRelatedKey(pubkey)) { input.AddKeyPath(fingerprint, pubkey, path); } } foreach (var ouptut in this.Outputs) { if (scriptPubKey != null) { if (scriptPubKey == ouptut.ScriptPubKey) { ouptut.AddKeyPath(fingerprint, pubkey, path); } } else if (ouptut.IsRelatedKey(pubkey)) { ouptut.AddKeyPath(fingerprint, pubkey, path); } } return(this); }
public virtual void AddKeyPath(HDFingerprint fingerprint, PubKey key, KeyPath path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } hd_keypaths.AddOrReplace(key, new Tuple <HDFingerprint, KeyPath>(fingerprint, path)); // Let's try to be smart, if the added key match the scriptPubKey then we are in p2psh p2wpkh if (Parent.Settings.IsSmart && redeem_script == null) { var output = GetCoin(); if (output != null) { if (key.WitHash.ScriptPubKey.Hash.ScriptPubKey == output.ScriptPubKey) { redeem_script = key.WitHash.ScriptPubKey; } } } }
/// <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); }
private ExtKey(byte[] bytes, bool isSeed) { if (isSeed) { key = CalculateKey(bytes, out var cc); this.vchChainCode = cc; } else { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } if (bytes.Length != Length) { throw new FormatException($"An extpubkey should be {Length} bytes"); } int i = 0; nDepth = bytes[i]; i++; parentFingerprint = new HDFingerprint(bytes, i); i += 4; nChild = Utils.ToUInt32(bytes, i, false); i += 4; vchChainCode = new byte[32]; Array.Copy(bytes, i, vchChainCode, 0, 32); i += 32; if (bytes[i++] != 0) { throw new FormatException($"Invalid ExtKey"); } var pk = new byte[32]; Array.Copy(bytes, i, pk, 0, 32); key = new Key(pk); } }
internal PSBTInput(BitcoinStream stream, PSBT parent, uint index, TxIn input) : base(parent) { TxIn = input; Index = index; originalScriptSig = TxIn.ScriptSig ?? Script.Empty; originalWitScript = TxIn.WitScript ?? WitScript.Empty; byte[] k = new byte[0]; byte[] v = new byte[0]; try { stream.ReadWriteAsVarString(ref k); } catch (EndOfStreamException e) { throw new FormatException("Invalid PSBTInput. Failed to Parse key.", e); } while (k.Length != 0) { try { stream.ReadWriteAsVarString(ref v); } catch (EndOfStreamException e) { throw new FormatException("Invalid PSBTInput. Failed to parse key.", e); } switch (k.First()) { case PSBTConstants.PSBT_IN_NON_WITNESS_UTXO: if (k.Length != 1) { throw new FormatException("Invalid PSBTInput. Contains illegal value in key for NonWitnessUTXO"); } if (non_witness_utxo != null) { throw new FormatException("Invalid PSBTInput. Duplicate non_witness_utxo"); } non_witness_utxo = this.GetConsensusFactory().CreateTransaction(); non_witness_utxo.FromBytes(v); break; case PSBTConstants.PSBT_IN_WITNESS_UTXO: if (k.Length != 1) { throw new FormatException("Invalid PSBTInput. Contains illegal value in key for WitnessUTXO"); } if (witness_utxo != null) { throw new FormatException("Invalid PSBTInput. Duplicate witness_utxo"); } if (this.GetConsensusFactory().TryCreateNew <TxOut>(out var txout)) { witness_utxo = txout; } else { witness_utxo = new TxOut(); } witness_utxo.FromBytes(v); break; case PSBTConstants.PSBT_IN_PARTIAL_SIG: var pubkey = new PubKey(k.Skip(1).ToArray()); if (partial_sigs.ContainsKey(pubkey)) { throw new FormatException("Invalid PSBTInput. Duplicate key for partial_sigs"); } partial_sigs.Add(pubkey, new TransactionSignature(v)); break; case PSBTConstants.PSBT_IN_SIGHASH: if (k.Length != 1) { throw new FormatException("Invalid PSBTInput. Contains illegal value in key for SigHash type"); } if (!(sighash_type is null)) { throw new FormatException("Invalid PSBTInput. Duplicate key for sighash_type"); } if (v.Length != 4) { throw new FormatException("Invalid PSBTInput. SigHash Type is not 4 byte"); } var value = Utils.ToUInt32(v, 0, true); if (!Enum.IsDefined(typeof(SigHash), value)) { throw new FormatException($"Invalid PSBTInput Unknown SigHash Type {value}"); } sighash_type = (SigHash)value; break; case PSBTConstants.PSBT_IN_REDEEMSCRIPT: if (k.Length != 1) { throw new FormatException("Invalid PSBTInput. Contains illegal value in key for redeem script"); } if (redeem_script != null) { throw new FormatException("Invalid PSBTInput. Duplicate key for redeem_script"); } redeem_script = Script.FromBytesUnsafe(v); break; case PSBTConstants.PSBT_IN_WITNESSSCRIPT: if (k.Length != 1) { throw new FormatException("Invalid PSBTInput. Contains illegal value in key for witness script"); } if (witness_script != null) { throw new FormatException("Invalid PSBTInput. Duplicate key for redeem_script"); } witness_script = Script.FromBytesUnsafe(v); break; case PSBTConstants.PSBT_IN_BIP32_DERIVATION: var pubkey2 = new PubKey(k.Skip(1).ToArray()); if (hd_keypaths.ContainsKey(pubkey2)) { throw new FormatException("Invalid PSBTInput. Duplicate key for hd_keypaths"); } var masterFingerPrint = new HDFingerprint(v.Take(4).ToArray()); KeyPath path = KeyPath.FromBytes(v.Skip(4).ToArray()); hd_keypaths.Add(pubkey2, new RootedKeyPath(masterFingerPrint, path)); break; case PSBTConstants.PSBT_IN_SCRIPTSIG: if (k.Length != 1) { throw new FormatException("Invalid PSBTInput. Contains illegal value in key for final scriptsig"); } if (final_script_sig != null) { throw new FormatException("Invalid PSBTInput. Duplicate key for final_script_sig"); } final_script_sig = Script.FromBytesUnsafe(v); break; case PSBTConstants.PSBT_IN_SCRIPTWITNESS: if (k.Length != 1) { throw new FormatException("Invalid PSBTInput. Contains illegal value in key for final script witness"); } if (final_script_witness != null) { throw new FormatException("Invalid PSBTInput. Duplicate key for final_script_witness"); } final_script_witness = new WitScript(v); break; default: if (unknown.ContainsKey(k)) { throw new FormatException("Invalid PSBTInput. Duplicate key for unknown value"); } unknown.Add(k, v); break; } stream.ReadWriteAsVarString(ref k); } }
public override void AddKeyPath(HDFingerprint fingerprint, PubKey key, KeyPath path) { base.AddKeyPath(fingerprint, key, path); TrySlimOutput(); }
public RootedKeyPath ToRootedKeyPath(HDFingerprint masterFingerprint) { return(new RootedKeyPath(masterFingerprint, this)); }
/// <summary> /// Add keypath information to this PSBT for each input or output involving it /// </summary> /// <param name="fingerprint">The fingerprint of the master's key</param> /// <param name="pubkey">A public key to add</param> /// <param name="path">The key path</param> /// <returns>This PSBT</returns> public PSBT AddKeyPath(HDFingerprint fingerprint, PubKey pubkey, KeyPath path) { return(AddKeyPath(fingerprint, pubkey, path, null)); }