示例#1
0
        public void Decrypt()
        {
            try
            {
                if (Constants.IsRc4)
                {
                    Client.Decrypt(m_vData);
                    if (m_vType == 10101)
                    {
                        Client.State = ClientState.Login;
                    }

                    // No need since the decryption occurs on same buffer.
                    //SetData(m_vData);
                }
                else
                {
                    if (m_vType == 10101)
                    {
                        var cipherText = m_vData;
                        Client.CPublicKey = cipherText.Take(32).ToArray();

                        var blake = Blake2B.Create(new Blake2BConfig
                        {
                            OutputSizeInBytes = 24
                        });
                        blake.Init();
                        blake.Update(Client.CPublicKey);
                        blake.Update(Key.Crypto.PublicKey);

                        Client.CRNonce = blake.Finish();

                        cipherText = CustomNaCl.OpenPublicBox(cipherText.Skip(32).ToArray(), Client.CRNonce, Key.Crypto.PrivateKey, Client.CPublicKey);

                        Client.CSharedKey  = Client.CPublicKey;
                        Client.CSessionKey = cipherText.Take(24).ToArray();
                        Client.CSNonce     = cipherText.Skip(24).Take(24).ToArray();
                        Client.State       = ClientState.Login;

                        SetData(cipherText.Skip(48).ToArray());
                    }
                    else
                    {
                        if (m_vType != 10100)
                        {
                            if (Client.State == ClientState.LoginSuccess)
                            {
                                Client.CSNonce.Increment();
                                SetData(CustomNaCl.OpenSecretBox(new byte[16].Concat(m_vData).ToArray(), Client.CSNonce, Client.CSharedKey));
                            }
                        }
                    }
                }
            }
            catch
            {
                Client.State = ClientState.Exception;
                throw;
            }
        }
        public static void crypto_sign_keypair(byte[] pk, int pkoffset, byte[] sk, int skoffset, byte[] seed, int seedoffset)
        {
            GroupElementP3 A;
            int            i;

            Array.Copy(seed, seedoffset, sk, skoffset, 32);

            var blake2bConfig = new Blake2BConfig
            {
                OutputSizeInBytes = 64
            };
            var hasher = Blake2B.Create(blake2bConfig);

            hasher.Update(sk, skoffset, 32);
            byte[] h = hasher.Finish();
            //byte[] h = Sha512.Hash(sk, skoffset, 32);//ToDo: Remove alloc
            ScalarOperations.sc_clamp(h, 0);

            GroupOperations.ge_scalarmult_base(out A, h, 0);
            GroupOperations.ge_p3_tobytes(pk, pkoffset, ref A);

            for (i = 0; i < 32; ++i)
            {
                sk[skoffset + 32 + i] = pk[pkoffset + i];
            }
            CryptoBytes.Wipe(h);
        }
示例#3
0
 public void Decrypt()
 {
     try
     {
         if (m_vType == 10101)
         {
             byte[] cipherText = m_vData;
             Client.CPublicKey = cipherText.Take(32).ToArray();
             Hasher b = Blake2B.Create(new Blake2BConfig
             {
                 OutputSizeInBytes = 24
             });
             b.Init();
             b.Update(Client.CPublicKey);
             b.Update(Key.Crypto.PublicKey);
             Client.CRNonce     = b.Finish();
             cipherText         = CustomNaCl.OpenPublicBox(cipherText.Skip(32).ToArray(), Client.CRNonce, Key.Crypto.PrivateKey, Client.CPublicKey);
             Client.CSharedKey  = Client.CPublicKey;
             Client.CSessionKey = cipherText.Take(24).ToArray();
             Client.CSNonce     = cipherText.Skip(24).Take(24).ToArray();
             Client.CState      = 1;
             SetData(cipherText.Skip(48).ToArray());
         }
         else if (m_vType != 10100)
         {
             Client.CSNonce.Increment();
             SetData(CustomNaCl.OpenSecretBox(new byte[16].Concat(m_vData).ToArray(), Client.CSNonce, Client.CSharedKey));
         }
     }
     catch (Exception ex)
     {
         Client.CState = 0;
     }
 }
        public string EncodeAccount(UInt256 account)
        {
            var hasher = Blake2B.Create(new Blake2BConfig
            {
                OutputSizeInBytes = 5
            });

            var bytes = account.ToByteArray().Reverse().ToArray();

            hasher.Update(bytes);
            byte[] checkBytes = hasher.Finish();
            Array.Resize(ref checkBytes, 8);
            UInt64     check  = BitConverter.ToUInt64(checkBytes, 0);
            BigInteger number = Number(bytes);

            number <<= 40;
            number  |= new BigInteger(check);
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < 60; i++)
            {
                var r = number.ToByteArray()[0] & 0x1f;
                number >>= 5;
                sb.Append(AccountLookup[r]);
            }
            sb.Append("_brx");
            var addrReverse = sb.ToString();
            var arr         = addrReverse.ToCharArray();

            Array.Reverse(arr);
            return(new string(arr));
        }
示例#5
0
 public void Encrypt(byte[] plainText)
 {
     try
     {
         if (GetMessageType() == 20104 || GetMessageType() == 20103)
         {
             Hasher b = Blake2B.Create(new Blake2BConfig
             {
                 OutputSizeInBytes = 24
             });
             b.Init();
             b.Update(Client.CSNonce);
             b.Update(Client.CPublicKey);
             b.Update(Key.Crypto.PublicKey);
             SetData(CustomNaCl.CreatePublicBox(Client.CRNonce.Concat(Client.CSharedKey).Concat(plainText).ToArray(), b.Finish(), Key.Crypto.PrivateKey, Client.CPublicKey));
             if (GetMessageType() == 20104)
             {
                 Client.CState = 2;
             }
         }
         else
         {
             Client.CRNonce.Increment();
             SetData(CustomNaCl.CreateSecretBox(plainText, Client.CRNonce, Client.CSharedKey).Skip(16).ToArray());
         }
     }
     catch (Exception)
     {
         Client.CState = 0;
     }
 }
示例#6
0
        public bool ValidateAddress(string address)
        {
            if (address.Length != 64 && !address.StartsWith("xrb_"))
            {
                return(false);
            }
            var pk32 = address.Substring(4, 52);
            var pk   = Base32withPadding.Decode(pk32, _base32Alphabet, 4);

            var checksum        = address.Substring(56);
            var checksumDecoded = Base32withPadding.Decode(checksum, _base32Alphabet, 0);

            checksumDecoded = checksumDecoded.Reverse().ToArray();

            var blake2bConfig = new Blake2BConfig
            {
                OutputSizeInBytes = 5
            };
            var hasher = Blake2B.Create(blake2bConfig);

            hasher.Update(pk);
            var pkChecksum = hasher.Finish();

            return(pkChecksum.SequenceEqual(checksumDecoded));
        }
示例#7
0
        public static string HashStateBlock(string accountAddress, string previousHash, string balance, string representativeAccount, string link)
        {
            var representativePublicKey = AddressToPublicKey(representativeAccount);
            var accountPublicKey        = AddressToPublicKey(accountAddress);
            var previousBytes           = HexStringToByteArray(previousHash);

            var balanceHex = BigInteger.Parse(balance).ToString("X");

            if (balanceHex.Length % 2 == 1)
            {
                balanceHex = "0" + balanceHex;
            }
            byte[] balanceBytes = HexStringToByteArray(balanceHex.PadLeft(32, '0'));
            var    linkBytes    = HexStringToByteArray(link);
            var    preamble     = HexStringToByteArray("0000000000000000000000000000000000000000000000000000000000000006");

            var blake = Blake2B.Create(new Blake2BConfig()
            {
                OutputSizeInBytes = 32
            });

            blake.Init();
            blake.Update(preamble);
            blake.Update(accountPublicKey);
            blake.Update(previousBytes);
            blake.Update(representativePublicKey);
            blake.Update(balanceBytes);
            blake.Update(linkBytes);

            var hashBytes = blake.Finish();

            return(ByteArrayToHex(hashBytes));
        }
        public void Hash(Blake2BConfig config, byte[] message)
        {
            var hasher = Blake2B.Create(new Blake2BConfig()
            {
                OutputSizeInBytes = 64
            });

            hasher.Init();
            hasher.Update(Previous.ToByteArray());
            hasher.Update(Source.ToByteArray());
        }
示例#9
0
        public static byte[] Hash(byte[] data, int size)
        {
            var hasher = Blake2B.Create(new Blake2BConfig
            {
                OutputSizeInBytes = size,
            });

            hasher.Init();
            hasher.Update(data);
            return(hasher.Finish());
        }
示例#10
0
        public void Hash(Blake2BConfig config, byte[] message)
        {
            var hasher = Blake2B.Create(new Blake2BConfig()
            {
                OutputSizeInBytes = 64
            });

            hasher.Init();
            hasher.Update(Source.ToByteArray());
            hasher.Update(Representative.ToByteArray());
            hasher.Update(Account.ToByteArray());
        }
示例#11
0
        // Original crypto_sign_open, for reference only

        /*public static int crypto_sign_open(
         * byte[] m, out int mlen,
         * byte[] sm, int smlen,
         * byte[] pk)
         * {
         *  byte[] h = new byte[64];
         *  byte[] checkr = new byte[32];
         *  GroupElementP3 A;
         *  GroupElementP2 R;
         *  int i;
         *
         *  mlen = -1;
         *  if (smlen < 64) return -1;
         *  if ((sm[63] & 224) != 0) return -1;
         *  if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, 0) != 0) return -1;
         *
         *  for (i = 0; i < smlen; ++i) m[i] = sm[i];
         *  for (i = 0; i < 32; ++i) m[32 + i] = pk[i];
         *  Sha512BclWrapper.crypto_hash_sha512(h, m, 0, smlen);
         *  ScalarOperations.sc_reduce(h);
         *
         *  var sm32 = new byte[32];
         *  Array.Copy(sm, 32, sm32, 0, 32);
         *  GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32);
         *  GroupOperations.ge_tobytes(checkr, 0, ref R);
         *  if (Helpers.crypto_verify_32(checkr, sm) != 0)
         *  {
         *      for (i = 0; i < smlen; ++i)
         *          m[i] = 0;
         *      return -1;
         *  }
         *
         *  for (i = 0; i < smlen - 64; ++i)
         *      m[i] = sm[64 + i];
         *  for (i = smlen - 64; i < smlen; ++i)
         *      m[i] = 0;
         *  mlen = smlen - 64;
         *  return 0;
         * }*/

        public static bool crypto_sign_verify(
            byte[] sig, int sigoffset,
            byte[] m, int moffset, int mlen,
            byte[] pk, int pkoffset)
        {
            byte[]         h;
            byte[]         checkr = new byte[32];
            GroupElementP3 A;
            GroupElementP2 R;

            if ((sig[sigoffset + 63] & 224) != 0)
            {
                return(false);
            }
            if (GroupOperations.ge_frombytes_negate_vartime(out A, pk, pkoffset) != 0)
            {
                return(false);
            }

            var blake2bConfig = new Blake2BConfig
            {
                OutputSizeInBytes = 64
            };
            var hasher = Blake2B.Create(blake2bConfig);

            hasher.Update(sig, sigoffset, 32);
            hasher.Update(pk, pkoffset, 32);
            hasher.Update(m, moffset, mlen);
            h = hasher.Finish();

            /*
             * var hasher = new Sha512();
             * hasher.Update(sig, sigoffset, 32);
             * hasher.Update(pk, pkoffset, 32);
             * hasher.Update(m, moffset, mlen);
             * h = hasher.Finish();
             */

            ScalarOperations.sc_reduce(h);

            var sm32 = new byte[32];//todo: remove allocation

            Array.Copy(sig, sigoffset + 32, sm32, 0, 32);
            GroupOperations.ge_double_scalarmult_vartime(out R, h, ref A, sm32);
            GroupOperations.ge_tobytes(checkr, 0, ref R);
            var result = CryptoBytes.ConstantTimeEquals(checkr, 0, sig, sigoffset, 32);

            CryptoBytes.Wipe(h);
            CryptoBytes.Wipe(checkr);
            return(result);
        }
示例#12
0
        byte[] GenerateRaiAddressSeed(int index)
        {
            var blake2bConfig = new Blake2BConfig
            {
                OutputSizeInBytes = 32
            };
            var hasher = Blake2B.Create(blake2bConfig);

            hasher.Update(Seed);
            var indexBytes = BitConverter.GetBytes(index).Reverse().ToArray();

            hasher.Update(indexBytes);
            return(hasher.Finish());
        }
示例#13
0
        public static byte[] HashAll(params byte[][] data)
        {
            var hasher = Blake2B.Create(new Blake2BConfig()
            {
                OutputSizeInBytes = 32
            }, SecureArray.DefaultCall);

            foreach (var d in data)
            {
                hasher.Update(d);
            }

            var hashAll = hasher.Finish();

            return(hashAll);
        }
        public static void KeyExchange(ArraySegment <byte> sharedKey, ArraySegment <byte> publicKey, ArraySegment <byte> privateKey)
        {
            if (sharedKey.Array == null)
            {
                throw new ArgumentNullException("sharedKey.Array");
            }
            if (publicKey.Array == null)
            {
                throw new ArgumentNullException("publicKey.Array");
            }
            if (privateKey.Array == null)
            {
                throw new ArgumentNullException("privateKey");
            }
            if (sharedKey.Count != 32)
            {
                throw new ArgumentException("sharedKey.Count != 32");
            }
            if (publicKey.Count != 32)
            {
                throw new ArgumentException("publicKey.Count != 32");
            }
            if (privateKey.Count != 64)
            {
                throw new ArgumentException("privateKey.Count != 64");
            }

            FieldElement montgomeryX, edwardsY, edwardsZ, sharedMontgomeryX;

            FieldOperations.fe_frombytes(out edwardsY, publicKey.Array, publicKey.Offset);
            FieldOperations.fe_1(out edwardsZ);
            MontgomeryCurve25519.EdwardsToMontgomeryX(out montgomeryX, ref edwardsY, ref edwardsZ);
            var blake2bConfig = new Blake2BConfig
            {
                OutputSizeInBytes = 64
            };
            var hasher = Blake2B.Create(blake2bConfig);

            hasher.Update(privateKey.Array, privateKey.Offset, 32);
            byte[] h = hasher.Finish();
            //byte[] h = Sha512.Hash(privateKey.Array, privateKey.Offset, 32);//ToDo: Remove alloc
            ScalarOperations.sc_clamp(h, 0);
            MontgomeryOperations.scalarmult(out sharedMontgomeryX, h, 0, ref montgomeryX);
            CryptoBytes.Wipe(h);
            FieldOperations.fe_tobytes(sharedKey.Array, sharedKey.Offset, ref sharedMontgomeryX);
            MontgomeryCurve25519.KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset);
        }
        public UInt256 DecodeAccount(string account)
        {
            if (account.Length != 64)
            {
                throw new InvalidDataException("length should be 64");
            }

            if (!account.StartsWith("xrb_"))
            {
                throw new InvalidDataException("invalid account format");
            }

            BigInteger number = new BigInteger();

            for (int i = 4; i < account.Length; i++)
            {
                sbyte byteResult = DecodeChar(account[i]);
                if (byteResult != '~')
                {
                    number <<= 5;
                    number  += byteResult;
                }
            }

            UInt256 accountUInt256 = new UInt256(number >> 40);
            var     accountBytes   = accountUInt256.ToByteArray().Reverse().ToArray();
            UInt64  check          = BitConverter.ToUInt64(number.ToByteArray(), 0);

            check &= 0xffffffffff;
            var hasher = Blake2B.Create(new Blake2BConfig {
                OutputSizeInBytes = 5
            });

            hasher.Update(accountBytes);
            var final = hasher.Finish();

            Array.Resize(ref final, 8);
            UInt64 validation = BitConverter.ToUInt64(final, 0);

            if (check != validation)
            {
                throw new InvalidDataException();
            }

            return(accountUInt256);
        }
示例#16
0
        public static string PublicKeyToAddress(byte[] publicKey)
        {
            var address = "nano_" + NanoEncode(publicKey);

            var blake = Blake2B.Create(new Blake2BConfig()
            {
                OutputSizeInBytes = 5
            });

            blake.Init();
            blake.Update(publicKey);
            var checksumBytes = blake.Finish();

            address += NanoEncode(checksumBytes.Reverse().ToArray(), false);

            return(address);
        }
        /// <summary>
        /// Does a Blake2 hash with the ability to truncate or extend the hash to any length.
        /// </summary>
        /// <param name="hash">
        /// The buffer to fill with the hash.
        /// </param>
        /// <param name="inputBuffer">
        /// What to hash.
        /// </param>
        /// <param name="secureArrayCall">
        /// The methods that get called to secure arrays. A null value defaults to <see cref="SecureArray"/>.<see cref="SecureArray.DefaultCall"/>.
        /// </param>
        private static void Blake2BLong(byte[] hash, byte[] inputBuffer, SecureArrayCall secureArrayCall)
        {
            var outputLengthBytes = new byte[4];

            using var intermediateHash = SecureArray <byte> .Best(Blake2B.OutputLength, secureArrayCall);

            var config = new Blake2BConfig
            {
                Result64ByteBuffer = intermediateHash.Buffer,
                OutputSizeInBytes  = hash.Length > 64 ? 64 : hash.Length,
            };

            Store32(outputLengthBytes, hash.Length);
            using (var blakeHash = Blake2B.Create(config, secureArrayCall))
            {
                blakeHash.Update(outputLengthBytes);
                blakeHash.Update(inputBuffer);
                blakeHash.Finish();
            }

            if (hash.Length <= intermediateHash.Buffer.Length)
            {
                Array.Copy(intermediateHash.Buffer, hash, hash.Length);
                return;
            }

            const int b2B2 = Blake2B.OutputLength / 2;

            Array.Copy(intermediateHash.Buffer, hash, b2B2);
            int pos           = b2B2;
            int lastHashIndex = hash.Length - Blake2B.OutputLength;
            var toHash        = new byte[Blake2B.OutputLength];

            while (pos < lastHashIndex)
            {
                Array.Copy(intermediateHash.Buffer, toHash, intermediateHash.Buffer.Length);
                Blake2B.ComputeHash(toHash, config, secureArrayCall);
                Array.Copy(intermediateHash.Buffer, 0, hash, pos, b2B2);
                pos += b2B2;
            }

            Array.Copy(intermediateHash.Buffer, toHash, intermediateHash.Buffer.Length);
            Blake2B.ComputeHash(toHash, config, secureArrayCall);
            Array.Copy(intermediateHash.Buffer, 0, hash, pos, hash.Length - pos);
        }
示例#18
0
        public void Encrypt(byte[] plainText)
        {
            try
            {
                if (Constants.IsRc4)
                {
                    Client.Encrypt(plainText);
                    if (m_vType == 20104)
                    {
                        Client.State = Client.ClientState.LoginSuccess;
                    }

                    SetData(plainText);
                }
                else
                {
                    if (m_vType == 20104 || m_vType == 20103)
                    {
                        Hasher b = Blake2B.Create(new Blake2BConfig
                        {
                            OutputSizeInBytes = 24
                        });
                        b.Init();
                        b.Update(Client.CSNonce);
                        b.Update(Client.CPublicKey);
                        b.Update(Key.Crypto.PublicKey);
                        SetData(CustomNaCl.CreatePublicBox(Client.CRNonce.Concat(Client.CSharedKey).Concat(plainText).ToArray(), b.Finish(), Key.Crypto.PrivateKey, Client.CPublicKey));
                        if (m_vType == 20104)
                        {
                            Client.State = Client.ClientState.LoginSuccess;
                        }
                    }
                    else
                    {
                        Client.CRNonce.Increment();
                        SetData(CustomNaCl.CreateSecretBox(plainText, Client.CRNonce, Client.CSharedKey).Skip(16).ToArray());
                    }
                }
            }
            catch (Exception)
            {
                Client.State = ClientState.Exception;
            }
        }
示例#19
0
        public string PublicAddress(int index = 0)
        {
            var addressSeed = GenerateRaiAddressSeed(index);

            var pk   = Ed25519.PublicKeyFromSeed(addressSeed);
            var pk32 = Base32withPadding.Encode(pk, _base32Alphabet, 260);

            var blake2bConfig = new Blake2BConfig
            {
                OutputSizeInBytes = 5
            };
            var hasher = Blake2B.Create(blake2bConfig);

            hasher.Update(pk);
            var checksum   = hasher.Finish().Reverse().ToArray();
            var checksum32 = Base32withPadding.Encode(checksum, _base32Alphabet, 40);

            return($"xrb_{pk32}{checksum32}");
        }
示例#20
0
        /*public static void crypto_sign(
         * byte[] sm, out int smlen,
         * byte[] m, int mlen,
         * byte[] sk
         * )
         * {
         *      byte[] az = new byte[64];
         *      byte[] r = new byte[64];
         *      byte[] hram = new byte[64];
         *      GroupElementP3 R;
         *      int i;
         *
         *      Helpers.crypto_hash_sha512(az, sk, 0, 32);
         *      az[0] &= 248;
         *      az[31] &= 63;
         *      az[31] |= 64;
         *
         *      smlen = mlen + 64;
         *      for (i = 0; i < mlen; ++i) sm[64 + i] = m[i];
         *      for (i = 0; i < 32; ++i) sm[32 + i] = az[32 + i];
         *      Helpers.crypto_hash_sha512(r, sm, 32, mlen + 32);
         *      for (i = 0; i < 32; ++i) sm[32 + i] = sk[32 + i];
         *
         *      ScalarOperations.sc_reduce(r);
         *      GroupOperations.ge_scalarmult_base(out R, r, 0);
         *      GroupOperations.ge_p3_tobytes(sm, 0, ref R);
         *
         *      Helpers.crypto_hash_sha512(hram, sm, 0, mlen + 64);
         *      ScalarOperations.sc_reduce(hram);
         *      var sm32 = new byte[32];
         *      Array.Copy(sm, 32, sm32, 0, 32);
         *      ScalarOperations.sc_muladd(sm32, hram, az, r);
         *      Array.Copy(sm32, 0, sm, 32, 32);
         * }*/

        public static void crypto_sign2(
            byte[] sig, int sigoffset,
            byte[] m, int moffset, int mlen,
            byte[] sk, int skoffset)
        {
            byte[]         az;
            byte[]         r;
            byte[]         hram;
            GroupElementP3 R;
            var            blake2bConfig = new Blake2BConfig
            {
                OutputSizeInBytes = 64
            };
            var hasher = Blake2B.Create(blake2bConfig);
            //var hasher = new Sha512();
            {
                hasher.Update(sk, skoffset, 32);
                az = hasher.Finish();
                ScalarOperations.sc_clamp(az, 0);

                hasher.Init();
                hasher.Update(az, 32, 32);
                hasher.Update(m, moffset, mlen);
                r = hasher.Finish();

                ScalarOperations.sc_reduce(r);
                GroupOperations.ge_scalarmult_base(out R, r, 0);
                GroupOperations.ge_p3_tobytes(sig, sigoffset, ref R);

                hasher.Init();
                hasher.Update(sig, sigoffset, 32);
                hasher.Update(sk, skoffset + 32, 32);
                hasher.Update(m, moffset, mlen);
                hram = hasher.Finish();

                ScalarOperations.sc_reduce(hram);
                var s = new byte[32];                //todo: remove allocation
                Array.Copy(sig, sigoffset + 32, s, 0, 32);
                ScalarOperations.sc_muladd(s, hram, az, r);
                Array.Copy(s, 0, sig, sigoffset + 32, 32);
                CryptoBytes.Wipe(s);
            }
        }
示例#21
0
        public static bool AddressIsValid(string address)
        {
            byte[] pubkeyBytes = AddressToPublicKey(address);
            if (pubkeyBytes == null)
            {
                return(false);
            }

            var blake = Blake2B.Create(new Blake2BConfig()
            {
                OutputSizeInBytes = 5
            });

            blake.Init();
            blake.Update(pubkeyBytes);
            var hashBytes = blake.Finish();

            // Checksum is last 8 characters, compare
            var checksum = address.Substring(address.Length - 8, 8);

            var binaryString = "";

            for (int i = 0; i < checksum.Length; i++)
            {
                // Decode each character into string representation of it's binary parts
                binaryString += nano_addressEncoding[checksum[i]];
            }

            // Convert to bytes
            var pk = new byte[5];

            for (int i = 0; i < 5; i++)
            {
                // for each byte, read the bits from the binary string
                var b = Convert.ToByte(binaryString.Substring(i * 8, 8), 2);
                pk[i] = b;
            }

            return(hashBytes.SequenceEqual(pk.Reverse()));
        }
        public void Splits()
        {
            var hasher = Blake2B.Create();

            for (int len = 0; len <= 256; len++)
            {
                hasher.Init();
                hasher.Update(input, 0, len);
                string hash0 = BitConverter.ToString(hasher.Finish());

                for (int split1 = 0; split1 <= len; split1++)
                {
                    for (int split2 = split1; split2 <= len; split2++)
                    {
                        hasher.Init();
                        hasher.Update(input, 0, split1);
                        hasher.Update(input, split1, split2 - split1);
                        hasher.Update(input, split2, len - split2);
                        string hash1 = BitConverter.ToString(hasher.Finish());
                        Assert.AreEqual(hash0, hash1);
                    }
                }
            }
        }
        private SecureArray <byte> InitialHash()
        {
            var ret = BestSecureArray <byte>(Blake2B.OutputLength);

            using (var blakeHash =
                       Blake2B.Create(
                           new Blake2BConfig
            {
                OutputSizeInBytes = PrehashDigestLength,
                Result64ByteBuffer = ret.Buffer
            }))
            {
                var value = new byte[4];
                Store32(value, this.config.Lanes);
                blakeHash.Update(value);
                Store32(value, this.config.HashLength);
                blakeHash.Update(value);
                Store32(value, this.config.MemoryCost);
                blakeHash.Update(value);
                Store32(value, this.config.TimeCost);
                blakeHash.Update(value);
                Store32(value, (uint)this.config.Version);
                blakeHash.Update(value);
                Store32(value, (uint)this.config.Type);
                blakeHash.Update(value);
                Store32(value, this.config.Password?.Length ?? 0);
                blakeHash.Update(value);
                if (this.config.Password != null)
                {
                    blakeHash.Update(this.config.Password);
                    if (this.config.ClearPassword)
                    {
                        SecureArray.Zero(this.config.Password);
                    }
                }

                Store32(value, this.config.Salt?.Length ?? 0);
                blakeHash.Update(value);
                if (this.config.Salt != null)
                {
                    blakeHash.Update(this.config.Salt);
                }

                Store32(value, this.config.Secret?.Length ?? 0);
                blakeHash.Update(value);
                if (this.config.Secret != null)
                {
                    blakeHash.Update(this.config.Secret);
                    if (this.config.ClearSecret)
                    {
                        SecureArray.Zero(this.config.Secret);
                    }
                }

                Store32(value, this.config.AssociatedData?.Length ?? 0);
                blakeHash.Update(value);
                if (this.config.AssociatedData != null)
                {
                    blakeHash.Update(this.config.AssociatedData);
                }

                blakeHash.Finish();
            }

            return(ret);
        }