Dealing with partial WIFs and missing parts

6 replies 103 views
RogueMoonFull Member
Posts: 110 · Reputation: 789
#1Jan 22, 2024, 01:20 PM
I wanted to kick off this discussion to ask and share some of my experiences regarding those weird cases of WIF where certain characters are missing. Here's an example of how I tackle it: - First, I brute force the initial 4 missing characters. - Then I employ BSGS to figure out the second part with 6 missing characters. - Finally, I mix things up using both brute force and BSGS to address everything at once. For you, PawGo, this might resemble your hybrid approach with some tweaks (not specifically for this case, but there could be some useful ideas here). So my question is, how quickly can public programs tackle this using a CPU? I whipped up a single-threaded script that could use a lot of enhancements. It managed to solve this in about 3 hours, but keep in mind it's not a general solution; it needs to be customized for each situation. Oh, and just a note: if you have the public key, you can solve 10, 11, or 12 missing characters at the start in just minutes with a CPU. Without the public key, though, it's virtually impossible. I might be overlooking something, and I wonder if there's a way to handle this specific issue in a simpler or faster manner.
5 Reply Quote Share
gw3i1337Full Member
Posts: 148 · Reputation: 495
#2Jan 22, 2024, 04:38 PM
The problem with middle part is that any change has impact on checksum and compression flag. And that's good! Try to increment 6 characters and see if they produce correct flag 01. It would give you a subset of correct possibilities (not 58^6). PS: I work on migrating WifSolver to CUDA, early beta version will be available soon (today/tomorrow).
3 Reply Quote Share
RogueMoonFull Member
Posts: 110 · Reputation: 789
#3Jan 22, 2024, 08:33 PM
Yes you are right, seems if i implement the correct increment i can solve this in less than half hour with CPU even less i need to make some test L1dU1111d4NTd71111116zCyXqGyWXhXTa16dNWXZs7cpdk6en2t 80 8391fe958e6543b739b52db45eb396b672fc42d48472ee321f50b150cd4f8c33 84 07d5b039 L1dU1111d4NTd7zzzzzz6zCyXqGyWXhXTa16dNWXZs7cpdk6en2t 80 8391fe958e6543b73a1667b0dbc3b3c8fe91fb939a818d5e0f8de094de4432a7 43 07d5b039 I'm solving the 6 missing chars with BSGS and that part is solved instantly and doesn't matter if the byte encode is over written or not, but maybe i can do that part faster with your hint
5 Reply Quote Share
RogueMoonFull Member
Posts: 110 · Reputation: 789
#4Jan 22, 2024, 09:38 PM
I try to find an easy/faster/efficient way to get what is the next valid WIF in this case finding the next 01 in the Encode byte, but seems that it require more operations that my current method, so i will pass that approach. PawGo if you know an easy way to calculate it please tell us. NOW I will post here one example of what I'm doing in my program, step by step and i will show you guys the public key operations that i do to the public key in order to get a new "Transformed Public key" and how i solve the problem with that new public key. The target public key is: Lets to suppose that the only missing characters are the second chunk of 6 characters at the middle. I know that the key is not there, but lets to suppose that for the first example and at the end i will show you the real location and how to solve it with keyhunt. (Since you already know how to solve it with bitcrack and kangaroo). So lets to calculate the start range and the End range for this example: If we remove the Encode bytes and the check sum the range in hexadecimal is: So if we are sure that the target public key is there we can  assume that the private key start by: Lets to call it "Base Private key" It's public key is: In that case we can substract to our target public key the value of the base publickey: Call the Result "PublickeyStep1" Now, as PawGo mention in this post and others of his post the problem with middle missing characters is tha they usually overwrite the encode byte 01 and others (not this case) the checksum part. In this case the full base58 stride is: If we see the hexadecimal part the last 4 bytes (8 hexadecimal characters) are 0 so in this case the Checksum is not overwritten so we can remove those not overwritten bytes and work only with the encode byte overwritten. New Stride hex: So, to work with our actual public key "PublickeyStep1" we need to add to it one extra byte, this can be done multiplying it by 256 Call the Result: PublickeyStep2 Also we need add 1 to the PublickeyStep2 because we expected that the valid Target (Unknow Private key) have an 0x01 value in the Encode byte Call the Result: PublickeyStep3 Now with that extra byte set to ONE we can work with the current stride. You remember that we substract to the target publickey the "Base Public key" value? well now is time to subtract to the "PublickeyStep3" the value of the remainder of the of the base publickey in this case is the value of: Please check the value include the extra encode byte, but with the overwritten value 0x84 Call the result PublickeyStep4, I know, is getting a little complicated to follow, but it is only because the results are publickey in a ECC Operations and those operations are not in our day to day. Now if the partial WIF is valid, I can guaranty you that the "PublickeyStep4" is perfectly divisible by our stride. This result is now our Expected "Transformed Public key" and it will be in the range from 1 to 58^6 1 to 38068692544 or in hexadecimal from 0x01 to 0x08DD122640 that is 36 bits and it can solve instantly with almost all the programs mentioned above. Summary: PublickeyStep1 = Target Public key - Base Public key (This last value change if we change the original first 4 missing characters) PublickeyStep2 =  PublickeyStep1 x 256 (This part add and extra "blank byte to the current public key") PublickeyStep3 =  PublickeyStep2 +1 (We add the public key of G to the current public key) PublickeyStep4 =  PublickeyStep3 - Base Public key remainder with extra overwritten byte Transformed Public key = PublickeyStep4  / Stride Real example: Now we find the Transformed Public key with any of our tools in the range from  0x01 to 0x08DD122640 In case of found one of those public keys you only need to do the inverse Operations in reverse way in order to get the Target privatekey PrivatekeyStep4 = Transformed Privatekey x Stride PrivatekeyStep3 = PrivatekeyStep4 + Base Private key remainder with extra overwritten byte PrivatekeyStep2 = PrivatekeyStep3 - 1 PrivatekeyStep1 = PrivatekeyStep3 / 256 Target Privatekey = PrivatekeyStep1 + Base Private key Obviously this need to be automatically to avoid errors, also remember that the first missing part is 4 characters length, this mean that we need to repeat all those operations almost 58^4 times this is 11316496 times
2 Reply Quote Share
gw3i1337Full Member
Posts: 148 · Reputation: 495
#5Jan 22, 2024, 10:47 PM
Yes, I was interested in that subject. I based one of my algorithms on that, but at the end I concluded it is not 100% sure solution and abandoned that. I have tried to calculate the step which would produce the correct checksum. The problem I found was that it works only for missing characters on very limited range (close to limit which changes stride, I do not remember exactly but I had good results for range 2-3 characters to the right of character which stops changing checksum). If I moved right, I was not able to find the stable jump. In my post https://bitcointalk.org/index.php?topic=5265788.msg54905327#msg54905327 I showed the example where I was able to find the proper jump, but then I realized that method is not 100% sure and I did not work on that anymore.
4 Reply Quote Share
colddiamondHero Member
Posts: 623 · Reputation: 2467
#6Jan 23, 2024, 12:31 AM
Hello! Can you please tell if some news here about how to solve split-key where is 2 blocks Example : L****9****fFfVQU5uie8xmdSisUd8ESWaf956kM8wKAkc48o9nz  with your Kangaroo-stride or something?
0 Reply Quote Share
paul.ninjaFull Member
Posts: 152 · Reputation: 539
#7Jan 23, 2024, 05:11 AM
This is an interesting problem, but I’d separate the encoding problem from the key-recovery problem right away. WIF is just an encoded container. Once you decode the WIF, what you are dealing with is the version byte, the 32-byte private key, possibly the compressed-key marker, and then the 4-byte Base58Check checksum derived from the payload. The Base58 text is only the outer representation, so a one-character change there usually shifts the decoded integer rather than neatly flipping one private-key byte. If the real public key is known, then the EC subtraction approach can make sense. You can build the known scalar contribution, subtract its public point from the target public key, and reduce the unknown part to a smaller search. For one clean missing range, kangaroo or BSGS may be useful. For two separate missing sections, it becomes more like a meet-in-the-middle problem unless you can express the unknown part as one interval. The key detail is whether you have the public key itself, not merely the resulting address. With only a P2PKH or P2WPKH address, and no revealed public key on-chain, there is no known curve point available for that subtraction step. Then you are stuck generating candidates, checking the Base58Check checksum, deriving the public key, hashing it, and comparing the resulting address. The checksum helps, but only as a filter. It removes bad candidates quickly, especially if the missing characters touch the checksum area, but it does not make the elliptic-curve problem easier. SHA256 is not linear, so you cannot smoothly combine checksum logic with EC subtraction. The clean way to attack this is to decode the known WIF positions into exact integer ranges, handle compressed versus uncompressed WIF correctly, make sure the scalar is in 1..n-1, use EC math only on the actual private-key portion, and then use Base58Check validation at the end. For six missing Base58 characters, plain brute force may still be reasonable if the code is efficient. Once the missing part gets larger or split into awkward positions, then the EC math starts becoming worth the trouble. The safest way to reason about it is to keep WIF encoding, checksum filtering, and secp256k1 scalar math in their own boxes. They interact, but they should not be treated as one interchangeable operation.
3 Reply Quote Share
?Reply
Sign in to reply to this topic

Related topics