Пример #1
0
        /// <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));
        }
Пример #2
0
        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);
        }
Пример #3
0
        KzUInt256 ComputeHash(KzMerkleTreeNode n)
        {
            // This ToArray call could be eliminated.
            var h = new KzUInt256();

            KzHashes.HASH256(n.LeftRightHashes, h.Span);
            return(h);
        }
Пример #4
0
        /// <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));
        }
Пример #5
0
 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);
 }
Пример #6
0
        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);
        }
Пример #7
0
        /// <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));
        }
Пример #8
0
        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);
        }
Пример #9
0
        /// <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());
        }
Пример #10
0
 public KzUInt160 ToHash160() => KzHashes.HASH160(ReadOnlySpan);
Пример #11
0
        static KzUInt256 GetMessageHash(ReadOnlySpan <byte> message)
        {
            var messagehash = KzHashes.SHA256(message).ToHex();

            return(new KzWriterHash().Add(_messageMagic).Add(messagehash).GetHashFinal());
        }
Пример #12
0
 /// <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));
 }
Пример #13
0
 public static KzExtPrivKey GetMasterPrivKey(string seed, string seedExtension = null) =>
 KzExtPrivKey.Master(KzHashes.pbkdf2_hmac_sha512(seed.UTF8ToBytes(), $"electrum{seedExtension}".UTF8ToBytes(), 2048).Span);
Пример #14
0
        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));
        }
Пример #15
0
 public static byte[] GenerateIV(ReadOnlySpan <byte> key, ReadOnlySpan <byte> data, int length = 16)
 => KzHashes.HMACSHA256(key, data).ReadOnlySpan.Slice(0, length).ToArray();