コード例 #1
0
        public unsafe void CompressHmacBlock_0x5c_Bitcoinseed_Test()
        {
            int extraLen = 5;

            byte[] extraEndBa = GetRandomBytes(extraLen);
            int    dataLen    = 128 + extraLen;

            byte[] data = new byte[dataLen];
            ((Span <byte>)data).Fill(0x5c);
            Buffer.BlockCopy(extraEndBa, 0, data, 128, extraLen);
            // XOR "Bitcoin seed" with initial bytes
            byte[] xor = Encoding.UTF8.GetBytes("Bitcoin seed");
            for (int i = 0; i < xor.Length; i++)
            {
                data[i] ^= xor[i];
            }

            byte[] expected = ComputeSingleSha(data);

            using Sha512Fo sha = new Sha512Fo();
            fixed(byte *dPt = &data[0])
            fixed(ulong *hPt = &sha.hashState[0], wPt = &sha.w[0])
            {
                sha.Init(hPt);
                sha.CompressHmacBlock_0x5c_Bitcoinseed(hPt, wPt);

                sha.CompressData(dPt + 128, extraLen, dataLen, hPt, wPt);
                byte[] actual = sha.GetBytes(hPt);

                Assert.Equal(expected, actual);
            }
        }
コード例 #2
0
        public void ComputeHash_AMillionATest()
        {
            byte[] actualHash   = Sha512Fo.ComputeHash(HashTestCaseHelper.GetAMillionA());
            byte[] expectedHash = Helper.HexToBytes("e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");

            Assert.Equal(expectedHash, actualHash);
        }
コード例 #3
0
        public unsafe void Compare_Sha512HashStateTest()
        {
            PrvToPubComparer comp = new();

            byte[] data = new byte[] { 1, 2, 3 };
            ulong *hPt  = stackalloc ulong[Sha512Fo.UBufferSize];
            ulong *wPt  = hPt + Sha512Fo.HashStateSize;

            fixed(byte *dPt = data)
            {
                // Get hashstate ready first
                Sha512Fo.CompressData(dPt, data.Length, data.Length, hPt, wPt);

                Scalar key = new(hPt, out int overflow);

                Assert.Equal(0, overflow);
                Calc   calc   = new();
                string pubHex = calc.GetPubkey(key, true).ToArray().ToBase16();
                bool   b      = comp.Init(pubHex);

                Assert.True(b);

                bool actual = comp.Compare(hPt);

                Assert.True(actual);
            }
        }
コード例 #4
0
        public unsafe void CompressHmacBlock_0x36_Bitcoinseed_Test()
        {
            int extraLen = 5;

            byte[] extraEndBa = GetRandomBytes(extraLen);
            int    dataLen    = 128 + extraLen;

            byte[] data = new byte[dataLen];
            ((Span <byte>)data).Fill(0x36);
            Buffer.BlockCopy(extraEndBa, 0, data, 128, extraLen);
            // XOR "Bitcoin seed" with initial bytes
            byte[] xor = Encoding.UTF8.GetBytes("Bitcoin seed");
            for (int i = 0; i < xor.Length; i++)
            {
                data[i] ^= xor[i];
            }

            byte[] expected = ComputeSingleSha(data);

            ulong *hPt = stackalloc ulong[Sha512Fo.UBufferSize];
            ulong *wPt = hPt + Sha512Fo.HashStateSize;

            fixed(byte *dPt = &data[0])
            {
                Sha512Fo.Init(hPt);
                Sha512Fo.CompressHmacBlock_0x36_Bitcoinseed(hPt, wPt);

                Sha512Fo.CompressData(dPt + 128, extraLen, dataLen, hPt, wPt);
                byte[] actual = Sha512Fo.GetBytes(hPt);

                Assert.Equal(expected, actual);
            }
        }
コード例 #5
0
        private unsafe void Loop12()
        {
            if (missCount > 1)
            {
                report.AddMessageSafe("Running in parallel.");
                report.SetProgressStep(2048);
                int firstIndex = missingIndexes[0];
                Parallel.For(0, 2048, (firstItem, state) => Loop12(firstItem, firstIndex, state));
            }
            else
            {
                // We can't call the same parallel method due to usage of LoopState so we at least optimize this by
                // avoiding the inner loop over the IEnumerable
                using Sha512Fo sha512 = new Sha512Fo();
                ulong[] ipad = new ulong[80];
                ulong[] opad = new ulong[80];

                using Sha256Fo sha256 = new Sha256Fo();

                int misIndex = missingIndexes[0];

                fixed(ulong *iPt = ipad, oPt = opad)
                fixed(uint *wPt  = &sha256.w[0], hPt = &sha256.hashState[0], wrd = &wordIndexes[0])
                fixed(byte *mnPt = &mnBytes[0])
                {
                    wPt[4]  = 0b10000000_00000000_00000000_00000000U;
                    wPt[15] = 128;

                    for (uint item = 0; item < 2048; item++)
                    {
                        wrd[misIndex] = item;

                        wPt[0] = wrd[0] << 21 | wrd[1] << 10 | wrd[2] >> 1;
                        wPt[1] = wrd[2] << 31 | wrd[3] << 20 | wrd[4] << 9 | wrd[5] >> 2;
                        wPt[2] = wrd[5] << 30 | wrd[6] << 19 | wrd[7] << 8 | wrd[8] >> 3;
                        wPt[3] = wrd[8] << 29 | wrd[9] << 18 | wrd[10] << 7 | wrd[11] >> 4;

                        sha256.Init(hPt);
                        sha256.Compress16(hPt, wPt);

                        if ((wrd[11] & 0b1111) == hPt[0] >> 28)
                        {
                            int mnLen = 0;
                            for (int i = 0; i < 12; i++)
                            {
                                var temp = allWordsBytes[wrd[i]];
                                Buffer.BlockCopy(temp, 0, mnBytes, mnLen, temp.Length);
                                mnLen += temp.Length;
                            }

                            if (SetBip32(sha512, mnPt, --mnLen, iPt, oPt))
                            {
                                SetResultParallel(mnPt, mnLen);
                                break;
                            }
                        }
                    }
                }
            }
        }
コード例 #6
0
        public unsafe void GetSecond32BytesTest()
        {
            byte[]  data      = GetRandomBytes(64);
            byte[]  expected  = ((Span <byte>)data).Slice(32, 32).ToArray();
            ulong[] hashState = new ulong[8];
            for (int i = 0, j = 0; i < 8; i++, j += 8)
            {
                hashState[i] =
                    ((ulong)data[j] << 56) |
                    ((ulong)data[j + 1] << 48) |
                    ((ulong)data[j + 2] << 40) |
                    ((ulong)data[j + 3] << 32) |
                    ((ulong)data[j + 4] << 24) |
                    ((ulong)data[j + 5] << 16) |
                    ((ulong)data[j + 6] << 8) |
                    data[j + 7];
            }

            using Sha512Fo sha = new Sha512Fo();
            fixed(ulong *hPt = &hashState[0])
            {
                byte[] actual = sha.GetSecond32Bytes(hPt);
                Assert.Equal(expected, actual);
            }
        }
コード例 #7
0
        public unsafe void CompressSingleBlockTest(int len)
        {
            byte[] data   = GetRandomBytes(len);
            byte[] padded = new byte[Sha512Fo.BlockByteSize];
            Buffer.BlockCopy(data, 0, padded, 0, data.Length);
            padded[len] = 0x80;
            padded[127] = (byte)(len << 3);
            padded[126] = (byte)(len >> 5);
            padded[125] = (byte)(len >> 13);
            padded[124] = (byte)(len >> 21);
            padded[123] = (byte)(len >> 29);

            ulong *hPt1 = stackalloc ulong[Sha512Fo.UBufferSize];
            ulong *wPt1 = hPt1 + Sha512Fo.HashStateSize;

            ulong *hPt2 = stackalloc ulong[Sha512Fo.UBufferSize];
            ulong *wPt2 = hPt2 + Sha512Fo.HashStateSize;

            fixed(byte *dPt1 = &data[0], dPt2 = &padded[0])
            {
                Sha512Fo.Init(hPt1);
                Sha512Fo.CompressData(dPt1, data.Length, data.Length, hPt1, wPt1);
                byte[] expected = Sha512Fo.GetBytes(hPt1);

                Sha512Fo.Init(hPt2);
                Sha512Fo.CompressSingleBlock(dPt2, hPt2, wPt2);
                byte[] actual = Sha512Fo.GetBytes(hPt2);

                Assert.Equal(expected, actual);
            }
        }
コード例 #8
0
        public void ComputeHash_NistMonteCarloTest()
        {
            byte[]  seed  = Helper.HexToBytes("5c337de5caf35d18ed90b5cddfce001ca1b8ee8602f367e7c24ccca6f893802fb1aca7a3dae32dcd60800a59959bc540d63237876b799229ae71a2526fbc52cd");
            JObject jObjs = Helper.ReadResources <JObject>("Sha512NistTestData");
            int     size  = 64;

            byte[] toHash = new byte[3 * size];

            byte[] M0 = seed;
            byte[] M1 = seed;
            byte[] M2 = seed;

            using Sha512Fo sha = new Sha512Fo();

            foreach (var item in jObjs["MonteCarlo"])
            {
                byte[] expected = Helper.HexToBytes(item.ToString());
                for (int i = 0; i < 1000; i++)
                {
                    Buffer.BlockCopy(M0, 0, toHash, 0, size);
                    Buffer.BlockCopy(M1, 0, toHash, size, size);
                    Buffer.BlockCopy(M2, 0, toHash, size * 2, size);

                    M0 = M1;
                    M1 = M2;
                    M2 = sha.ComputeHash(toHash);
                }
                M0 = M2;
                M1 = M2;

                Assert.Equal(expected, M2);
            }
        }
コード例 #9
0
        private unsafe bool Loop21()
        {
            using Sha512Fo sha512 = new Sha512Fo();
            ulong[] ipad = new ulong[80];
            ulong[] opad = new ulong[80];

            using Sha256Fo sha256 = new Sha256Fo();
            var cartesian = CartesianProduct.Create(Enumerable.Repeat(Enumerable.Range(0, 2048), missCount));

            fixed(ulong *iPt = ipad, oPt = opad)
            fixed(uint *wPt  = &sha256.w[0], hPt = &sha256.hashState[0], wrd = &wordIndexes[0])
            fixed(int *mi    = &missingIndexes[0])
            fixed(byte *mnPt = &mnBytes[0])
            {
                wPt[7]  = 0b10000000_00000000_00000000_00000000U;
                wPt[15] = 224;

                foreach (var item in cartesian)
                {
                    int j = 0;
                    foreach (var k in item)
                    {
                        wrd[mi[j]] = (uint)k;
                        j++;
                    }

                    wPt[0] = wrd[0] << 21 | wrd[1] << 10 | wrd[2] >> 1;
                    wPt[1] = wrd[2] << 31 | wrd[3] << 20 | wrd[4] << 9 | wrd[5] >> 2;
                    wPt[2] = wrd[5] << 30 | wrd[6] << 19 | wrd[7] << 8 | wrd[8] >> 3;
                    wPt[3] = wrd[8] << 29 | wrd[9] << 18 | wrd[10] << 7 | wrd[11] >> 4;
                    wPt[4] = wrd[11] << 28 | wrd[12] << 17 | wrd[13] << 6 | wrd[14] >> 5;
                    wPt[5] = wrd[14] << 27 | wrd[15] << 16 | wrd[16] << 5 | wrd[17] >> 6;
                    wPt[6] = wrd[17] << 26 | wrd[18] << 15 | wrd[19] << 4 | wrd[20] >> 7;

                    sha256.Init(hPt);
                    sha256.Compress28(hPt, wPt);

                    if ((wrd[20] & 0b111_1111) == hPt[0] >> 25)
                    {
                        int mnLen = 0;
                        for (int i = 0; i < 21; i++)
                        {
                            foreach (byte b in wordBytes[wrd[i]])
                            {
                                mnPt[mnLen++] = b;
                            }
                            mnPt[mnLen++] = SpaceByte;
                        }

                        if (SetBip32(sha512, mnPt, --mnLen, iPt, oPt))
                        {
                            return(SetResult(mnLen));
                        }
                    }
                }
            }

            return(false);
        }
コード例 #10
0
        public unsafe void Compress192SecondBlockTest()
        {
            int dataLen = 192;

            byte[] data     = GetRandomBytes(dataLen);
            byte[] expected = ComputeSingleSha(data);

            ulong *hPt = stackalloc ulong[Sha512Fo.UBufferSize];
            ulong *wPt = hPt + Sha512Fo.HashStateSize;

            Sha512Fo.Init(hPt);

            int dIndex = 0;

            for (int i = 0; i < 16; i++, dIndex += 8)
            {
                wPt[i] =
                    ((ulong)data[dIndex] << 56) |
                    ((ulong)data[dIndex + 1] << 48) |
                    ((ulong)data[dIndex + 2] << 40) |
                    ((ulong)data[dIndex + 3] << 32) |
                    ((ulong)data[dIndex + 4] << 24) |
                    ((ulong)data[dIndex + 5] << 16) |
                    ((ulong)data[dIndex + 6] << 8) |
                    data[dIndex + 7];
            }

            Sha512Fo.SetW(wPt);
            Sha512Fo.CompressBlockWithWSet(hPt, wPt);

            for (int i = 0; i < 8; i++, dIndex += 8)
            {
                wPt[i] =
                    ((ulong)data[dIndex] << 56) |
                    ((ulong)data[dIndex + 1] << 48) |
                    ((ulong)data[dIndex + 2] << 40) |
                    ((ulong)data[dIndex + 3] << 32) |
                    ((ulong)data[dIndex + 4] << 24) |
                    ((ulong)data[dIndex + 5] << 16) |
                    ((ulong)data[dIndex + 6] << 8) |
                    data[dIndex + 7];
            }
            wPt[8]  = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL;
            wPt[9]  = 0;
            wPt[10] = 0;
            wPt[11] = 0;
            wPt[12] = 0;
            wPt[13] = 0;
            wPt[14] = 0;
            wPt[15] = (ulong)dataLen * 8;

            Sha512Fo.Compress192SecondBlock(hPt, wPt);
            byte[] actual = Sha512Fo.GetBytes(hPt);

            Assert.Equal(expected, actual);
        }
コード例 #11
0
        public unsafe void Compress192SecondBlockTest()
        {
            int dataLen = 192;

            byte[] data     = GetRandomBytes(dataLen);
            byte[] expected = ComputeSingleSha(data);

            using Sha512Fo sha = new Sha512Fo();
            fixed(ulong *hPt = &sha.hashState[0], wPt = &sha.w[0])
            {
                sha.Init(hPt);

                int dIndex = 0;

                for (int i = 0; i < 16; i++, dIndex += 8)
                {
                    wPt[i] =
                        ((ulong)data[dIndex] << 56) |
                        ((ulong)data[dIndex + 1] << 48) |
                        ((ulong)data[dIndex + 2] << 40) |
                        ((ulong)data[dIndex + 3] << 32) |
                        ((ulong)data[dIndex + 4] << 24) |
                        ((ulong)data[dIndex + 5] << 16) |
                        ((ulong)data[dIndex + 6] << 8) |
                        data[dIndex + 7];
                }

                sha.CompressBlock(hPt, wPt);

                for (int i = 0; i < 8; i++, dIndex += 8)
                {
                    wPt[i] =
                        ((ulong)data[dIndex] << 56) |
                        ((ulong)data[dIndex + 1] << 48) |
                        ((ulong)data[dIndex + 2] << 40) |
                        ((ulong)data[dIndex + 3] << 32) |
                        ((ulong)data[dIndex + 4] << 24) |
                        ((ulong)data[dIndex + 5] << 16) |
                        ((ulong)data[dIndex + 6] << 8) |
                        data[dIndex + 7];
                }
                wPt[8]  = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL;
                wPt[9]  = 0;
                wPt[10] = 0;
                wPt[11] = 0;
                wPt[12] = 0;
                wPt[13] = 0;
                wPt[14] = 0;
                wPt[15] = (ulong)dataLen * 8;

                sha.Compress192SecondBlock(hPt, wPt);
                byte[] actual = sha.GetBytes(hPt);

                Assert.Equal(expected, actual);
            }
        }
コード例 #12
0
        public void ComputeHash_ReuseTest()
        {
            byte[] msg1 = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog");
            byte[] msg2 = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy cog");
            byte[] exp1 = Helper.HexToBytes("07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6");
            byte[] exp2 = Helper.HexToBytes("3eeee1d0e11733ef152a6c29503b3ae20c4f1f3cda4cb26f1bc1a41f91c7fe4ab3bd86494049e201c4bd5155f31ecb7a3c8606843c4cc8dfcab7da11c8ae5045");

            byte[] act1 = Sha512Fo.ComputeHash(msg1);
            byte[] act2 = Sha512Fo.ComputeHash(msg2);

            Assert.Equal(exp1, act1);
            Assert.Equal(exp2, act2);
        }
コード例 #13
0
ファイル: ScalarTests.cs プロジェクト: nyzi/FinderOuter
        public unsafe void Constructor_FromSha512Test()
        {
            using Sha512Fo sha = new();
            byte[] data = new byte[] { 1, 2, 3 };
            // Get hashstate ready first
            sha.ComputeHash(data);

            fixed(ulong *hPt = &sha.hashState[0])
            {
                byte[] hash = Sha512Fo.GetFirst32Bytes(hPt);
                var    val1 = new Scalar(hash, out int of1);
                var    val2 = new Scalar(hPt, out int of2);

                Assert.True(val1 == val2);
                Assert.Equal(of1, of2);
                Assert.Equal(0, of1);
            }
        }
コード例 #14
0
        public unsafe void Constructor_FromSha512Test()
        {
            byte[] data = new byte[] { 1, 2, 3 };
            ulong *hPt  = stackalloc ulong[Sha512Fo.UBufferSize];
            ulong *wPt  = hPt + Sha512Fo.HashStateSize;

            fixed(byte *dPt = data)
            {
                // Get hashstate ready first
                Sha512Fo.CompressData(dPt, data.Length, data.Length, hPt, wPt);

                byte[] hash = Sha512Fo.GetFirst32Bytes(hPt);
                Scalar val1 = new(hash, out int of1);
                Scalar val2 = new(hPt, out int of2);

                Assert.True(val1 == val2);
                Assert.Equal(of1, of2);
                Assert.Equal(0, of1);
            }
        }
コード例 #15
0
 public void ComputeHashTest(byte[] message, byte[] expectedHash)
 {
     using Sha512Fo sha = new Sha512Fo();
     byte[] actualHash = sha.ComputeHash(message);
     Assert.Equal(expectedHash, actualHash);
 }
コード例 #16
0
 public void ComputeHash_NistLongTest(byte[] message, byte[] expected)
 {
     byte[] actual = Sha512Fo.ComputeHash(message);
     Assert.Equal(expected, actual);
 }
コード例 #17
0
        private unsafe void Loop12(int firstItem, int firstIndex, ParallelLoopState loopState)
        {
            var cartesian = CartesianProduct.Create(Enumerable.Repeat(Enumerable.Range(0, 2048), missCount - 1));

            using Sha512Fo sha512 = new Sha512Fo();
            ulong[] ipad = new ulong[80];
            ulong[] opad = new ulong[80];

            using Sha256Fo sha256 = new Sha256Fo();
            byte[] localMnBytes = new byte[mnBytes.Length];

            var localCopy = new byte[allWordsBytes.Length][];

            Array.Copy(allWordsBytes, localCopy, allWordsBytes.Length);

            uint[] localWIndex = new uint[wordIndexes.Length];
            Array.Copy(wordIndexes, localWIndex, wordIndexes.Length);

            fixed(ulong *iPt = &ipad[0], oPt = &opad[0])
            fixed(uint *wPt  = &sha256.w[0], hPt = &sha256.hashState[0], wrd = &localWIndex[0])
            fixed(int *mi    = &missingIndexes[1])
            fixed(byte *mnPt = &localMnBytes[0])
            {
                wPt[4]  = 0b10000000_00000000_00000000_00000000U;
                wPt[15] = 128;

                wrd[firstIndex] = (uint)firstItem;

                foreach (var item in cartesian)
                {
                    if (loopState.IsStopped)
                    {
                        return;
                    }

                    int j = 0;
                    foreach (var k in item)
                    {
                        wrd[mi[j]] = (uint)k;
                        j++;
                    }

                    wPt[0] = wrd[0] << 21 | wrd[1] << 10 | wrd[2] >> 1;
                    wPt[1] = wrd[2] << 31 | wrd[3] << 20 | wrd[4] << 9 | wrd[5] >> 2;
                    wPt[2] = wrd[5] << 30 | wrd[6] << 19 | wrd[7] << 8 | wrd[8] >> 3;
                    wPt[3] = wrd[8] << 29 | wrd[9] << 18 | wrd[10] << 7 | wrd[11] >> 4;

                    sha256.Init(hPt);
                    sha256.Compress16(hPt, wPt);

                    if ((wrd[11] & 0b1111) == hPt[0] >> 28)
                    {
                        int mnLen = 0;
                        for (int i = 0; i < 12; i++)
                        {
                            var temp = localCopy[wrd[i]];
                            Buffer.BlockCopy(temp, 0, mnBytes, mnLen, temp.Length);
                            mnLen += temp.Length;
                        }

                        if (SetBip32(sha512, mnPt, --mnLen, iPt, oPt))
                        {
                            SetResultParallel(mnPt, mnLen);
                            loopState.Stop();
                            break;
                        }
                    }
                }
            }

            report.IncrementProgress();
        }
コード例 #18
0
        public unsafe void MainLoop(ulong[] pads, byte[] salt, byte[] allValues, int passLength)
        {
            Debug.Assert(pads != null && pads.Length == Sha512Fo.HashStateSize * 2);
            Debug.Assert(salt != null && salt.Length == Sha512Fo.BlockByteSize);

            if (passLength == 1)
            {
                ulong *bigBuffer = stackalloc ulong[Sha512Fo.UBufferSize + Sha512Fo.HashStateSize + (2 * Sha512Fo.WorkingVectorSize)];
                ulong *hPt       = bigBuffer;
                ulong *wPt       = hPt + Sha512Fo.HashStateSize;
                ulong *seedPt    = wPt + Sha512Fo.WorkingVectorSize;

                fixed(byte *dPt = &salt[0], valPt = &allValues[0])
                fixed(ulong *iPt = &pads[0], oPt = &pads[Sha512Fo.HashStateSize])
                {
                    foreach (byte val in allValues)
                    {
                        dPt[8] = val;

                        // 1. SHA512(inner_pad | data) -> 2 blocks; first one is already compressed
                        *(Block64 *)hPt = *(Block64 *)iPt;
                        // Data length is unknown and an initial block of 128 bytes was already compressed
                        // but we already reject anything big that needs another block (there is only one more block to compress)
                        // The pad and data length is also already set
                        Sha512Fo.CompressSingleBlock(dPt, hPt, wPt);

                        // 2. SHA512(outer_pad | hash) -> 2 blocks; first one is already compressed
                        // Copy hashstate into next block before changing it
                        *(Block64 *)wPt = *(Block64 *)hPt;
                        wPt[8]          = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL;
                        wPt[9]          = 0;
                        wPt[10]         = 0;
                        wPt[11]         = 0;
                        wPt[12]         = 0;
                        wPt[13]         = 0;
                        wPt[14]         = 0;
                        wPt[15]         = 1536; // oPad.Length(=128) + hashState.Lengh(=64) = 192 byte *8 = 1,536 bit

                        *(Block64 *)hPt = *(Block64 *)oPt;
                        Sha512Fo.Compress192SecondBlock(hPt, wPt);

                        // Copy u1 to result of F() to be XOR'ed with each result on iterations, and result of F() is the seed
                        *(Block64 *)seedPt = *(Block64 *)hPt;

                        // Compute u2 to u(c-1) where c is iteration and each u is the HMAC of previous u
                        for (int j = 1; j < 2048; j++)
                        {
                            // Each u is calculated by computing HMAC(previous_u) where previous_u is 64 bytes hPt
                            // Start by making a copy of hPt so Init() can be called
                            *(Block64 *)wPt = *(Block64 *)hPt;

                            // Final result is SHA512(outer_pad | SHA512(inner_pad | 64_byte_data))
                            // 1. Compute SHA512(inner_pad | 64_byte_data)
                            // 2. Compute SHA512(outer_pad | hash)
                            //    Since pads don't change and each step is Init() then Compress(pad) the hashState is always the same
                            //    after these 2 steps and is already computed and stored in temp arrays above
                            //    by doing this 2*2047=4094 SHA512 block compressions are skipped

                            // Replace: sha.Init(hPt); sha.CompressBlockWithWSet(hPt, iPt); with line below:
                            *(Block64 *)hPt = *(Block64 *)iPt;
                            Sha512Fo.Compress192SecondBlock(hPt, wPt);

                            // 2. Compute SHA512(outer_pad | hash)
                            *(Block64 *)wPt = *(Block64 *)hPt;
                            // The rest of wPt is set above and is unchanged

                            // Replace: sha.Init(hPt); sha.CompressBlock(hPt, oPt); with line below:
                            *(Block64 *)hPt = *(Block64 *)oPt;
                            Sha512Fo.Compress192SecondBlock(hPt, wPt);

                            // result of F() is XOR sum of all u arrays
                            seedPt[0] ^= hPt[0];
                            seedPt[1] ^= hPt[1];
                            seedPt[2] ^= hPt[2];
                            seedPt[3] ^= hPt[3];
                            seedPt[4] ^= hPt[4];
                            seedPt[5] ^= hPt[5];
                            seedPt[6] ^= hPt[6];
                            seedPt[7] ^= hPt[7];
                        }

                        if (SetBip32(bigBuffer, comparer))
                        {
                            report.FoundAnyResult = true;
                            string finalResult = Encoding.UTF8.GetString(new byte[] { val });
                            report.AddMessageSafe($"Passphrase is: {finalResult}");

                            return;
                        }
                    }
                }
            }
            else
            {
                report.SetProgressStep(allValues.Length);
                Parallel.For(0, allValues.Length,
                             (firstItem, state) => LoopBip39(pads, ParallelSalt(salt, allValues[firstItem]), allValues, passLength, state));
            }
        }
コード例 #19
0
 public void ComputeHash_NistLongTest(byte[] message, byte[] expected)
 {
     using Sha512Fo sha = new Sha512Fo();
     byte[] actual = sha.ComputeHash(message);
     Assert.Equal(expected, actual);
 }
コード例 #20
0
        private unsafe bool Loop24()
        {
            using Sha512Fo sha512 = new Sha512Fo();
            ulong[] ipad = new ulong[80];
            ulong[] opad = new ulong[80];

            using Sha256Fo sha256 = new Sha256Fo();
            var cartesian = CartesianProduct.Create(Enumerable.Repeat(Enumerable.Range(0, 2048), missCount));

            fixed(ulong *iPt = ipad, oPt = opad)
            fixed(uint *wPt  = &sha256.w[0], hPt = &sha256.hashState[0], wrd = &wordIndexes[0])
            fixed(int *mi    = &missingIndexes[0])
            fixed(byte *mnPt = &mnBytes[0])
            {
                wPt[8]  = 0b10000000_00000000_00000000_00000000U;
                wPt[15] = 256;

                foreach (var item in cartesian)
                {
                    int j = 0;
                    foreach (var k in item)
                    {
                        wrd[mi[j]] = (uint)k;
                        j++;
                    }
                    // 0000_0000 0000_0000 0000_0111 1111_1111 -> 1111_1111 1110_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0222 2222_2222 -> 0000_0000 0002_2222 2222_2200 0000_0000
                    // 0000_0000 0000_0000 0000_0333 3333_3333 -> 0000_0000 0000_0000 0000_0033 3333_3333 -> 3
                    //                                            1111_1111 1112_2222 2222_2233 3333_3333
                    wPt[0] = wrd[0] << 21 | wrd[1] << 10 | wrd[2] >> 1;

                    // 0000_0000 0000_0000 0000_0000 0000_0003 -> 3000_0000 0000_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0444 4444_4444 -> 0444_4444 4444_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0555 5555_5555 -> 0000_0000 0000_5555 5555_5550 0000_0000
                    // 0000_0000 0000_0000 0000_0666 6666_6666 -> 0000_0000 0000_0000 0000_0006 6666_6666 -> 66
                    //                                            3444_4444 4444_5555 5555_5556 6666_6666
                    wPt[1] = wrd[2] << 31 | wrd[3] << 20 | wrd[4] << 9 | wrd[5] >> 2;

                    // 0000_0000 0000_0000 0000_0000 0000_0066 -> 6600_0000 0000_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0777 7777_7777 -> 0077_7777 7777_7000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0888 8888_8888 -> 0000_0000 0000_0888 8888_8888 0000_0000
                    // 0000_0000 0000_0000 0000_0999 9999_9999 -> 0000_0000 0000_0000 0000_0000 9999_9999 -> 999
                    //                                            6677_7777 7777_7888 8888_8888 9999_9999
                    wPt[2] = wrd[5] << 30 | wrd[6] << 19 | wrd[7] << 8 | wrd[8] >> 3;

                    // 0000_0000 0000_0000 0000_0000 0000_0999 -> 9990_0000 0000_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0AAA AAAA_AAAA -> 000A_AAAA AAAA_AA00 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0BBB BBBB_BBBB -> 0000_0000 0000_00BB BBBB_BBBB B000_0000
                    // 0000_0000 0000_0000 0000_0CCC CCCC_CCCC -> 0000_0000 0000_0000 0000_0000 0CCC_CCCC -> CCCC
                    //                                            999A_AAAA AAAA_AABB BBBB_BBBB BCCC_CCCC
                    wPt[3] = wrd[8] << 29 | wrd[9] << 18 | wrd[10] << 7 | wrd[11] >> 4;

                    // 0000_0000 0000_0000 0000_0000 0000_CCCC -> CCCC_0000 0000_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0DDD DDDD_DDDD -> 0000_DDDD DDDD_DDD0 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0EEE EEEE_EEEE -> 0000_0000 0000_000E EEEE_EEEE EE00_0000
                    // 0000_0000 0000_0000 0000_0FFF FFFF_FFFF -> 0000_0000 0000_0000 0000_0000 00FF_FFFF -> FFFF_F
                    //                                            CCCC_DDDD DDDD_DDDE EEEE_EEEE EEFF_FFFF
                    wPt[4] = wrd[11] << 28 | wrd[12] << 17 | wrd[13] << 6 | wrd[14] >> 5;

                    // 0000_0000 0000_0000 0000_0000 000F_FFFF -> FFFF_F000 0000_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0GGG GGGG_GGGG -> 0000_0GGG GGGG_GGGG 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0HHH HHHH_HHHH -> 0000_0000 0000_0000 HHHH_HHHH HHH0_0000
                    // 0000_0000 0000_0000 0000_0III IIII_IIII -> 0000_0000 0000_0000 0000_0000 000I_IIII -> IIII_II
                    //                                         -> FFFF_FGGG GGGG_GGGG HHHH_HHHH HHHI_IIII
                    wPt[5] = wrd[14] << 27 | wrd[15] << 16 | wrd[16] << 5 | wrd[17] >> 6;

                    // 0000_0000 0000_0000 0000_0000 00II_IIII -> IIII_II00 0000_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0JJJ JJJJ_JJJJ -> 0000_00JJ JJJJ_JJJJ J000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0KKK KKKK_KKKK -> 0000_0000 0000_0000 0KKK_KKKK KKKK_0000
                    // 0000_0000 0000_0000 0000_0LLL LLLL_LLLL -> 0000_0000 0000_0000 0000_0000 0000_LLLL -> LLLL_LLL
                    //                                         -> IIII_IIJJ JJJJ_JJJJ JKKK_KKKK KKKK_LLLL
                    wPt[6] = wrd[17] << 26 | wrd[18] << 15 | wrd[19] << 4 | wrd[20] >> 7;

                    // 0000_0000 0000_0000 0000_0000 0LLL_LLLL -> LLLL_LLL0 0000_0000 0000_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0MMM MMMM_MMMM -> 0000_000M MMMM_MMMM MM00_0000 0000_0000
                    // 0000_0000 0000_0000 0000_0NNN NNNN_NNNN -> 0000_0000 0000_0000 00NN_NNNN NNNN_N000
                    // 0000_0000 0000_0000 0000_0OOO OOOO_OOOO -> 0000_0000 0000_0000 0000_0000 0000_0OOO -> OOOO_OOOO
                    //                                         -> LLLL_LLLM MMMM_MMMM MMNN_NNNN NNNN_NOOO
                    wPt[7] = wrd[20] << 25 | wrd[21] << 14 | wrd[22] << 3 | wrd[23] >> 8;

                    sha256.Init(hPt);
                    sha256.Compress32(hPt, wPt);

                    if ((byte)wrd[23] == hPt[0] >> 24)
                    {
                        int mnLen = 0;
                        for (int i = 0; i < 24; i++)
                        {
                            foreach (byte b in wordBytes[wrd[i]])
                            {
                                mnPt[mnLen++] = b;
                            }
                            mnPt[mnLen++] = SpaceByte;
                        }

                        if (SetBip32(sha512, mnPt, --mnLen, iPt, oPt))
                        {
                            return(SetResult(mnLen));
                        }
                    }
                }
            }

            return(false);
        }
コード例 #21
0
        public unsafe bool SetBip32(ulong *bigBuffer, ICompareService comparer)
        {
            ulong *hPt    = bigBuffer;
            ulong *wPt    = hPt + Sha512Fo.HashStateSize;
            ulong *seedPt = wPt + Sha512Fo.WorkingVectorSize;
            ulong *iPt    = seedPt + Sha512Fo.HashStateSize;
            ulong *oPt    = iPt + Sha512Fo.WorkingVectorSize;

            // *** BIP32 ***
            // Set from entropy/seed by computing HMAC(data=seed, key="Bitcoin seed")

            // Final result is SHA512(outer_pad | SHA512(inner_pad | data)) where data is 64-byte seed
            // 1. Compute SHA512(inner_pad | data)
            Sha512Fo.Init_InnerPad_Bitcoinseed(hPt);
            *(Block64 *)wPt = *(Block64 *)seedPt;
            // from wPt[8] to wPt[15] didn't change
            Sha512Fo.Compress192SecondBlock(hPt, wPt);

            // 2. Compute SHA512(outer_pad | hash)
            *(Block64 *)wPt = *(Block64 *)hPt; // ** Copy hashState before changing it **
                                               // from wPt[8] to wPt[15] didn't change
            Sha512Fo.Init_OuterPad_Bitcoinseed(hPt);
            Sha512Fo.Compress192SecondBlock(hPt, wPt);
            // Master key is set. PrivateKey= first 32-bytes of hPt and ChainCode is second 32-bytes

            // Each child is derived by computing HMAC(data=(hardened? 0|prvKey : pubkey) | index, key=ChainCode)
            // ChainCode is the second 32-byte half of the hash. Set pad items that never change here:
            // TODO: this part can be set by the caller outside its loop
            iPt[4]  = 0x3636363636363636U;
            iPt[5]  = 0x3636363636363636U;
            iPt[6]  = 0x3636363636363636U;
            iPt[7]  = 0x3636363636363636U;
            iPt[8]  = 0x3636363636363636U;
            iPt[9]  = 0x3636363636363636U;
            iPt[10] = 0x3636363636363636U;
            iPt[11] = 0x3636363636363636U;
            iPt[12] = 0x3636363636363636U;
            iPt[13] = 0x3636363636363636U;
            iPt[14] = 0x3636363636363636U;
            iPt[15] = 0x3636363636363636U;

            oPt[4]  = 0x5c5c5c5c5c5c5c5cU;
            oPt[5]  = 0x5c5c5c5c5c5c5c5cU;
            oPt[6]  = 0x5c5c5c5c5c5c5c5cU;
            oPt[7]  = 0x5c5c5c5c5c5c5c5cU;
            oPt[8]  = 0x5c5c5c5c5c5c5c5cU;
            oPt[9]  = 0x5c5c5c5c5c5c5c5cU;
            oPt[10] = 0x5c5c5c5c5c5c5c5cU;
            oPt[11] = 0x5c5c5c5c5c5c5c5cU;
            oPt[12] = 0x5c5c5c5c5c5c5c5cU;
            oPt[13] = 0x5c5c5c5c5c5c5c5cU;
            oPt[14] = 0x5c5c5c5c5c5c5c5cU;
            oPt[15] = 0x5c5c5c5c5c5c5c5cU;

            Scalar sclrParent = new(hPt, out int overflow);

            if (overflow != 0)
            {
                return(false);
            }

            foreach (uint index in path.Indexes)
            {
                if ((index & 0x80000000) != 0) // IsHardened
                {
                    // First _byte_ is zero
                    // private-key is the first 32 bytes (4 items) of hPt (total 33 bytes)
                    // 4 bytes index + SHA padding are also added
                    wPt[0] = (ulong)sclrParent.b7 << 24 | (ulong)sclrParent.b6 >> 8;
                    wPt[1] = (ulong)sclrParent.b6 << 56 | (ulong)sclrParent.b5 << 24 | (ulong)sclrParent.b4 >> 8;
                    wPt[2] = (ulong)sclrParent.b4 << 56 | (ulong)sclrParent.b3 << 24 | (ulong)sclrParent.b2 >> 8;
                    wPt[3] = (ulong)sclrParent.b2 << 56 | (ulong)sclrParent.b1 << 24 | (ulong)sclrParent.b0 >> 8;
                    wPt[4] = (ulong)sclrParent.b0 << 56 |
                             (ulong)index << 24 |
                             0b00000000_00000000_00000000_00000000_00000000_10000000_00000000_00000000UL;
                }
                else
                {
                    Span <byte> pubkeyBytes = comparer.Calc.GetPubkey(sclrParent, true);
                    fixed(byte *pubXPt = &pubkeyBytes[0])
                    {
                        wPt[0] = (ulong)pubXPt[0] << 56 |
                                 (ulong)pubXPt[1] << 48 |
                                 (ulong)pubXPt[2] << 40 |
                                 (ulong)pubXPt[3] << 32 |
                                 (ulong)pubXPt[4] << 24 |
                                 (ulong)pubXPt[5] << 16 |
                                 (ulong)pubXPt[6] << 8 |
                                 pubXPt[7];
                        wPt[1] = (ulong)pubXPt[8] << 56 |
                                 (ulong)pubXPt[9] << 48 |
                                 (ulong)pubXPt[10] << 40 |
                                 (ulong)pubXPt[11] << 32 |
                                 (ulong)pubXPt[12] << 24 |
                                 (ulong)pubXPt[13] << 16 |
                                 (ulong)pubXPt[14] << 8 |
                                 pubXPt[15];
                        wPt[2] = (ulong)pubXPt[16] << 56 |
                                 (ulong)pubXPt[17] << 48 |
                                 (ulong)pubXPt[18] << 40 |
                                 (ulong)pubXPt[19] << 32 |
                                 (ulong)pubXPt[20] << 24 |
                                 (ulong)pubXPt[21] << 16 |
                                 (ulong)pubXPt[22] << 8 |
                                 pubXPt[23];
                        wPt[3] = (ulong)pubXPt[24] << 56 |
                                 (ulong)pubXPt[25] << 48 |
                                 (ulong)pubXPt[26] << 40 |
                                 (ulong)pubXPt[27] << 32 |
                                 (ulong)pubXPt[28] << 24 |
                                 (ulong)pubXPt[29] << 16 |
                                 (ulong)pubXPt[30] << 8 |
                                 pubXPt[31];
                        wPt[4] = (ulong)pubXPt[32] << 56 |
                                 (ulong)index << 24 |
                                 0b00000000_00000000_00000000_00000000_00000000_10000000_00000000_00000000UL;
                    }
                }

                wPt[5]  = 0;
                wPt[6]  = 0;
                wPt[7]  = 0;
                wPt[8]  = 0;
                wPt[9]  = 0;
                wPt[10] = 0;
                wPt[11] = 0;
                wPt[12] = 0;
                wPt[13] = 0;
                wPt[14] = 0;
                wPt[15] = 1320; // (1+32+4 + 128)*8

                // Final result is SHA512(outer_pad | SHA512(inner_pad | 37_byte_data))
                // 1. Compute SHA512(inner_pad | 37_byte_data)
                // Set pads to be used as working vectors (key is ChainCode that is the second 32 bytes of SHA512
                iPt[0] = 0x3636363636363636U ^ hPt[4];
                iPt[1] = 0x3636363636363636U ^ hPt[5];
                iPt[2] = 0x3636363636363636U ^ hPt[6];
                iPt[3] = 0x3636363636363636U ^ hPt[7];

                oPt[0] = 0x5c5c5c5c5c5c5c5cU ^ hPt[4];
                oPt[1] = 0x5c5c5c5c5c5c5c5cU ^ hPt[5];
                oPt[2] = 0x5c5c5c5c5c5c5c5cU ^ hPt[6];
                oPt[3] = 0x5c5c5c5c5c5c5c5cU ^ hPt[7];

                Sha512Fo.Init(hPt);
                Sha512Fo.SetW(iPt);
                Sha512Fo.CompressBlockWithWSet(hPt, iPt);
                Sha512Fo.Compress165SecondBlock(hPt, wPt);

                // 2. Compute SHA512(outer_pad | hash)
                *(Block64 *)wPt = *(Block64 *)hPt;
                wPt[8]          = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL;
                wPt[9]          = 0;
                wPt[10]         = 0;
                wPt[11]         = 0;
                wPt[12]         = 0;
                wPt[13]         = 0;
                wPt[14]         = 0;
                wPt[15]         = 1536; // (128+64)*8

                Sha512Fo.Init(hPt);
                Sha512Fo.SetW(oPt);
                Sha512Fo.CompressBlockWithWSet(hPt, oPt);
                Sha512Fo.Compress192SecondBlock(hPt, wPt);

                // New private key is (parentPrvKey + int(hPt)) % order
                sclrParent = sclrParent.Add(new Scalar(hPt, out _), out _);
            }

            // Child extended key (private key + chianCode) should be set by adding the index to the end of the Path
            // and have been computed already
            hPt[0] = (ulong)sclrParent.b7 << 32 | sclrParent.b6;
            hPt[1] = (ulong)sclrParent.b5 << 32 | sclrParent.b4;
            hPt[2] = (ulong)sclrParent.b3 << 32 | sclrParent.b2;
            hPt[3] = (ulong)sclrParent.b1 << 32 | sclrParent.b0;

            return(comparer.Compare(hPt));
        }
コード例 #22
0
        public unsafe bool SetBip32(Sha512Fo sha, byte *mnPt, int mnLen, ulong *iPt, ulong *oPt)
        {
            // The process is: PBKDF2(password=UTF8(mnemonic), salt=UTF8("mnemonic+passphrase") -> BIP32 seed
            //                 BIP32 -> HMACSHA(data=seed, key=MasterKeyHashKey) -> HMACSHA(data=key|index, key=ChainCode)
            // All HMACSHAs are using 512 variant

            // *** PBKDF2 ***
            // dkLen/HmacLen=1 => only 1 block => no loop needed
            // Salt is the "mnemonic+passPhrase" + blockNumber(=1) => fixed and set during precomputing
            ulong[] resultOfF = new ulong[8];
            ulong[] uTemp     = new ulong[80];

            ulong[] iPadHashStateTemp = new ulong[8];
            ulong[] oPadHashStateTemp = new ulong[8];

            ulong parkey0, parkey1, parkey2, parkey3, carry;

            fixed(byte *dPt = &pbkdf2Salt[0])
            fixed(ulong *hPt = &sha.hashState[0], wPt = &sha.w[0], seedPt = &resultOfF[0], uPt = &uTemp[0],
                  ihPt       = &iPadHashStateTemp[0], ohPt = &oPadHashStateTemp[0])
            {
                // Setting values in uTemp that never change
                uPt[8]  = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL;
                uPt[9]  = 0;
                uPt[10] = 0;
                uPt[11] = 0;
                uPt[12] = 0;
                uPt[13] = 0;
                uPt[14] = 0;
                uPt[15] = 1536;


                // Set HMAC key ie. set pads (used as working vectors)
                if (mnLen > Sha512Fo.BlockByteSize)
                {
                    // Key bytes must be hashed first
                    sha.Init(hPt);
                    sha.CompressData(mnPt, mnLen, mnLen, hPt, wPt);
                    // Set pads to be used as working vectors
                    iPt[0]  = 0x3636363636363636U ^ hPt[0];
                    iPt[1]  = 0x3636363636363636U ^ hPt[1];
                    iPt[2]  = 0x3636363636363636U ^ hPt[2];
                    iPt[3]  = 0x3636363636363636U ^ hPt[3];
                    iPt[4]  = 0x3636363636363636U ^ hPt[4];
                    iPt[5]  = 0x3636363636363636U ^ hPt[5];
                    iPt[6]  = 0x3636363636363636U ^ hPt[6];
                    iPt[7]  = 0x3636363636363636U ^ hPt[7];
                    iPt[8]  = 0x3636363636363636U;
                    iPt[9]  = 0x3636363636363636U;
                    iPt[10] = 0x3636363636363636U;
                    iPt[11] = 0x3636363636363636U;
                    iPt[12] = 0x3636363636363636U;
                    iPt[13] = 0x3636363636363636U;
                    iPt[14] = 0x3636363636363636U;
                    iPt[15] = 0x3636363636363636U;

                    oPt[0]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[0];
                    oPt[1]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[1];
                    oPt[2]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[2];
                    oPt[3]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[3];
                    oPt[4]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[4];
                    oPt[5]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[5];
                    oPt[6]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[6];
                    oPt[7]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[7];
                    oPt[8]  = 0x5c5c5c5c5c5c5c5cU;
                    oPt[9]  = 0x5c5c5c5c5c5c5c5cU;
                    oPt[10] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[11] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[12] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[13] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[14] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[15] = 0x5c5c5c5c5c5c5c5cU;
                }
                else
                {
                    byte[] temp = new byte[Sha512Fo.BlockByteSize];
                    fixed(byte *tPt = &temp[0])
                    {
                        Buffer.MemoryCopy(mnPt, tPt, Sha512Fo.BlockByteSize, mnLen);
                        for (int i = 0, j = 0; i < 16; i++, j += 8)
                        {
                            ulong val =
                                ((ulong)tPt[j] << 56) |
                                ((ulong)tPt[j + 1] << 48) |
                                ((ulong)tPt[j + 2] << 40) |
                                ((ulong)tPt[j + 3] << 32) |
                                ((ulong)tPt[j + 4] << 24) |
                                ((ulong)tPt[j + 5] << 16) |
                                ((ulong)tPt[j + 6] << 8) |
                                tPt[j + 7];

                            iPt[i] = 0x3636363636363636U ^ val;
                            oPt[i] = 0x5c5c5c5c5c5c5c5cU ^ val;
                        }
                    }
                }

                // F()
                // compute u1 = hmac.ComputeHash(data=pbkdf2Salt);

                // Final result is SHA512(outer_pad | SHA512(inner_pad | data)) where data is pbkdf2Salt
                // 1. Compute SHA512(inner_pad | data)
                sha.Init(hPt);
                sha.CompressBlock(hPt, iPt);
                // Make a copy of hashState of inner-pad to be used in the loop below (explaination in the loop)
                *(Block64 *)ihPt = *(Block64 *)hPt;
                // Data length is unknown and an initial block of 128 bytes was already compressed
                sha.CompressData(dPt, pbkdf2Salt.Length, pbkdf2Salt.Length + 128, hPt, wPt);
                // 2. Compute SHA512(outer_pad | hash)
                *(Block64 *)wPt = *(Block64 *)hPt;
                wPt[8]          = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL;
                wPt[9]          = 0;
                wPt[10]         = 0;
                wPt[11]         = 0;
                wPt[12]         = 0;
                wPt[13]         = 0;
                wPt[14]         = 0;
                wPt[15]         = 1536; // oPad.Length(=128) + hashState.Lengh(=64) = 192 byte *8 = 1,536 bit

                sha.Init(hPt);
                sha.CompressBlock(hPt, oPt);
                // Make a copy of hashState of outer-pad to be used in the loop below (explaination in the loop)
                *(Block64 *)ohPt = *(Block64 *)hPt;
                sha.Compress192SecondBlock(hPt, wPt);

                // Copy u1 to result of F() to be XOR'ed with each result on iterations, and result of F() is the seed
                *(Block64 *)seedPt = *(Block64 *)hPt;

                // Compute u2 to u(c-1) where c is iteration and each u is the HMAC of previous u
                for (int j = 1; j < 2048; j++)
                {
                    // Each u is calculated by computing HMAC(previous_u) where previous_u is 64 bytes hPt
                    // Start by making a copy of hPt so Init() can be called
                    *(Block64 *)uPt = *(Block64 *)hPt;

                    // Final result is SHA512(outer_pad | SHA512(inner_pad | 64_byte_data))
                    // 1. Compute SHA512(inner_pad | 64_byte_data)
                    // 2. Compute SHA512(outer_pad | hash)
                    //    Since pads don't change and each step is Init() then Compress(pad) the hashState is always the same
                    //    after these 2 steps and is already computed and stored in temp arrays above
                    //    by doing this 2*2047=4094 SHA512 block compressions are skipped

                    // Replace: sha.Init(hPt); sha.CompressBlockWithWSet(hPt, iPt); with line below:
                    *(Block64 *)hPt = *(Block64 *)ihPt;
                    sha.Compress192SecondBlock(hPt, uPt);

                    // 2. Compute SHA512(outer_pad | hash)
                    *(Block64 *)wPt = *(Block64 *)hPt;
                    // The rest of wPt is set above and is unchanged

                    // Replace: sha.Init(hPt); sha.CompressBlock(hPt, oPt); with line below:
                    *(Block64 *)hPt = *(Block64 *)ohPt;
                    sha.Compress192SecondBlock(hPt, wPt);

                    // result of F() is XOR sum of all u arrays
                    if (Avx2.IsSupported) // AVX512 :(
                    {
                        Vector256 <ulong> part1 = Avx2.Xor(Avx2.LoadVector256(seedPt), Avx2.LoadVector256(hPt));
                        Vector256 <ulong> part2 = Avx2.Xor(Avx2.LoadVector256(seedPt + 4), Avx2.LoadVector256(hPt + 4));

                        Avx2.Store(seedPt, part1);
                        Avx2.Store(seedPt + 4, part2);
                    }
                    else
                    {
                        seedPt[0] ^= hPt[0];
                        seedPt[1] ^= hPt[1];
                        seedPt[2] ^= hPt[2];
                        seedPt[3] ^= hPt[3];
                        seedPt[4] ^= hPt[4];
                        seedPt[5] ^= hPt[5];
                        seedPt[6] ^= hPt[6];
                        seedPt[7] ^= hPt[7];
                    }
                }


                // *** BIP32 ***
                // Set from entropy/seed by computing HMAC(data=seed, key="Bitcoin seed")

                // Final result is SHA512(outer_pad | SHA512(inner_pad | data)) where data is 64-byte seed
                // 1. Compute SHA512(inner_pad | data)
                sha.Init_InnerPad_Bitcoinseed(hPt);
                *(Block64 *)wPt = *(Block64 *)seedPt;
                // from wPt[8] to wPt[15] didn't change
                sha.Compress192SecondBlock(hPt, wPt);

                // 2. Compute SHA512(outer_pad | hash)
                *(Block64 *)wPt = *(Block64 *)hPt; // ** Copy hashState before changing it **
                // from wPt[8] to wPt[15] didn't change
                sha.Init_OuterPad_Bitcoinseed(hPt);
                sha.Compress192SecondBlock(hPt, wPt);
                // Master key is set. PrivateKey= first 32-bytes of hPt and ChainCode is second 32-bytes

                // Each child is derived by computing HMAC(data=(hardened? 0|prvKey : pubkey) | index, key=ChainCode)
                // ChainCode is the second 32-byte half of the hash. Set pad items that never change here:
                iPt[4]  = 0x3636363636363636U;
                iPt[5]  = 0x3636363636363636U;
                iPt[6]  = 0x3636363636363636U;
                iPt[7]  = 0x3636363636363636U;
                iPt[8]  = 0x3636363636363636U;
                iPt[9]  = 0x3636363636363636U;
                iPt[10] = 0x3636363636363636U;
                iPt[11] = 0x3636363636363636U;
                iPt[12] = 0x3636363636363636U;
                iPt[13] = 0x3636363636363636U;
                iPt[14] = 0x3636363636363636U;
                iPt[15] = 0x3636363636363636U;

                oPt[4]  = 0x5c5c5c5c5c5c5c5cU;
                oPt[5]  = 0x5c5c5c5c5c5c5c5cU;
                oPt[6]  = 0x5c5c5c5c5c5c5c5cU;
                oPt[7]  = 0x5c5c5c5c5c5c5c5cU;
                oPt[8]  = 0x5c5c5c5c5c5c5c5cU;
                oPt[9]  = 0x5c5c5c5c5c5c5c5cU;
                oPt[10] = 0x5c5c5c5c5c5c5c5cU;
                oPt[11] = 0x5c5c5c5c5c5c5c5cU;
                oPt[12] = 0x5c5c5c5c5c5c5c5cU;
                oPt[13] = 0x5c5c5c5c5c5c5c5cU;
                oPt[14] = 0x5c5c5c5c5c5c5c5cU;
                oPt[15] = 0x5c5c5c5c5c5c5c5cU;

                uPt[5]  = 0;
                uPt[6]  = 0;
                uPt[7]  = 0;
                uPt[8]  = 0;
                uPt[9]  = 0;
                uPt[10] = 0;
                uPt[11] = 0;
                uPt[12] = 0;
                uPt[13] = 0;
                uPt[14] = 0;
                uPt[15] = 1320; // (1+32+4 + 128)*8

                BigInteger kParent = new BigInteger(sha.GetFirst32Bytes(hPt), true, true);

                if (kParent == 0 || kParent >= order)
                {
                    return(false);
                }
                parkey0 = hPt[3];
                parkey1 = hPt[2];
                parkey2 = hPt[1];
                parkey3 = hPt[0];

                foreach (var index in path.Indexes)
                {
                    if ((index & 0x80000000) != 0) // IsHardened
                    {
                        // First _byte_ is zero
                        // private-key is the first 32 bytes (4 items) of hPt (total 33 bytes)
                        // 4 bytes index + SHA padding are also added
                        uPt[0] = parkey3 >> 8;
                        uPt[1] = parkey3 << 56 | parkey2 >> 8;
                        uPt[2] = parkey2 << 56 | parkey1 >> 8;
                        uPt[3] = parkey1 << 56 | parkey0 >> 8;
                        uPt[4] = parkey0 << 56 |
                                 (ulong)index << 24 |
                                 0b00000000_00000000_00000000_00000000_00000000_10000000_00000000_00000000UL;
                    }
                    else
                    {
                        var    point  = calc.MultiplyByG(kParent);
                        byte[] xBytes = point.X.ToByteArray(true, true).PadLeft(32);
                        fixed(byte *pubXPt = &xBytes[0])
                        {
                            uPt[0] = (point.Y.IsEven ? 0x0200000000000000UL : 0x0300000000000000UL) |
                                     (ulong)pubXPt[0] << 48 |
                                     (ulong)pubXPt[1] << 40 |
                                     (ulong)pubXPt[2] << 32 |
                                     (ulong)pubXPt[3] << 24 |
                                     (ulong)pubXPt[4] << 16 |
                                     (ulong)pubXPt[5] << 8 |
                                     pubXPt[6];
                            uPt[1] = (ulong)pubXPt[7] << 56 |
                                     (ulong)pubXPt[8] << 48 |
                                     (ulong)pubXPt[9] << 40 |
                                     (ulong)pubXPt[10] << 32 |
                                     (ulong)pubXPt[11] << 24 |
                                     (ulong)pubXPt[12] << 16 |
                                     (ulong)pubXPt[13] << 8 |
                                     pubXPt[14];
                            uPt[2] = (ulong)pubXPt[15] << 56 |
                                     (ulong)pubXPt[16] << 48 |
                                     (ulong)pubXPt[17] << 40 |
                                     (ulong)pubXPt[18] << 32 |
                                     (ulong)pubXPt[19] << 24 |
                                     (ulong)pubXPt[20] << 16 |
                                     (ulong)pubXPt[21] << 8 |
                                     pubXPt[22];
                            uPt[3] = (ulong)pubXPt[23] << 56 |
                                     (ulong)pubXPt[24] << 48 |
                                     (ulong)pubXPt[25] << 40 |
                                     (ulong)pubXPt[26] << 32 |
                                     (ulong)pubXPt[27] << 24 |
                                     (ulong)pubXPt[28] << 16 |
                                     (ulong)pubXPt[29] << 8 |
                                     pubXPt[30];
                            uPt[4] = (ulong)pubXPt[31] << 56 |
                                     (ulong)index << 24 |
                                     0b00000000_00000000_00000000_00000000_00000000_10000000_00000000_00000000UL;
                        }
                    }


                    // Final result is SHA512(outer_pad | SHA512(inner_pad | 37_byte_data))
                    // 1. Compute SHA512(inner_pad | 37_byte_data)
                    // Set pads to be used as working vectors (key is ChainCode that is the second 32 bytes of SHA512
                    iPt[0] = 0x3636363636363636U ^ hPt[4];
                    iPt[1] = 0x3636363636363636U ^ hPt[5];
                    iPt[2] = 0x3636363636363636U ^ hPt[6];
                    iPt[3] = 0x3636363636363636U ^ hPt[7];

                    oPt[0] = 0x5c5c5c5c5c5c5c5cU ^ hPt[4];
                    oPt[1] = 0x5c5c5c5c5c5c5c5cU ^ hPt[5];
                    oPt[2] = 0x5c5c5c5c5c5c5c5cU ^ hPt[6];
                    oPt[3] = 0x5c5c5c5c5c5c5c5cU ^ hPt[7];

                    sha.Init(hPt);
                    sha.CompressBlock(hPt, iPt);
                    sha.Compress165SecondBlock(hPt, uPt);

                    // 2. Compute SHA512(outer_pad | hash)
                    *(Block64 *)wPt = *(Block64 *)hPt;

                    // from wPt[8] to wPt[15] didn't change
                    sha.Init(hPt);
                    sha.CompressBlock(hPt, oPt);
                    sha.Compress192SecondBlock(hPt, wPt);

                    // New private key is (parentPrvKey + int(hPt)) % order
                    // TODO: this is a bottleneck and needs to be replaced by a ModularUInt256 instance
                    kParent = (kParent + new BigInteger(sha.GetFirst32Bytes(hPt), true, true)) % order;

                    ulong toAdd = hPt[3];
                    parkey0 += toAdd;
                    if (parkey0 < toAdd)
                    {
                        parkey1++;
                    }

                    toAdd    = hPt[2];
                    parkey1 += toAdd;
                    if (parkey1 < toAdd)
                    {
                        parkey2++;
                    }

                    toAdd    = hPt[1];
                    parkey2 += toAdd;
                    if (parkey2 < toAdd)
                    {
                        parkey3++;
                    }

                    toAdd    = hPt[0];
                    parkey3 += toAdd;
                    if (parkey3 < toAdd)
                    {
                        carry = 1;
                    }
                    else
                    {
                        carry = 0;
                    }

                    bool bigger = false;
                    if (carry == 1)
                    {
                        bigger = true;
                    }
                    else if (parkey3 == N3)
                    {
                        if (parkey2 > N2)
                        {
                            bigger = true;
                        }
                        else if (parkey2 == N2)
                        {
                            if (parkey1 > N1)
                            {
                                bigger = true;
                            }
                            else if (parkey1 == N1)
                            {
                                if (parkey0 >= N0)
                                {
                                    bigger = true;
                                }
                            }
                        }
                    }

                    if (bigger)
                    {
                        if (parkey0 < N0)
                        {
                            parkey1--;
                        }
                        parkey0 -= N0;

                        if (parkey1 < N1)
                        {
                            parkey2--;
                        }
                        parkey1 -= N1;

                        if (parkey2 < N2)
                        {
                            parkey3--;
                        }
                        parkey2 -= N2;

                        parkey3 -= N3;
                    }
                }

                // Child extended key (private key + chianCode) should be set by adding the index to the end of the Path
                // and have been computed already
                hPt[0] = parkey3;
                hPt[1] = parkey2;
                hPt[2] = parkey1;
                hPt[3] = parkey0;

                return(comparer.Compare(sha.GetFirst32Bytes(hPt)));
            }
        }
コード例 #23
0
        private static unsafe void SetHmacPads(byte[] mnBytes, ulong[] pads)
        {
            Debug.Assert(mnBytes != null && mnBytes.Length > 0);
            Debug.Assert(pads != null && pads.Length == 2 * Sha512Fo.HashStateSize);

            // PBKDF2:
            // compute u1 = hmac.ComputeHash(data=pbkdf2Salt/pass, key=mnemonic);
            //         u1 = SHA512(outer_pad | SHA512(inner_pad | pass | 0x00000001 ))
            // First block of each SHA512 is the pad with key already set to mnemonic so they can be pre-computed

            ulong *hPt = stackalloc ulong[Sha512Fo.UBufferSize + Sha512Fo.WorkingVectorSize];
            ulong *iPt = hPt + Sha512Fo.HashStateSize;
            ulong *oPt = hPt + Sha512Fo.UBufferSize;

            fixed(byte *mnPt = &mnBytes[0])
            fixed(ulong *rPt = &pads[0])
            {
                if (mnBytes.Length > Sha512Fo.BlockByteSize)
                {
                    // Key bytes must be hashed first
                    Sha512Fo.Init(hPt);
                    Sha512Fo.CompressData(mnPt, mnBytes.Length, mnBytes.Length, hPt, iPt);
                    iPt[0]  = 0x3636363636363636U ^ hPt[0];
                    iPt[1]  = 0x3636363636363636U ^ hPt[1];
                    iPt[2]  = 0x3636363636363636U ^ hPt[2];
                    iPt[3]  = 0x3636363636363636U ^ hPt[3];
                    iPt[4]  = 0x3636363636363636U ^ hPt[4];
                    iPt[5]  = 0x3636363636363636U ^ hPt[5];
                    iPt[6]  = 0x3636363636363636U ^ hPt[6];
                    iPt[7]  = 0x3636363636363636U ^ hPt[7];
                    iPt[8]  = 0x3636363636363636U;
                    iPt[9]  = 0x3636363636363636U;
                    iPt[10] = 0x3636363636363636U;
                    iPt[11] = 0x3636363636363636U;
                    iPt[12] = 0x3636363636363636U;
                    iPt[13] = 0x3636363636363636U;
                    iPt[14] = 0x3636363636363636U;
                    iPt[15] = 0x3636363636363636U;

                    oPt[0]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[0];
                    oPt[1]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[1];
                    oPt[2]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[2];
                    oPt[3]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[3];
                    oPt[4]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[4];
                    oPt[5]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[5];
                    oPt[6]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[6];
                    oPt[7]  = 0x5c5c5c5c5c5c5c5cU ^ hPt[7];
                    oPt[8]  = 0x5c5c5c5c5c5c5c5cU;
                    oPt[9]  = 0x5c5c5c5c5c5c5c5cU;
                    oPt[10] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[11] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[12] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[13] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[14] = 0x5c5c5c5c5c5c5c5cU;
                    oPt[15] = 0x5c5c5c5c5c5c5c5cU;
                }
                else
                {
                    byte[] temp = new byte[Sha512Fo.BlockByteSize];
                    fixed(byte *tPt = &temp[0])
                    {
                        Buffer.MemoryCopy(mnPt, tPt, Sha512Fo.BlockByteSize, mnBytes.Length);
                        for (int i = 0, j = 0; i < 16; i++, j += 8)
                        {
                            ulong val =
                                ((ulong)tPt[j] << 56) |
                                ((ulong)tPt[j + 1] << 48) |
                                ((ulong)tPt[j + 2] << 40) |
                                ((ulong)tPt[j + 3] << 32) |
                                ((ulong)tPt[j + 4] << 24) |
                                ((ulong)tPt[j + 5] << 16) |
                                ((ulong)tPt[j + 6] << 8) |
                                tPt[j + 7];

                            iPt[i] = 0x3636363636363636U ^ val;
                            oPt[i] = 0x5c5c5c5c5c5c5c5cU ^ val;
                        }
                    }
                }

                Sha512Fo.Init(hPt);
                Sha512Fo.SetW(iPt);
                Sha512Fo.CompressBlockWithWSet(hPt, iPt);
                *(Block64 *)rPt = *(Block64 *)hPt;

                Sha512Fo.Init(hPt);
                Sha512Fo.SetW(oPt);
                Sha512Fo.CompressBlockWithWSet(hPt, oPt);
                *(Block64 *)(rPt + Sha512Fo.HashStateSize) = *(Block64 *)hPt;
            }
        }
コード例 #24
0
 public void ComputeHashTest(byte[] message, byte[] expectedHash)
 {
     byte[] actualHash = Sha512Fo.ComputeHash(message);
     Assert.Equal(expectedHash, actualHash);
 }