public (bool ok, KzPubKey keyChild, KzUInt256 ccChild) Derive(uint nChild, KzUInt256 cc) { if (!IsValid || !IsCompressed || nChild >= HardenedBit) goto fail; var vout = new byte[64]; KzHashes.BIP32Hash(cc, nChild, ReadOnlySpan[0], ReadOnlySpan.Slice(1), vout); var sout = vout.AsSpan(); var ccChild = new KzUInt256(); sout.Slice(32, 32).CopyTo(ccChild.Span); var pkbs = new byte[64]; if (!secp256k1.PublicKeyParse(pkbs.AsSpan(), ReadOnlySpan)) goto fail; if (!secp256k1.PubKeyTweakAdd(pkbs.AsSpan(), sout.Slice(0, 32))) goto fail; var dataChild = new byte[33]; if (!secp256k1.PublicKeySerialize(dataChild.AsSpan(), pkbs, Flags.SECP256K1_EC_COMPRESSED)) goto fail; var keyChild = new KzPubKey(true); dataChild.AsSpan().CopyTo(keyChild.Span); return (true, keyChild, ccChild); fail: return (false, null, KzUInt256.Zero); }
public (bool ok, KzPrivKey keyChild, KzUInt256 ccChild) Derive(uint nChild, KzUInt256 cc) { if (!IsValid || !IsCompressed) { goto fail; } var vout = new byte[64]; if (nChild < HardenedBit) { // Not hardened. var pubkey = GetPubKey(); Debug.Assert(pubkey.ReadOnlySpan.Length == 33); KzHashes.BIP32Hash(cc, nChild, pubkey.ReadOnlySpan[0], pubkey.ReadOnlySpan.Slice(1), vout); } else { // Hardened. Debug.Assert(keydata.Span.Length == 32); KzHashes.BIP32Hash(cc, nChild, 0, keydata.Span, vout); } var sout = vout.AsSpan(); var ccChild = new KzUInt256(); sout.Slice(32, 32).CopyTo(ccChild.Span); var dataChild = new KzUInt256(); keydata.Span.CopyTo(dataChild.Span); var ok = secp256k1.PrivKeyTweakAdd(dataChild.Span, sout.Slice(0, 32)); if (!ok) { goto fail; } var keyChild = new KzPrivKey(dataChild); return(ok, keyChild, ccChild); fail: return(false, null, KzUInt256.Zero); }