public Key Derivate(byte[] cc, uint nChild, out byte[] ccChild) { byte[] l = null; byte[] ll = new byte[32]; byte[] lr = new byte[32]; if ((nChild >> 31) == 0) { var pubKey = PubKey.ToBytes(); l = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.Skip(1).ToArray()); } else { l = Hashes.BIP32Hash(cc, nChild, 0, this.ToBytes()); } Array.Copy(l, ll, 32); Array.Copy(l, 32, lr, 0, 32); ccChild = lr; BigInteger parse256LL = new BigInteger(1, ll); BigInteger kPar = new BigInteger(1, vch); BigInteger N = ECKey.CURVE.N; if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException("You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } var key = parse256LL.Add(kPar).Mod(N); if (key == BigInteger.Zero) { throw new InvalidOperationException("You won the big prize ! this would happen only 1 in 2^127. Take a screenshot, and roll the dice again."); } return(new Key(key.ToByteArrayUnsigned())); }
/// <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("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"); } byte[] expectedFingerPrint = parent.CalculateChildFingerprint(); if (parent.Depth != this.Depth - 1 || !expectedFingerPrint.SequenceEqual(vchFingerprint)) { throw new ArgumentException("The parent ExtPubKey is not the immediate parent of this ExtKey", "parent"); } byte[] l = null; var ll = new byte[32]; var lr = new byte[32]; byte[] 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); byte[] ccChild = lr; var 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"); } byte[] keyBytes = PrivateKey.ToBytes(); var key = new BigInteger(1, keyBytes); BigInteger kPar = key.Add(parse256LL.Negate()).Mod(N); byte[] 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, vchFingerprint = parent.Fingerprint, nChild = parent.nChild, key = new Key(keyParentBytes) }; return(parentExtKey); }
public PubKey Derivate(byte[] cc, uint nChild, out byte[] ccChild) { if (!IsCompressed) { throw new InvalidOperationException("The pubkey must be compressed"); } if ((nChild >> 31) != 0) { throw new InvalidOperationException("A public key can't derivate an hardened child"); } #if HAS_SPAN Span <byte> vout = stackalloc byte[64]; vout.Clear(); Span <byte> pubkey = stackalloc byte[33]; this.ToBytes(pubkey, out _); Hashes.BIP32Hash(cc, nChild, pubkey[0], pubkey.Slice(1), vout); ccChild = new byte[32];; vout.Slice(32, 32).CopyTo(ccChild); return(new PubKey(this.ECKey.AddTweak(vout.Slice(0, 32)), true)); #else byte[] lr = null; byte[] l = new byte[32]; byte[] r = new byte[32]; var pubKey = ToBytes(); lr = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.Skip(1).ToArray()); Array.Copy(lr, l, 32); Array.Copy(lr, 32, r, 0, 32); ccChild = r; BigInteger N = ECKey.CURVE.N; BigInteger parse256LL = new BigInteger(1, l); if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException("You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } var q = ECKey.CURVE.G.Multiply(parse256LL).Add(ECKey.GetPublicKeyParameters().Q); if (q.IsInfinity) { throw new InvalidOperationException("You won the big prize ! this would happen only 1 in 2^127. Take a screenshot, and roll the dice again."); } q = q.Normalize(); var p = new NBitcoin.BouncyCastle.Math.EC.FpPoint(ECKey.CURVE.Curve, q.XCoord, q.YCoord, true); return(new PubKey(p.GetEncoded())); #endif }
public Key Derivate(byte[] cc, uint nChild, out byte[] ccChild) { byte[] l = null; if (nChild >> 31 == 0) { var pubKey = PubKey.ToBytes(); l = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.SafeSubArray(1)); } else { l = Hashes.BIP32Hash(cc, nChild, 0, this.ToBytes()); } var ll = l.SafeSubArray(0, 32); var lr = l.SafeSubArray(32, 32); ccChild = lr; var parse256LL = new BigInteger(1, ll); var kPar = new BigInteger(1, _vch); var N = ECKey.Curve.N; if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException( "You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } var key = parse256LL.Add(kPar).Mod(N); if (key == BigInteger.Zero) { throw new InvalidOperationException( "You won the big prize ! this has probability lower than 1 in 2^127. Take a screenshot, and roll the dice again."); } var keyBytes = key.ToByteArrayUnsigned(); if (keyBytes.Length < 32) { keyBytes = new byte[32 - keyBytes.Length].Concat(keyBytes).ToArray(); } return(new Key(keyBytes)); }
public PubKey Derivate(byte[] cc, uint nChild, out byte[] ccChild) { byte[] lr = null; var l = new byte[32]; var r = new byte[32]; if (nChild >> 31 == 0) { var pubKey = ToBytes(); lr = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.Skip(1).ToArray()); } else { throw new InvalidOperationException("A public key can't derivate an hardened child"); } Array.Copy(lr, l, 32); Array.Copy(lr, 32, r, 0, 32); ccChild = r; var N = ECKey.CURVE.N; var parse256LL = new BigInteger(1, l); if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException( "You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } var q = ECKey.CURVE.G.Multiply(parse256LL).Add(this.ECKey.GetPublicKeyParameters().Q); if (q.IsInfinity) { throw new InvalidOperationException( "You won the big prize ! this would happen only 1 in 2^127. Take a screenshot, and roll the dice again."); } q = q.Normalize(); var p = new FpPoint(ECKey.CURVE.Curve, q.XCoord, q.YCoord, true); return(new PubKey(p.GetEncoded())); }
public PubKey Derivate(byte[] cc, uint nChild, out byte[] ccChild) { byte[] lr = null; byte[] l = new byte[32]; byte[] r = new byte[32]; if ((nChild >> 31) == 0) { var pubKey = ToBytes(); lr = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.Skip(1).ToArray()); } else { throw new InvalidOperationException("Impossible to derivate a child key from a hardened one"); } Array.Copy(lr, l, 32); Array.Copy(lr, 32, r, 0, 32); ccChild = r; BigInteger N = ECKey.CURVE.N; BigInteger kPar = new BigInteger(1, this.vch); BigInteger parse256LL = new BigInteger(1, l); if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException("You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } var q = ECKey.CURVE.G.Multiply(parse256LL).Add(_Key.GetPublicKeyParameters().Q); if (q.IsInfinity) { throw new InvalidOperationException("You won the big prize ! this would happen only 1 in 2^127. Take a screenshot, and roll the dice again."); } var p = new NBitcoin.BouncyCastle.Math.EC.FpPoint(ECKey.CURVE.Curve, q.X, q.Y, true); return(new PubKey(p.GetEncoded())); }
/// <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 = parent.PubKey.GetHDFingerPrint(); 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 Key(keyParentBytes) }; return(parentExtKey); #endif }
public Key Derivate(byte[] cc, uint nChild, out byte[] ccChild) { AssertNotDisposed(); #if HAS_SPAN if (!IsCompressed) { throw new InvalidOperationException("The key must be compressed"); } Span <byte> vout = stackalloc byte[64]; vout.Clear(); if ((nChild >> 31) == 0) { Span <byte> pubkey = stackalloc byte[33]; this.PubKey.ToBytes(pubkey, out _); Hashes.BIP32Hash(cc, nChild, pubkey[0], pubkey.Slice(1), vout); } else { Span <byte> privkey = stackalloc byte[32]; this._ECKey.WriteToSpan(privkey); Hashes.BIP32Hash(cc, nChild, 0, privkey, vout); privkey.Fill(0); } ccChild = new byte[32]; vout.Slice(32, 32).CopyTo(ccChild); Secp256k1.ECPrivKey keyChild = _ECKey.TweakAdd(vout.Slice(0, 32)); vout.Clear(); return(new Key(keyChild, true)); #else byte[]? l = null; if ((nChild >> 31) == 0) { var pubKey = PubKey.ToBytes(); l = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.SafeSubarray(1)); } else { l = Hashes.BIP32Hash(cc, nChild, 0, this.ToBytes()); } var ll = l.SafeSubarray(0, 32); var lr = l.SafeSubarray(32, 32); ccChild = lr; var parse256LL = new BigInteger(1, ll); var kPar = new BigInteger(1, vch); var N = ECKey.CURVE.N; if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException("You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } var key = parse256LL.Add(kPar).Mod(N); if (key == BigInteger.Zero) { throw new InvalidOperationException("You won the big prize ! this has probability lower than 1 in 2^127. Take a screenshot, and roll the dice again."); } var keyBytes = key.ToByteArrayUnsigned(); if (keyBytes.Length < 32) { keyBytes = new byte[32 - keyBytes.Length].Concat(keyBytes).ToArray(); } return(new Key(keyBytes)); #endif }