private static unsafe bool Loop23Hash(Sha256Fo sha, uint *wPt, uint *hPt, byte *tmp, ICompareService comparer) { // The added value below is the fixed first char('S')=0x53 shifted left 24 places wPt[0] = 0b01010011_00000000_00000000_00000000U | (uint)tmp[1] << 16 | (uint)tmp[2] << 8 | tmp[3]; wPt[1] = (uint)tmp[4] << 24 | (uint)tmp[5] << 16 | (uint)tmp[6] << 8 | tmp[7]; wPt[2] = (uint)tmp[8] << 24 | (uint)tmp[9] << 16 | (uint)tmp[10] << 8 | tmp[11]; wPt[3] = (uint)tmp[12] << 24 | (uint)tmp[13] << 16 | (uint)tmp[14] << 8 | tmp[15]; wPt[4] = (uint)tmp[16] << 24 | (uint)tmp[17] << 16 | (uint)tmp[18] << 8 | tmp[19]; // The added value below is the SHA padding and the last added ? char equal to 0x3f shifted right 8 places wPt[5] = (uint)tmp[20] << 24 | (uint)tmp[21] << 16 | 0b00000000_00000000_00111111_10000000U; // from 6 to 14 = 0 wPt[15] = 184; // 23 *8 = 184 sha.Init(hPt); sha.Compress23(hPt, wPt); if ((hPt[0] & 0b11111111_00000000_00000000_00000000U) == 0) { // The actual key is SHA256 of 22 char key (without '?') // SHA working vector is already set, only the last 2 bytes ('?' and pad) and the length have to change wPt[5] ^= 0b00000000_00000000_10111111_10000000U; // from 6 to 14 (remain) = 0 wPt[15] = 176; // 22 *8 = 176 sha.Init(hPt); sha.Compress22(hPt, wPt); return(comparer.Compare(hPt)); }
public void OrderShouldBeValid() { // Arrange var models = new List <TariffModel> { new BasicElectricityTariff { Consumption = 3500 }, new BasicElectricityTariff { Consumption = 4500 }, new BasicElectricityTariff { Consumption = 6000 }, new PackagedTariff { Consumption = 3500 }, new PackagedTariff { Consumption = 4500 }, new PackagedTariff { Consumption = 6000 } }; // Act var result = compareService.Compare(models); // Assert Assert.IsTrue(result[0].AnnualCost < result[1].AnnualCost && result[1].AnnualCost < result[2].AnnualCost && result[2].AnnualCost < result[3].AnnualCost && result[3].AnnualCost < result[4].AnnualCost && result[4].AnnualCost < result[5].AnnualCost); }
public async Task <IActionResult> Post([FromBody] RequestBody input) { try { if (!string.IsNullOrEmpty(input.backImage)) { var frontTask = Task.Run(() => _service.Compare(input.frontImage, _configuration)); var backTask = Task.Run(() => _service.Compare(input.backImage, _configuration, false)); await Task.WhenAll(frontTask, backTask); if (frontTask.Result + backTask.Result >= _configuration.FailedTreshold) { return(Ok(ResultEnum.Fail)); } if (frontTask.Result + backTask.Result >= _configuration.NotOkayTreshold) { return(Ok(ResultEnum.NotOk)); } } else { var frontTask = await Task.Run(() => _service.Compare(input.frontImage, _configuration)); if (frontTask >= _configuration.NotOkayTreshold) { return(Ok(ResultEnum.NotOk)); } if (frontTask >= _configuration.FailedTreshold) { return(Ok(ResultEnum.Fail)); } } return(Ok(ResultEnum.Ok)); } catch (Exception e) { return(BadRequest(e.Message)); } }
public async Task <IActionResult> Compare([FromBody] CompareInputDTO compareInputDTO) { if (!ModelState.IsValid) { return(BadRequest()); } var result = await compareService.Compare(compareInputDTO); return(Ok(result)); }
public void CloneTest() { PrvToAddrNestedComparer original = new(); Assert.True(original.Init(KeyHelper.Pub1NestedSegwit)); // Make sure it is successfully initialized ICompareService cloned = original.Clone(); // Change original field value to make sure it is cloned not a reference copy Assert.True(original.Init(KeyHelper.Pub2NestedSegwit)); byte[] key = KeyHelper.Prv1.ToBytes(); // Since the original was changed it should fail when comparing Assert.False(original.Compare(key)); Assert.True(cloned.Compare(key)); }
public void Loop(BIP0032 bip32, uint count) { BIP0032Path[] allPaths = new BIP0032Path[] { new BIP0032Path("m/0"), new BIP0032Path("m/0'"), new BIP0032Path("m/0'/0/"), new BIP0032Path("m/0'/0'"), // BIP-44 xprv/xpub P2PKH new BIP0032Path("m/44'/0'/0'/0"), new BIP0032Path("m/44'/0'/0'"), // BIP-49 yprv/upub P2SH-P2WPKH new BIP0032Path("m/49'/0'/0'/0"), new BIP0032Path("m/49'/0'/0'"), // BIP-84 zprv/zpub P2WPKH new BIP0032Path("m/84'/0'/0'/0"), new BIP0032Path("m/84'/0'/0'/"), new BIP0032Path("m/84'/0'/2147483644'/0"), new BIP0032Path("m/84'/0'/2147483645'/0"), new BIP0032Path("m/84'/0'/2147483646'/0"), new BIP0032Path("m/84'/0'/2147483647'/0"), new BIP0032Path("m/49'/0'/2147483647'/0"), new BIP0032Path("m/44'/0'/2147483647'/0"), new BIP0032Path("m/141'/0'/0'/0"), }; foreach (BIP0032Path path in allPaths) { PrivateKey[] keys = bip32.GetPrivateKeys(path, count); for (int i = 0; i < keys.Length; i++) { if (comparer.Compare(keys[i].ToBytes())) { report.AddMessageSafe($"The correct key path is: {path}/{i}"); report.FoundAnyResult = true; return; } } } report.AddMessageSafe("Could not find any correct paths."); }
public async Task Handle(object parameterObj) { var parameter = parameterObj as CompareParameter; Console.WriteLine("Start Compare the Files:"); Console.WriteLine($"{parameter.Path1}"); Console.WriteLine("And:"); Console.WriteLine($"{parameter.Path2}"); Console.WriteLine($"Config File: {parameter.ConfigFile}"); Console.WriteLine($"Result will Save to: {parameter.OutputPath}"); var progress = new Progress <IProgressReport>(report => { TextProgressBar.Draw(report.Current, report.Total); }); var compareFiles = await compareService.Compare(parameter.Path1, parameter.Path2, parameter.ConfigFile, progress); Thread.Sleep(200); await reportService.Output(compareFiles, parameter.Path1, parameter.Path2, parameter.OutputPath, false); }
public async Task <IActionResult> OnPost() { try { var places = await turistPlaceService.ShowAll(); ViewData["Places"] = new SelectList(places, "Name", "Name"); if (!ModelState.IsValid) { return(Page()); } compareOutput = await compareService.Compare(compareInput); State = true; return(Page()); } catch (Exception e) { State = false; ViewData["Errore"] = e.Message; return(Page()); } }
public void Loop(BIP0032 bip32, uint count, bool isPubkey) { BIP0032Path[] allPaths = isPubkey ? new BIP0032Path[] { new BIP0032Path("m/0") } : new BIP0032Path[] { new BIP0032Path("m/0"), new BIP0032Path("m/0'"), new BIP0032Path("m/0'/0/"), // BIP-44 xprv/xpub P2PKH new BIP0032Path("m/44'/0'/0'/0"), // BIP-49 yprv/upub P2SH-P2WPKH new BIP0032Path("m/49'/0'/0'/0"), // BIP-84 zprv/zpub P2WPKH new BIP0032Path("m/84'/0'/0'/0"), }; foreach (var path in allPaths) { PublicKey[] pubkeys = bip32.GetPublicKeys(path, count); for (int i = 0; i < pubkeys.Length; i++) { if (comparer.Compare(pubkeys[i].ToPoint())) { report.AddMessageSafe($"The correct key path is: {path}/{i}"); report.FoundAnyResult = true; return; } } } report.AddMessageSafe("Could not find any correct paths."); }
public async Task <string> Diff(int?id) { ValidateIdAndData(id, string.Empty); return(JsonConvert.SerializeObject(await _service.Compare(id.Value))); }
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)); }
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))); } }
private unsafe void Loop2(byte[] preComputed, int missCount1, int missCount2, uint mask1, uint mask2, uint comp1, uint comp2) { // Note that in the following context HMAC is NOT HMACSHA256 despite the name // because it is using wrong inner/outer pads. For reference: // https://github.com/etotheipi/BitcoinArmory/blob/2a6fc5355bb0c6fe26e387ccba30a5baafe8cd98/armoryengine/ArmoryUtils.py#L1823 // ChainCode is result of HMAC with 2x hash of private key as HMAC key // and "Derive Chaincode from Root Key" as its message using Sha256Fo sha = new Sha256Fo(); byte *kPt = stackalloc byte[32 + missingIndexes.Length]; byte *item1 = kPt + 32; byte *item2 = item1 + missCount1; uint *oPt = stackalloc uint[8]; fixed(byte *pre = &preComputed[0]) fixed(int *mi = &missingIndexes[0]) fixed(uint *wPt = &sha.w[0], hPt = &sha.hashState[0]) { do { *(Block32 *)kPt = *(Block32 *)pre; int mIndex = 0; for (int i = 0; i < missCount1; i++) { int index = mi[mIndex++]; kPt[index / 2] |= (index % 2 == 0) ? (byte)(item1[i] << 4) : item1[i]; } wPt[0] = (uint)((kPt[0] << 24) | (kPt[1] << 16) | (kPt[2] << 8) | kPt[3]); wPt[1] = (uint)((kPt[4] << 24) | (kPt[5] << 16) | (kPt[6] << 8) | kPt[7]); wPt[2] = (uint)((kPt[8] << 24) | (kPt[9] << 16) | (kPt[10] << 8) | kPt[11]); wPt[3] = (uint)((kPt[12] << 24) | (kPt[13] << 16) | (kPt[14] << 8) | kPt[15]); wPt[4] = 0b10000000_00000000_00000000_00000000U; wPt[5] = 0; wPt[6] = 0; wPt[7] = 0; wPt[8] = 0; // From 9 to 14 remain 0 wPt[15] = 128; sha.Init(hPt); sha.CompressDouble16(hPt, wPt); if ((hPt[0] & mask1) == comp1) { int mIndexInternal = mIndex; do { for (int i = 0; i < missCount2; i++) { int index = mi[mIndex++]; kPt[(index / 2) + 16] |= (index % 2 == 0) ? (byte)(item2[i] << 4) : item2[i]; } wPt[0] = (uint)((kPt[16] << 24) | (kPt[17] << 16) | (kPt[18] << 8) | kPt[19]); wPt[1] = (uint)((kPt[20] << 24) | (kPt[21] << 16) | (kPt[22] << 8) | kPt[23]); wPt[2] = (uint)((kPt[24] << 24) | (kPt[25] << 16) | (kPt[26] << 8) | kPt[27]); wPt[3] = (uint)((kPt[28] << 24) | (kPt[29] << 16) | (kPt[30] << 8) | kPt[31]); wPt[4] = 0b10000000_00000000_00000000_00000000U; wPt[5] = 0; wPt[6] = 0; wPt[7] = 0; wPt[8] = 0; // From 9 to 14 remain 0 wPt[15] = 128; sha.Init(hPt); sha.CompressDouble16(hPt, wPt); if ((hPt[0] & mask2) == comp2) { BigInteger secexp = ComputeKey(sha, hPt, wPt, oPt, kPt); if (comparer.Compare(secexp)) { SetResult(kPt); return; } } // Reset second part for next round *(Block16 *)(kPt + 16) = *(Block16 *)(pre + 16); mIndex = mIndexInternal; } while (MoveNext(item2, missCount2)); // Checking second line reached the end and failed, item2 must be reset to 0 for (int i = 0; i < missCount2; i++) { item2[i] = 0; } } } while (MoveNext(item1, missCount1)); } }
private unsafe bool Loop23() { // The actual data that is changing is 22 bytes (22 char long mini key) with a fixed starting character ('S') // plus an additional byte added to the end (char('?')=0x3f) during checking loop. // Checksum is replaced by checking if first byte of hash result is zero. // The actual key itself is the hash of the same 22 bytes (without '?') using a single SHA256 // Note characters are decoded using UTF-8 var cartesian = CartesianProduct.Create(Enumerable.Repeat(Encoding.UTF8.GetBytes(ConstantsFO.Base58Chars), missCount)); using Sha256Fo sha = new Sha256Fo(); bool success = false; byte[] temp = new byte[precomputed.Length]; fixed(uint *hPt = &sha.hashState[0], wPt = &sha.w[0]) fixed(byte *pre = &precomputed[0], tmp = &temp[0]) fixed(int *mi = &missingIndexes[0]) { foreach (var item in cartesian) { Buffer.MemoryCopy(pre, tmp, 22, 22); int mis = 0; foreach (var keyItem in item) { tmp[mi[mis]] = keyItem; mis++; } // The added value below is the fixed first char(S)=0x53 shifted left 24 places wPt[0] = 0b01010011_00000000_00000000_00000000U | (uint)tmp[1] << 16 | (uint)tmp[2] << 8 | tmp[3]; wPt[1] = (uint)tmp[4] << 24 | (uint)tmp[5] << 16 | (uint)tmp[6] << 8 | tmp[7]; wPt[2] = (uint)tmp[8] << 24 | (uint)tmp[9] << 16 | (uint)tmp[10] << 8 | tmp[11]; wPt[3] = (uint)tmp[12] << 24 | (uint)tmp[13] << 16 | (uint)tmp[14] << 8 | tmp[15]; wPt[4] = (uint)tmp[16] << 24 | (uint)tmp[17] << 16 | (uint)tmp[18] << 8 | tmp[19]; // The added value below is the SHA padding and the last added ? char equal to 0x3f shifted right 8 places wPt[5] = (uint)tmp[20] << 24 | (uint)tmp[21] << 16 | 0b00000000_00000000_00111111_10000000U; // from 6 to 14 = 0 wPt[15] = 184; // 23 *8 = 184 sha.Init(hPt); sha.Compress23(hPt, wPt); if ((hPt[0] & 0b11111111_00000000_00000000_00000000U) == 0) { // The actual key is SHA256 of 22 char key (without '?') // SHA working vector is already set, only the last 2 bytes ('?' and pad) and the length have to change wPt[5] ^= 0b00000000_00000000_10111111_10000000U; // from 6 to 14 (remain) = 0 wPt[15] = 176; // 22 *8 = 176 sha.Init(hPt); sha.Compress22(hPt, wPt); if (comparer.Compare(sha.GetBytes(hPt))) { SetResult(item); success = true; break; } } } } return(success); }