/// <summary> /// Sets Bip32 private key. /// Uses a single invocation of HMACSHA512 to generate 512 bits of entropy with which to set master private key and chaincode. /// </summary> /// <param name="hmacData">Sequence of bytes passed as hmacData to HMACSHA512 along with byte encoding of hmacKey.</param> /// <param name="required">if not null, each key path will be verified as valid on the generated key or returns null.</param> /// <param name="hmacKey">Default is current global Kz.MasterBip32Key which may default to "Bitcoin seed".</param> /// <returns>Returns this key unless required key paths aren't valid for generated key.</returns> public KzExtPrivKey SetMasterBip32(ReadOnlySpan <byte> hmacData, IEnumerable <KzKeyPath> required = null, string hmacKey = null) { hmacKey = hmacKey ?? Kz.MasterBip32Key; var vout = KzHashes.HMACSHA512(hmacKey.UTF8NFKDToBytes(), hmacData); return(SetMaster(vout, required)); }
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); }
KzUInt256 ComputeHash(KzMerkleTreeNode n) { // This ToArray call could be eliminated. var h = new KzUInt256(); KzHashes.HASH256(n.LeftRightHashes, h.Span); return(h); }
/// <summary> /// Appends first 4 bytes of double SHA256 hash to bytes before standard Base58 encoding. /// </summary> /// <param name="bytes"></param> /// <returns></returns> public override string Encode(ReadOnlySpan <byte> bytes) { var checksum = KzHashes.HASH256(bytes); var buf = new byte[bytes.Length + 4]; bytes.CopyTo(buf); checksum.Span.Slice(0, 4).CopyTo(buf.AsSpan().Slice(bytes.Length)); return(KzEncoders.B58.Encode(buf)); }
public override (bool ok, byte[] bytes) TryDecode(string encoded) { var(ok, bytes) = KzEncoders.B58.TryDecode(encoded); if (ok) { var span = bytes.AsSpan(); var checksum = span.Slice(span.Length - 4); bytes = span.Slice(0, span.Length - 4).ToArray(); var hash = KzHashes.HASH256(bytes); ok = checksum.SequenceEqual(hash.Span.Slice(0, 4)); } return(ok, bytes); }
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); }
/// <summary> /// Verify thoroughly whether a private key and a public key match. /// This is done using a different mechanism than just regenerating it. /// </summary> /// <param name="pubKey"></param> /// <returns></returns> public bool VerifyPubKey(KzPubKey pubkey) { if (pubkey.IsCompressed != fCompressed) { return(false); } var rnd = KzRandom.GetStrongRandBytes(8).ToArray(); var str = "Bitcoin key verification\n"; var hash = KzHashes.HASH256(Encoding.ASCII.GetBytes(str).Concat(rnd).ToArray()); var(ok, sig) = Sign(hash); if (!ok) { return(false); } return(pubkey.Verify(hash, sig)); }
bool Verify() { var s = _Static; var message = $"{s.prevMinerId}{s.minerId}{s.vctx.txid}"; var verifyHash = KzHashes.SHA256(message.UTF8ToBytes()); var verifySignature = s.prevMinerIdSig.HexToBytes(); PrevPubKeyBytes = s.prevMinerId.HexToBytes(); PrevPubKey = new KzPubKey(PrevPubKeyBytes); var verified = PrevPubKey.IsValid && PrevPubKey.Verify(verifyHash, verifySignature); if (verified) { PubKeyBytes = s.minerId.HexToBytes(); PubKey = new KzPubKey(PubKeyBytes); verified = PubKey.IsValid; } return(verified); }
/// <summary> /// The checksum is a substring of the binary representation of the SHA256 hash of entropy. /// For every four bytes of entropy, one additional bit of the hash is used. /// </summary> /// <param name="entropy"></param> /// <returns></returns> public static string GetChecksum(ReadOnlySequence <byte> entropy) { var hash = KzHashes.SHA256(entropy); var bits = (int)entropy.Length * 8; var cs = bits / 32; var sb = new StringBuilder(); foreach (var b in hash.Span) { sb.Append(Convert.ToString(b, 2).PadLeft(8, '0')); cs -= 8; if (cs <= 0) { break; } } if (cs < 0) { sb.Length += cs; } return(sb.ToString()); }
public KzUInt160 ToHash160() => KzHashes.HASH160(ReadOnlySpan);
static KzUInt256 GetMessageHash(ReadOnlySpan <byte> message) { var messagehash = KzHashes.SHA256(message).ToHex(); return(new KzWriterHash().Add(_messageMagic).Add(messagehash).GetHashFinal()); }
/// <summary> /// Computes 512 bit Bip39 seed. /// passphrase, password, and passwordPrefix are converted to bytes using UTF8 KD normal form encoding. /// </summary> /// <param name="passphrase">arbitrary passphrase (typically mnemonic words with checksum but not necessarily)</param> /// <param name="password">password and passwordPrefix are combined to generate salt bytes.</param> /// <param name="passwordPrefix">password and passwordPrefix are combined to generate salt bytes. Default is "mnemonic".</param> /// <returns>Computes 512 bit Bip39 seed.</returns> public static KzUInt512 Bip39Seed(string passphrase, string password = null, string passwordPrefix = "mnemonic") { return(KzHashes.pbkdf2_hmac_sha512(passphrase.UTF8NFKDToBytes(), $"{passwordPrefix}{password}".UTF8NFKDToBytes(), 2048)); }
public static KzExtPrivKey GetMasterPrivKey(string seed, string seedExtension = null) => KzExtPrivKey.Master(KzHashes.pbkdf2_hmac_sha512(seed.UTF8ToBytes(), $"electrum{seedExtension}".UTF8ToBytes(), 2048).Span);
public KzExtPrivKey SetMaster(ReadOnlySpan <byte> seed, IEnumerable <KzKeyPath> required = null) { var vout = KzHashes.HMACSHA512(Encoding.ASCII.GetBytes(Kz.SetMasterSeed), seed).ReadOnlySpan; return(SetMaster(vout.Slice(0, 32).ToKzUInt256(), vout.Slice(32, 32).ToKzUInt256(), required)); }
public static byte[] GenerateIV(ReadOnlySpan <byte> key, ReadOnlySpan <byte> data, int length = 16) => KzHashes.HMACSHA256(key, data).ReadOnlySpan.Slice(0, length).ToArray();