Skip to content

Commit 098cef1

Browse files
Add new feature: find missing characters in a base-58 encoded BIP-38 (encrypted private key)
1 parent 8f12d94 commit 098cef1

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

Src/FinderOuter/Services/Base58Sevice.cs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public enum InputType
4141
{
4242
PrivateKey,
4343
Address,
44+
Bip38
4445
//MiniPrivateKey
4546
}
4647

@@ -53,6 +54,7 @@ private void Initialize(char[] key, char missingChar, InputType keyType)
5354
{
5455
InputType.PrivateKey => 10, // Maximum result (58^52) is 39 bytes = 39/4 = 10 uint
5556
InputType.Address => 7, // Maximum result (58^35) is 26 bytes = 26/4 = 7 uint
57+
InputType.Bip38 => 11, // Maximum result (58^58) is 43 bytes = 43/4 = 11 uint
5658
_ => throw new ArgumentException("Input type is not defined yet."),
5759
};
5860
powers58 = new uint[key.Length * uLen];
@@ -484,6 +486,60 @@ private void SetAddrResult(IEnumerable<int> item)
484486
});
485487
}
486488

489+
private unsafe bool Loop58()
490+
{
491+
var cartesian = CartesianProduct.Create(Enumerable.Repeat(Enumerable.Range(0, 58), missCount));
492+
493+
bool success = false;
494+
495+
uint[] temp = new uint[precomputed.Length];
496+
fixed (uint* hPt = &sha.hashState[0], wPt = &sha.w[0])
497+
fixed (uint* pow = &powers58[0], res = &precomputed[0], tmp = &temp[0])
498+
fixed (int* mi = &missingIndexes[0])
499+
{
500+
foreach (var item in cartesian)
501+
{
502+
Buffer.MemoryCopy(res, tmp, 44, 44);
503+
int mis = 0;
504+
foreach (var keyItem in item)
505+
{
506+
ulong carry = 0;
507+
for (int k = 10, j = 0; k >= 0; k--, j++)
508+
{
509+
ulong result = (pow[(mi[mis] * 11) + j] * (ulong)keyItem) + tmp[k] + carry;
510+
tmp[k] = (uint)result;
511+
carry = (uint)(result >> 32);
512+
}
513+
mis++;
514+
}
515+
516+
wPt[0] = (tmp[0] << 8) | (tmp[1] >> 24);
517+
wPt[1] = (tmp[1] << 8) | (tmp[2] >> 24);
518+
wPt[2] = (tmp[2] << 8) | (tmp[3] >> 24);
519+
wPt[3] = (tmp[3] << 8) | (tmp[4] >> 24);
520+
wPt[4] = (tmp[4] << 8) | (tmp[5] >> 24);
521+
wPt[5] = (tmp[5] << 8) | (tmp[6] >> 24);
522+
wPt[6] = (tmp[6] << 8) | (tmp[7] >> 24);
523+
wPt[7] = (tmp[7] << 8) | (tmp[8] >> 24);
524+
wPt[8] = (tmp[8] << 8) | (tmp[9] >> 24);
525+
wPt[9] = (tmp[9] << 8) | 0b00000000_00000000_00000000_10000000U;
526+
// from 10 to 14 = 0
527+
wPt[15] = 312; // 39 *8 = 168
528+
529+
sha.Init(hPt);
530+
sha.CompressDouble39(hPt, wPt);
531+
532+
if (hPt[0] == tmp[10])
533+
{
534+
SetAddrResult(item);
535+
success = true;
536+
}
537+
}
538+
}
539+
540+
return success;
541+
}
542+
487543

488544

489545
public async Task<bool> FindUnknownLocation3(string key)
@@ -670,6 +726,56 @@ private async Task<bool> FindAddress(string address, char missingChar)
670726
return success;
671727
}
672728

729+
private async Task<bool> FindBip38(string bip38, char missingChar)
730+
{
731+
missCount = bip38.Count(c => c == missingChar);
732+
if (missCount == 0)
733+
{
734+
AddQueue("The given BIP38 key has no missing characters, verifying it as a complete key.");
735+
AddQueue(inputService.CheckBase58Bip38(bip38));
736+
return true;
737+
}
738+
739+
bool success = false;
740+
if (!bip38.StartsWith(ConstantsFO.Bip38Start))
741+
{
742+
AddQueue($"Base-58 encoded BIP-38 should start with {ConstantsFO.Bip38Start}.");
743+
return false;
744+
}
745+
else if (bip38.Length != ConstantsFO.Bip38Base58Len)
746+
{
747+
AddQueue($"Base-58 encoded BIP-38 length must be between {ConstantsFO.Bip38Base58Len}.");
748+
return false;
749+
}
750+
else
751+
{
752+
keyToCheck = bip38;
753+
missingIndexes = new int[missCount];
754+
Initialize(bip38.ToCharArray(), missingChar, InputType.Bip38);
755+
756+
Stopwatch watch = Stopwatch.StartNew();
757+
758+
success = await Task.Run(() =>
759+
{
760+
AddQueue($"Total number of addresses to test: {GetTotalCount(missCount):n0}");
761+
AddQueue("Going throgh each case. Please wait...");
762+
return Loop58();
763+
}
764+
);
765+
766+
watch.Stop();
767+
AddQueue($"Elapsed time: {watch.Elapsed}");
768+
AddQueue(GetKeyPerSec(GetTotalCount(missCount), watch.Elapsed.TotalSeconds));
769+
}
770+
771+
if (!success)
772+
{
773+
AddQueue("Couldn't find any valid addresses with the given input.");
774+
}
775+
776+
return success;
777+
}
778+
673779
public async Task<bool> Find(string key, char missingChar, InputType t)
674780
{
675781
InitReport();
@@ -688,6 +794,9 @@ public async Task<bool> Find(string key, char missingChar, InputType t)
688794
case InputType.Address:
689795
success = await FindAddress(key, missingChar);
690796
break;
797+
case InputType.Bip38:
798+
success = await FindBip38(key, missingChar);
799+
break;
691800
default:
692801
return Fail("Given input type is not defined.");
693802
}

0 commit comments

Comments
 (0)