public ExtKey(CCKey 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); }
public RootedKeyPath(HDFingerprint masterFingerprint, KeyPath keyPath) { if (keyPath == null) { throw new ArgumentNullException(nameof(keyPath)); } _KeyPath = keyPath; _MasterFingerprint = masterFingerprint; }
public RootedKeyPath(IHDKey masterKey, KeyPath keyPath) { if (masterKey == null) { throw new ArgumentNullException(nameof(masterKey)); } if (keyPath == null) { throw new ArgumentNullException(nameof(keyPath)); } _KeyPath = keyPath; _MasterFingerprint = new HDFingerprint(masterKey.GetPublicKey()); }
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); }
/// <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, CCKey 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); }
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) { return(false); } if (!HDFingerprint.TryParse(str.Substring(0, separator), out var fp)) { return(false); } if (!KeyPath.TryParse(str.Substring(separator + 1), out var keyPath)) { return(false); } result = new RootedKeyPath(fp, keyPath); return(true); }
/// <summary> /// Recreates the private key of the parent from the private key of the child /// combinated with the public key of the parent (hardened children cannot be /// used to recreate the parent). /// </summary> public ExtKey GetParentExtKey(ExtPubKey parent) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } if (Depth == 0) { throw new InvalidOperationException("This ExtKey is the root key of the HD tree"); } if (IsHardened) { throw new InvalidOperationException("This private key is hardened, so you can't get its parent"); } var expectedFingerPrint = new HDFingerprint(parent.PubKey); if (parent.Depth != this.Depth - 1 || expectedFingerPrint != parentFingerprint) { throw new ArgumentException("The parent ExtPubKey is not the immediate parent of this ExtKey", "parent"); } #if HAS_SPAN Span <byte> pubkey = stackalloc byte[33]; Span <byte> l = stackalloc byte[64]; parent.PubKey.ToBytes(pubkey, out _); Hashes.BIP32Hash(parent.vchChainCode, nChild, pubkey[0], pubkey.Slice(1), l); var parse256LL = new Secp256k1.Scalar(l.Slice(0, 32), out int overflow); if (overflow != 0 || parse256LL.IsZero) { throw new InvalidOperationException("Invalid extkey (this should never happen)"); } if (!l.Slice(32, 32).SequenceEqual(vchChainCode)) { throw new InvalidOperationException("The derived chain code of the parent is not equal to this child chain code"); } var kPar = this.PrivateKey._ECKey.sec + parse256LL.Negate(); return(new ExtKey { vchChainCode = parent.vchChainCode, nDepth = parent.Depth, parentFingerprint = parent.ParentFingerprint, nChild = parent.nChild, key = new Key(new Secp256k1.ECPrivKey(kPar, this.PrivateKey._ECKey.ctx, true), true) }); #else byte[] l = null; byte[] ll = new byte[32]; byte[] lr = new byte[32]; var pubKey = parent.PubKey.ToBytes(); l = Hashes.BIP32Hash(parent.vchChainCode, nChild, pubKey[0], pubKey.SafeSubarray(1)); Array.Copy(l, ll, 32); Array.Copy(l, 32, lr, 0, 32); var ccChild = lr; BigInteger parse256LL = new BigInteger(1, ll); BigInteger N = ECKey.CURVE.N; if (!ccChild.SequenceEqual(vchChainCode)) { throw new InvalidOperationException("The derived chain code of the parent is not equal to this child chain code"); } var keyBytes = PrivateKey.ToBytes(); var key = new BigInteger(1, keyBytes); BigInteger kPar = key.Add(parse256LL.Negate()).Mod(N); var keyParentBytes = kPar.ToByteArrayUnsigned(); if (keyParentBytes.Length < 32) { keyParentBytes = new byte[32 - keyParentBytes.Length].Concat(keyParentBytes).ToArray(); } var parentExtKey = new ExtKey { vchChainCode = parent.vchChainCode, nDepth = parent.Depth, parentFingerprint = parent.ParentFingerprint, nChild = parent.nChild, key = new CCKey(keyParentBytes) }; return(parentExtKey); #endif }
public RootedKeyPath ToRootedKeyPath(HDFingerprint masterFingerprint) { return(new RootedKeyPath(masterFingerprint, this)); }