Skip to content

Commit 884c50d

Browse files
Add the additional check part to MiniKey to only report the correct key result instead of all of them
1 parent b5891e5 commit 884c50d

File tree

3 files changed

+59
-32
lines changed

3 files changed

+59
-32
lines changed

Src/FinderOuter/Services/MiniKeyService.cs

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class MiniKeyService
2121
public MiniKeyService(IReport rep)
2222
{
2323
inputService = new InputService();
24+
comparer = new PrivateKeyToAddressComparer();
2425
report = rep;
2526
}
2627

@@ -31,6 +32,7 @@ public MiniKeyService(IReport rep)
3132
private int[] missingIndexes;
3233
private int missCount;
3334
private string keyToCheck;
35+
private ICompareService comparer;
3436

3537

3638
private BigInteger GetTotalCount(int missCount) => BigInteger.Pow(58, missCount);
@@ -46,29 +48,28 @@ private void SetResult(IEnumerable<byte> item)
4648
temp[missingIndexes[i++]] = (char)index;
4749
}
4850

49-
report.AddMessageSafe($"Found a possible result (still running): {new string(temp)}");
51+
report.AddMessageSafe($"Found a possible result: {new string(temp)}");
5052
return;
5153
});
5254
}
5355

5456
private unsafe bool Loop23()
5557
{
56-
// The actual data that is changing is 22 bytes (22 char long mini key)
57-
// plus an additional byte added to the end (char(?)=0x3f).
58+
// The actual data that is changing is 22 bytes (22 char long mini key) with a fixed starting character ('S')
59+
// plus an additional byte added to the end (char('?')=0x3f) during checking loop.
5860
// Checksum is replaced by checking if first byte of hash result is zero.
61+
// The actual key itself is the hash of the same 22 bytes (without '?') using a single SHA256
62+
// Note characters are decoded using UTF-8
5963

6064
var cartesian = CartesianProduct.Create(Enumerable.Repeat(Encoding.UTF8.GetBytes(ConstantsFO.Base58Chars), missCount));
6165
using Sha256 sha = new Sha256();
62-
uint[] secondW = new uint[sha.w.Length];
6366
bool success = false;
6467

6568
byte[] temp = new byte[precomputed.Length];
66-
fixed (uint* hPt = &sha.hashState[0], wPt = &sha.w[0], w2Pt = &secondW[0])
69+
fixed (uint* hPt = &sha.hashState[0], wPt = &sha.w[0])
6770
fixed (byte* pre = &precomputed[0], tmp = &temp[0])
6871
fixed (int* mi = &missingIndexes[0])
6972
{
70-
wPt[15] = 184; // 23 *8 = 184
71-
7273
foreach (var item in cartesian)
7374
{
7475
Buffer.MemoryCopy(pre, tmp, 22, 22);
@@ -88,18 +89,28 @@ private unsafe bool Loop23()
8889
// The added value below is the SHA padding and the last added ? char equal to 0x3f shifted right 8 places
8990
wPt[5] = (uint)tmp[20] << 24 | (uint)tmp[21] << 16 | 0b00000000_00000000_00111111_10000000U;
9091
// from 6 to 14 = 0
91-
// 15 is already set above
92+
wPt[15] = 184; // 23 *8 = 184
9293

9394
sha.Init(hPt);
9495
sha.Compress23(hPt, wPt);
9596

9697
if ((hPt[0] & 0b11111111_00000000_00000000_00000000U) == 0)
9798
{
98-
// TODO: perform another hash using the same wPt but change the char(?) value to SHA pad and
99-
// prev SHA pad to zero
100-
// this will give the actual 32 bytes key then perform the checks versus address,...
101-
SetResult(item);
102-
success = true;
99+
// The actual key is SHA256 of 22 char key (without '?')
100+
// SHA working vector is already set, only the last 2 bytes ('?' and pad) and the length have to change
101+
wPt[5] ^= 0b00000000_00000000_10111111_10000000U;
102+
// from 6 to 14 (remain) = 0
103+
wPt[15] = 176; // 22 *8 = 176
104+
105+
sha.Init(hPt);
106+
sha.Compress22(hPt, wPt);
107+
108+
if (comparer.Compare(sha.GetBytes(hPt)))
109+
{
110+
SetResult(item);
111+
success = true;
112+
break;
113+
}
103114
}
104115
}
105116
}
@@ -112,16 +123,13 @@ private unsafe bool Loop31()
112123
{
113124
var cartesian = CartesianProduct.Create(Enumerable.Repeat(Encoding.UTF8.GetBytes(ConstantsFO.Base58Chars), missCount));
114125
using Sha256 sha = new Sha256();
115-
uint[] secondW = new uint[sha.w.Length];
116126
bool success = false;
117127

118128
byte[] temp = new byte[precomputed.Length];
119-
fixed (uint* hPt = &sha.hashState[0], wPt = &sha.w[0], w2Pt = &secondW[0])
129+
fixed (uint* hPt = &sha.hashState[0], wPt = &sha.w[0])
120130
fixed (byte* pre = &precomputed[0], tmp = &temp[0])
121131
fixed (int* mi = &missingIndexes[0])
122132
{
123-
wPt[15] = 248; // 31 *8 = 184
124-
125133
foreach (var item in cartesian)
126134
{
127135
Buffer.MemoryCopy(pre, tmp, 30, 30);
@@ -143,16 +151,27 @@ private unsafe bool Loop31()
143151
// The added value below is the SHA padding and the last added ? char equal to 0x3f shifted right 8 places
144152
wPt[7] = (uint)tmp[28] << 24 | (uint)tmp[29] << 16 | 0b00000000_00000000_00111111_10000000U;
145153
// from 8 to 14 = 0
146-
// 15 is already set above
154+
wPt[15] = 248; // 31 *8 = 184
147155

148156
sha.Init(hPt);
149157
sha.Compress31(hPt, wPt);
150158

151159
if ((hPt[0] & 0b11111111_00000000_00000000_00000000U) == 0)
152160
{
153-
// TODO: same as above
154-
SetResult(item);
155-
success = true;
161+
// Same as above
162+
wPt[7] ^= 0b00000000_00000000_10111111_10000000U;
163+
// from 8 to 14 (remain) = 0
164+
wPt[15] = 240; // 30 *8 = 240
165+
166+
sha.Init(hPt);
167+
sha.Compress30(hPt, wPt);
168+
169+
if (comparer.Compare(sha.GetBytes(hPt)))
170+
{
171+
SetResult(item);
172+
success = true;
173+
break;
174+
}
156175
}
157176
}
158177
}
@@ -172,6 +191,11 @@ public async Task<bool> Find(string key, string extra, char missingChar)
172191
if (!key.StartsWith(ConstantsFO.MiniKeyStart))
173192
return report.Fail($"Minikey must start with {ConstantsFO.MiniKeyStart}.");
174193

194+
if (!((PrivateKeyToAddressComparer)comparer).TrySetHash(extra))
195+
{
196+
return report.Fail("Invalid address.");
197+
}
198+
175199
missCount = key.Count(c => c == missingChar);
176200
if (missCount == 0)
177201
{

Src/FinderOuter/ViewModels/MissingMiniPrivateKeyViewModel.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ public MissingMiniPrivateKeyViewModel()
1818
miniService = new MiniKeyService(Result);
1919

2020
IObservable<bool> isFindEnabled = this.WhenAnyValue(
21-
x => x.Input, x => x.MissingChar,
22-
x => x.Result.CurrentState, (b58, c, state) =>
23-
!string.IsNullOrEmpty(b58) &&
21+
x => x.Input,
22+
x => x.ExtraInput,
23+
x => x.MissingChar,
24+
x => x.Result.CurrentState, (miniKey, addr, c, state) =>
25+
!string.IsNullOrEmpty(miniKey) &&
26+
!string.IsNullOrEmpty(addr) &&
2427
inServ.IsMissingCharValid(c) &&
2528
state != Models.State.Working);
2629

@@ -29,7 +32,12 @@ public MissingMiniPrivateKeyViewModel()
2932

3033
public override string OptionName => "Missing mini private key";
3134

32-
public override string Description => "This option can recover missing characters in a mini private key.";
35+
public override string Description =>
36+
$"This option can recover missing characters in a mini private key." +
37+
$"{Environment.NewLine}" +
38+
$"Enter the mini key (22 or 30 characters long starting with S) in first box while replacing its missing " +
39+
$"characters with the specified {nameof(MissingChar)} and enter the " +
40+
$"corresponding address in second box and click Find button.";
3341

3442

3543
private readonly MiniKeyService miniService;

Src/FinderOuter/Views/MissingMiniPrivateKeyView.xaml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</Design.DataContext>
1111

1212
<Grid ColumnDefinitions="*,auto" RowDefinitions="*,auto">
13-
<TextBox Text="{Binding Input}" Watermark="Base-58 encoded string" UseFloatingWatermark="True"
13+
<TextBox Text="{Binding Input}" Watermark="Mini-private-key (22 or 30 characters long)" UseFloatingWatermark="True"
1414
TextWrapping="Wrap"
1515
Margin="3" Grid.Column="0" Grid.Row="0"/>
1616

@@ -20,14 +20,9 @@
2020
Height="38" Width="40" Margin="3"/>
2121
</StackPanel>
2222

23-
<TextBox Text="{Binding ExtraInput}" Watermark="Extra input to check against (Public key or address)"
23+
<TextBox Text="{Binding ExtraInput}" Watermark="Extra input to check against (address)"
2424
UseFloatingWatermark="True"
2525
Margin="3" Grid.Column="0" Grid.Row="1"/>
2626

27-
<StackPanel Orientation="Vertical" Spacing="5" Margin="3" Grid.Column="1" Grid.Row="1">
28-
<TextBlock Text="Input type:" HorizontalAlignment="Center" Margin="0,10,0,0"/>
29-
<DropDown Items="{Binding InputTypeList}" SelectedItem="{Binding SelectedInputType}"/>
30-
</StackPanel>
31-
3227
</Grid>
3328
</UserControl>

0 commit comments

Comments
 (0)