@@ -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