@@ -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 {
0 commit comments