kTimesG
|
 |
June 02, 2025, 08:38:58 AM |
|
I have tested it in a step by step manner. On my machine everything works fine with point_search. And moreover it is just a concept code. As almost everything that can be found in the open-source domain. What is the purpose of your presence here?
That's pretty much how MT bugs present themselves: Heisenbugs that eventually manifest sooner or later. So your code is conceptually broken, even if it passes your tests. Also, are you aware that debugging a MT program is pretty much useless when running concurrent threads, especially if you have breakpoints that are reached one at a time? So of course everything works fine in that scenario, since debugging a concurrent function is basically identical as if running it single-threaded. Tests are not even needed to spot it as a bug. This is simple CS 101. At some point, at some time, you'll have two threads accessing the same bloom filter RAM, and the CPU cache lines will screw up the bloom filter because of R/W lack of sync. Well, my presence here is definitely not to show off broken code to n00bz that think it actually works correctly, while calling other people that know their thing as main-branch BS-ers. See it as you wish, and take from it what you want.
|
Off the grid, training pigeons to broadcast signed messages.
|
|
|
nomachine
|
 |
June 02, 2025, 11:14:18 AM |
|
Guys, have you ever thought that maybe it’s not a piece-by-piece puzzle at all, but simply a quiz? I mean, maybe the creator hid a pattern that could lead us straight to the solution. Has this idea been discussed already? Could you give us some hints, please @saatoshi_rising? We would really appreciate it!
Whoever came up with this Puzzle knows exactly what he's doing. I use a trial-and-error method a problem-solving approach where you systematically try different options or solutions until you find one that works or achieves the desired result. This is like the movie Groundhog Day, about a man reliving the same day over and over again. All puzzles are created with one or similar random, seed - known to the creator. The puzzle creator tattooed it on their upper arm. And there is no pattern. It’s not a timestamp. It can’t be reproduced by going back in time. I think it's obvious that he has his own custom deterministic wallet with errors = ZERO There is no limit and way someone can search for a puzzle. It's like art. Mostly worthless art collection.
|
BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
|
|
|
Akito S. M. Hosana
Jr. Member
Offline
Activity: 392
Merit: 8
|
 |
June 02, 2025, 11:32:22 AM |
|
This is like the movie Groundhog Day, about a man reliving the same day over and over again.
This is absolutely true. It's just that I'm not getting smarter and smarter like the character from the movie. Here is always a groundhog behind the wheel driving down the cliff. Especially with AI experiments. A lost cause. 
|
|
|
|
zion3301
Newbie
Offline
Activity: 8
Merit: 0
|
 |
June 02, 2025, 11:46:22 AM |
|
Guys, have you ever thought that maybe it’s not a piece-by-piece puzzle at all, but simply a quiz? I mean, maybe the creator hid a pattern that could lead us straight to the solution. Has this idea been discussed already? Could you give us some hints, please @saatoshi_rising? We would really appreciate it!
Whoever came up with this Puzzle knows exactly what he's doing. I use a trial-and-error method a problem-solving approach where you systematically try different options or solutions until you find one that works or achieves the desired result. This is like the movie Groundhog Day, about a man reliving the same day over and over again. All puzzles are created with one or similar random, seed - known to the creator. The puzzle creator tattooed it on their upper arm. And there is no pattern. It’s not a timestamp. It can’t be reproduced by going back in time. I think it's obvious that he has his own custom deterministic wallet with errors = ZERO There is no limit and way someone can search for a puzzle. It's like art. Mostly worthless art collection. Thats true. The creator know 100% what he was doing. He constructed the a perfectly ordered transaction after he created consecutive keys and masked them. He also remembered the private keys after two years. He almost forgot about the puzzle and then moved funds from 162-255 to the lower ones. if he used a seed-approach which contains methods like sha2, then there is truely no pattern, as the creator stated. But in my opinion, if he used a seed approach then the seed is anywhere public or accessable. I dont think its truely random, because of the fact, that the creator remembered the private keys after 2 years
|
|
|
|
nomachine
|
 |
June 02, 2025, 12:06:08 PM |
|
if he used a seed-approach which contains methods like sha2, then there is truely no pattern, as the creator stated. But in my opinion, if he used a seed approach then the seed is anywhere public or accessable. I dont think its truely random, because of the fact, that the creator remembered the private keys after 2 years
Here is example: import random import hashlib import base58
for puzzle in range(1, 160): lower = 2 ** (puzzle - 1) upper = (2 ** puzzle) - 1 seed = "SatoshiNakamotoPuzzle" + str(puzzle) random.seed(seed) dec = random.randint(lower, upper) private_key_hex = "%064x" % dec private_key_bytes = bytes.fromhex(private_key_hex) extended_key = b'\x80' + private_key_bytes extended_key += b'\x01' checksum = hashlib.sha256(hashlib.sha256(extended_key).digest()).digest()[:4] wif_bytes = extended_key + checksum wif_compressed = base58.b58encode(wif_bytes).decode() print(f"Puzzle = {puzzle} seed = {seed} wif = {wif_compressed}")
Puzzle = 60 seed = SatoshiNakamotoPuzzle60 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYkwi7gQXBe3k1QZLZ3Z Puzzle = 61 seed = SatoshiNakamotoPuzzle61 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYn9rYCpH1xFmXKYze83 Puzzle = 62 seed = SatoshiNakamotoPuzzle62 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYnqQxQ9uyUTp8A7vUwi Puzzle = 63 seed = SatoshiNakamotoPuzzle63 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYstQ4L2v4VZxu6s83mL Puzzle = 64 seed = SatoshiNakamotoPuzzle64 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qZ6CF5Nc1QqBfAA1Ynme Puzzle = 65 seed = SatoshiNakamotoPuzzle65 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qZCe9JmRWhdKweDYrcZo Puzzle = 66 seed = SatoshiNakamotoPuzzle66 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qZWCKpZnZsCqVzc1f9vt Puzzle = 67 seed = SatoshiNakamotoPuzzle67 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qbeiYkkDLY2iKmA6JS3q Puzzle = 68 seed = SatoshiNakamotoPuzzle68 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qcopt3giY39KjX9pfekV Puzzle = 69 seed = SatoshiNakamotoPuzzle69 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qkTtFZibZ9tNE96yFsjS Puzzle = 70 seed = SatoshiNakamotoPuzzle70 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qqDJuNu7s3FZKtsk9Pn7 Puzzle = 71 seed = SatoshiNakamotoPuzzle71 wif = KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3rBGXpLd8yP9kGu7rqRvw You don’t need anything else, not even a deterministic wallet. Just a Google Doc to save the code, and you’ll have all the WIFs.
|
BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
|
|
|
zion3301
Newbie
Offline
Activity: 8
Merit: 0
|
 |
June 02, 2025, 12:14:50 PM |
|
if he used a seed-approach which contains methods like sha2, then there is truely no pattern, as the creator stated. But in my opinion, if he used a seed approach then the seed is anywhere public or accessable. I dont think its truely random, because of the fact, that the creator remembered the private keys after 2 years
Here is example: import random import hashlib import base58
for puzzle in range(1, 160): lower = 2 ** (puzzle - 1) upper = (2 ** puzzle) - 1 seed = "SatoshiNakamotoPuzzle" + str(puzzle) random.seed(seed) dec = random.randint(lower, upper) private_key_hex = "%064x" % dec private_key_bytes = bytes.fromhex(private_key_hex) extended_key = b'\x80' + private_key_bytes extended_key += b'\x01' checksum = hashlib.sha256(hashlib.sha256(extended_key).digest()).digest()[:4] wif_bytes = extended_key + checksum wif_compressed = base58.b58encode(wif_bytes).decode() print(f"Puzzle = {puzzle} seed = {seed} wif = {wif_compressed}")
You don’t need anything else, not even a deterministic wallet. Just a Google Doc to save the code, and you’ll have all the WIFs. yes thats a kind of determinsitic wallet. you dont even need that line: dec = random.randint(lower, upper) you can also take the sha256 output of the seed. so there are many types of custom deterministic wallets and maaaany possible seed. also the seed itsself dont have to be ascii compatible (human readable). we can input any kind of data om the sha256 methods in hex format
|
|
|
|
Akito S. M. Hosana
Jr. Member
Offline
Activity: 392
Merit: 8
|
 |
June 02, 2025, 12:49:26 PM |
|
Just a Google Doc to save the code, and you’ll have all the WIFs.
Do you think the code is this simple? With a random seed in a document on Google Drive or ? 
|
|
|
|
AlexanderCurl
Jr. Member
Offline
Activity: 43
Merit: 193
|
 |
June 02, 2025, 12:50:26 PM Last edit: June 03, 2025, 08:37:29 PM by AlexanderCurl |
|
I have tested it in a step by step manner. On my machine everything works fine with point_search. And moreover it is just a concept code. As almost everything that can be found in the open-source domain. What is the purpose of your presence here?
That's pretty much how MT bugs present themselves: Heisenbugs that eventually manifest sooner or later. So your code is conceptually broken, even if it passes your tests. Also, are you aware that debugging a MT program is pretty much useless when running concurrent threads, especially if you have breakpoints that are reached one at a time? So of course everything works fine in that scenario, since debugging a concurrent function is basically identical as if running it single-threaded. Tests are not even needed to spot it as a bug. This is simple CS 101. At some point, at some time, you'll have two threads accessing the same bloom filter RAM, and the CPU cache lines will screw up the bloom filter because of R/W lack of sync. Well, my presence here is definitely not to show off broken code to n00bz that think it actually works correctly, while calling other people that know their thing as main-branch BS-ers. See it as you wish, and take from it what you want. Okay. Will break it down to you. Tests for bloomfilter creation were made in terms of final binary image being equal for one thread and multiple threads creation. In both cases the resulting binary image was equal. Of course thanks a lot for spending some amount of your precious time to take a peek at my code. Probably that break_down_to_pow10 function somehow omitted your peek. It namely breaks the number to power of ten decomposition. That way I count the index of a bloomfilter hit. It is a lot of consecutive bloomfilter hits. If any bit was damaged due to not using mutex lock Private key recovering could not be possible. No matter what random scalar i chose, no matter what range, works like a charm on my side. According to you I should smash my PC to pieces for showing right result when it should not. The whole thing is just idea sharing that came from testing even/odd concept. This is not puzzle-solver or some BSGS improved version. If you see ways to improve that concept well be my guest. Every coder should somehow know that checks are nessary where they are really needed. I do not put checks where not necessary. Even JLP did not put (scalar % N) in his ComputePublicKey class method. And lately one starter guy have found out and now thinks he can use that to break secp256k1 curve. Well I tried to explain. But he keeps thinking that way anyway.  .
|
|
|
|
nomachine
|
 |
June 02, 2025, 12:55:14 PM |
|
Just a Google Doc to save the code, and you’ll have all the WIFs.
Do you think the code is this simple? With a random seed in a document on Google Drive or ?  Why would it be more complicated? Everything can die. A USB stick, an SSD, a hard drive, even a hardware wallet. You don’t have to publish the seed publicly, but you can publicly share the code on Git, Pastebin, your email, or Google Drive. Who cares? It’ll still be there 50 years from now. You could even tattoo the seed on your lower leg so you don’t forget. 
|
BTC: bc1qdwnxr7s08xwelpjy3cc52rrxg63xsmagv50fa8
|
|
|
kTimesG
|
 |
June 02, 2025, 03:49:55 PM |
|
Okay. Will break it down to you. Tests for bloomfilter creation were made in terms of final binary image being equal for one thread and multiple threads creation. In both cases the resulting binary image was equal. . Not sure what you're trying to explain, I didn't see a mention that the insert method is thread-safe (that would have been sufficient, but also required). It's your code after all, so I guess when you get burned, you're doing it in a very assumed way. Bugs of these type can show up after executing many trillions of cycles, or instantly, depending on the input. Having identical outputs after thousands of runs means nothing, since the core issue is unaddressed. 
|
Off the grid, training pigeons to broadcast signed messages.
|
|
|
AlexanderCurl
Jr. Member
Offline
Activity: 43
Merit: 193
|
 |
June 02, 2025, 04:56:02 PM Last edit: June 02, 2025, 06:22:30 PM by AlexanderCurl |
|
Okay. Will break it down to you. Tests for bloomfilter creation were made in terms of final binary image being equal for one thread and multiple threads creation. In both cases the resulting binary image was equal. . Not sure what you're trying to explain, I didn't see a mention that the insert method is thread-safe (that would have been sufficient, but also required). It's your code after all, so I guess when you get burned, you're doing it in a very assumed way. Bugs of these type can show up after executing many trillions of cycles, or instantly, depending on the input. Having identical outputs after thousands of runs means nothing, since the core issue is unaddressed.  The bloomfilter binary images are identical for one thread approach and for multiple threads. So what is hard for you to grasp. The two have identical bits in every byte. Mutex locks are necessary when multiple threads read, write and modify the same value. And order of their actions matters. At the beginning all bits of a bloomfilter are off (set to 0). The insert function sets some bit to 1 according to hash_value modulo bloomfilter size. The race condition may happen very often. But which one thread will set the bit to 1 first does not matter. The bit will be set to one as a result. If you are so worried about that feel free to use mutex lock on bloomfilter insert action. It is easy to test when collision situation will happen. But I do not feel it necessary. The whole principle of open-source code is that anyone can download and modify to the extent he desires. Be my guest to present the improved version in your github. But I do not know what for. It is not a puzzle-solver. RetiredC has already shown what is needed for that. Array of GPUS and a SOTA method.  Since I have doubts that someone will ever find what is needed for inverse function to SCALAR_MULTIPLICATION.
|
|
|
|
kTimesG
|
 |
June 03, 2025, 06:07:05 AM Last edit: June 03, 2025, 06:43:08 AM by kTimesG |
|
Mutex locks are necessary when multiple threads read, write and modify the same value. And order of their actions matters.
At the beginning all bits of a bloomfilter are off (set to 0). The insert function sets some bit to 1 according to hash_value modulo bloomfilter size. The race condition may happen very often. But which one thread will set the bit to 1 first does not matter. The bit will be set to one as a result.
Writing a value involves reading the value. You're just ignoring this, and describing a perfect fallacy. When the different bits that need to be written end up on the same cache lines (let's say, in the same 64 bytes region, and a lot of cache lines can fit in L1) of different cores, you have two different results, both wrong, and one of those will end up in your filter. You're not seeing the issue because the allocated area is very large, so the probability of updating nearby bits is low, but a low probability just means it will eventually happen, not that it is impossible to happen.
|
Off the grid, training pigeons to broadcast signed messages.
|
|
|
AlexanderCurl
Jr. Member
Offline
Activity: 43
Merit: 193
|
 |
June 03, 2025, 07:55:11 AM Last edit: June 03, 2025, 08:08:45 AM by AlexanderCurl |
|
Mutex locks are necessary when multiple threads read, write and modify the same value. And order of their actions matters.
At the beginning all bits of a bloomfilter are off (set to 0). The insert function sets some bit to 1 according to hash_value modulo bloomfilter size. The race condition may happen very often. But which one thread will set the bit to 1 first does not matter. The bit will be set to one as a result.
I have tested it up to 67 bits. Not all possibilities but many for each range from 40 bits up to 67 bits. Max 2^32 bloomfilter size. Writing a value involves reading the value. You're just ignoring this, and describing a perfect fallacy. When the different bits that need to be written end up on the same cache lines (let's say, in the same 64 bytes region, and a lot of cache lines can fit in L1) of different cores, you have two different results, both wrong, and one of those will end up in your filter. You're not seeing the issue because the allocated area is very large, so the probability of updating nearby bits is low, but a low probability just means it will eventually happen, not that it is impossible to happen. It is easy to check when two or more threads try to access the same byte/bit to set it to 1 concurrently. The first one I already did. Comparing the resulting binary images to be equal. Since each thread is just a sequence of instructions. We can log each step of its insertion way and compare the results afterwards. To be near or exact, at which step, in what quantity. No need for debugger. For classic BSGS it is much easier since the babyTable is just a sequence from 1 to some power of two value. And I guess for home PC 2^40 or lower is the limit and that is with 256G RAM. What I see good in this is that at least now kTimesG started to write answers as the sane man and not some perverse nutcase.
|
|
|
|
kTimesG
|
 |
June 03, 2025, 09:19:06 AM |
|
Writing a value involves reading the value. Since each thread is just a sequence of instructions. We can log each step of its insertion way and compare the results afterwards. Yeah, but those instructions run in parallel, hence it's guaranteed that, without an access sync, at some point, a r/w race condition will occur. You should know best what'ya doin', so I won't insist. Or are you saying this can never happen: X = 0
Cycle T0 T1 0 read X read X // T0: is X 0 or 32? T1: is X 0 or 8? 1 set x[3] set X[5] // T0: is X 8 or 40? T1: is X 32 or 40? 2 write X write X // what X is final? what about cache lines refresh? 3 X = ???????? // one of 8, 32, or 40
|
Off the grid, training pigeons to broadcast signed messages.
|
|
|
AlexanderCurl
Jr. Member
Offline
Activity: 43
Merit: 193
|
 |
June 03, 2025, 12:24:23 PM Last edit: June 03, 2025, 08:40:04 PM by AlexanderCurl |
|
Writing a value involves reading the value. Since each thread is just a sequence of instructions. We can log each step of its insertion way and compare the results afterwards. Yeah, but those instructions run in parallel, hence it's guaranteed that, without an access sync, at some point, a r/w race condition will occur. You should know best what'ya doin', so I won't insist. Or are you saying this can never happen: X = 0
Cycle T0 T1 0 read X read X // T0: is X 0 or 32? T1: is X 0 or 8? 1 set x[3] set X[5] // T0: is X 8 or 40? T1: is X 32 or 40? 2 write X write X // what X is final? what about cache lines refresh? 3 X = ???????? // one of 8, 32, or 40
It can happen. But in practice I have everything working fine. Bloomfilters due to their multiple use of hash functions to insert one element are sure to hit the same bit in the same byte or different bits in the same byte in multi-threaded context. But no matter how many times I tested this never caused any broken state to the resulting binary image of the bloomfilter file. And concerning my code concept bloomfilter is used excessively to count the decimal places in order to get the index of the bloomfilter hit . That is used later to calculate the private key. If bloomfilter integrity was broken this would never happen. All in all thanks for explanation. Added mutex locks to make sure everything is fine.
|
|
|
|
Nuclearkeys
Newbie
Offline
Activity: 4
Merit: 0
|
 |
June 03, 2025, 09:55:06 PM |
|
3 seconds on PYTHON! PK found.
import math, time, sys, os from gmpy2 import mpz, powmod, invert, jacobi import xxhash from sortedcontainers import SortedDict
# Clear screen and initialize os.system("cls||clear") t = time.ctime() sys.stdout.write(f"\033[?25l\033[01;33m[+] BSGS: {t}\n") sys.stdout.flush()
# Elliptic Curve Parameters (secp256k1) modulo = mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) order = mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141) Gx = mpz(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) Gy = mpz(0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8) PG = (Gx, Gy)
# Point Addition on Elliptic Curve def add(P, Q): if P == (0, 0): return Q if Q == (0, 0): return P Px, Py = P Qx, Qy = Q if Px == Qx: if Py == Qy: inv_2Py = invert((Py << 1) % modulo, modulo) m = (3 * Px * Px * inv_2Py) % modulo else: return (0, 0) else: inv_diff_x = invert(Qx - Px, modulo) m = ((Qy - Py) * inv_diff_x) % modulo x = (m * m - Px - Qx) % modulo y = (m * (Px - x) - Py) % modulo return (x, y)
# Scalar Multiplication on Elliptic Curve def mul(k, P=PG): R0, R1 = (0, 0), P for i in reversed(range(k.bit_length())): if (k >> i) & 1: R0, R1 = add(R0, R1), add(R1, R1) else: R1, R0 = add(R0, R1), add(R0, R0) return R0
# Point Subtraction def point_subtraction(P, Q): Q_neg = (Q[0], (-Q[1]) % modulo) return add(P, Q_neg)
# Compute Y from X using curve equation def X2Y(X, y_parity, p=modulo): X3_7 = (pow(X, 3, p) + 7) % p if jacobi(X3_7, p) != 1: return None Y = powmod(X3_7, (p + 1) >> 2, p) return Y if (Y & 1) == y_parity else (p - Y)
# Convert point to compressed public key def point_to_cpub(point): x, y = point y_parity = y & 1 prefix = '02' if y_parity == 0 else '03' compressed_pubkey = prefix + format(x, '064x') return compressed_pubkey
# Hash a compressed public key using xxhash and store only the first 8 characters def hash_cpub(cpub): return xxhash.xxh64(cpub.encode()).hexdigest()[:8]
# Main Script if __name__ == "__main__": # Puzzle Parameters puzzle = 40 start_range, end_range = 2**(puzzle-1), (2**puzzle) - 1 puzzle_pubkey = '03a2efa402fd5268400c77c20e574ba86409ededee7c4020e4b9f0edbee53de0d4'
# Parse Public Key if len(puzzle_pubkey) != 66: print("[error] Public key length invalid!") sys.exit(1) prefix = puzzle_pubkey[:2] X = mpz(int(puzzle_pubkey[2:], 16)) y_parity = int(prefix) - 2 Y = X2Y(X, y_parity) if Y is None: print("[error] Invalid compressed public key!") sys.exit(1) P = (X, Y) # Uncompressed public key
# Precompute m and mP for BSGS m = int(math.floor(math.sqrt(end_range - start_range))) m_P = mul(m)
# Create Baby Table with SortedDict print('[+] Creating babyTable...') baby_table = SortedDict() Ps = (0, 0) # Start with the point at infinity for i in range(m + 1): cpub = point_to_cpub(Ps) cpub_hash = hash_cpub(cpub) # Use xxhash and store only 8 characters baby_table[cpub_hash] = i # Store the hash as the key and index as the value Ps = add(Ps, PG) # Incrementally add PG
# BSGS Search print('[+] BSGS Search in progress') S = point_subtraction(P, mul(start_range)) step = 0 st = time.time() while step < (end_range - start_range): cpub = point_to_cpub(S) cpub_hash = hash_cpub(cpub) # Hash the current compressed public key # Check if the hash exists in the baby_table if cpub_hash in baby_table: b = baby_table[cpub_hash] k = start_range + step + b if point_to_cpub(mul(k)) == puzzle_pubkey: print(f'[+] m={m} step={step} b={b}') print(f'[+] Key found: {k}') print("[+] Time Spent : {0:.2f} seconds".format(time.time() - st)) sys.exit() S = point_subtraction(S, m_P) step += m
print('[+] Key not found') print("[+] Time Spent : {0:.2f} seconds".format(time.time() - st)) puzzle 40 - BSGS: Thu Feb 20 21:49:30 2025
- Creating babyTable...
- BSGS Search in progress
- m=741455 step=453895024440 b=574622
- Key found: 1003651412950
- Time Spent : 2.90 seconds
puzzle 50 - BSGS: Thu Feb 20 22:13:12 2025
- Creating babyTable...
- BSGS Search in progress
- m=23726566 step=48190529944714 b=12801738
- Key found: 611140496167764
- Time Spent : 12.71 seconds
This is the result... on a single core  P.S. For puzzles above 50, you'll need a Bloom Filter Who wrote this code?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Share your donation address I can see light at the end of a tunnel.
|
|
|
|
cctv5go
Newbie
Offline
Activity: 48
Merit: 0
|
 |
June 04, 2025, 12:05:25 AM |
|
Does anyone know who the author of the puzzle is?JPL?…
|
|
|
|
|
Frequence
Jr. Member
Offline
Activity: 35
Merit: 2
|
 |
June 04, 2025, 12:49:30 AM |
|
3 seconds on PYTHON! PK found.
import math, time, sys, os from gmpy2 import mpz, powmod, invert, jacobi import xxhash from sortedcontainers import SortedDict
# Clear screen and initialize os.system("cls||clear") t = time.ctime() sys.stdout.write(f"\033[?25l\033[01;33m[+] BSGS: {t}\n") sys.stdout.flush()
# Elliptic Curve Parameters (secp256k1) modulo = mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) order = mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141) Gx = mpz(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) Gy = mpz(0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8) PG = (Gx, Gy)
# Point Addition on Elliptic Curve def add(P, Q): if P == (0, 0): return Q if Q == (0, 0): return P Px, Py = P Qx, Qy = Q if Px == Qx: if Py == Qy: inv_2Py = invert((Py << 1) % modulo, modulo) m = (3 * Px * Px * inv_2Py) % modulo else: return (0, 0) else: inv_diff_x = invert(Qx - Px, modulo) m = ((Qy - Py) * inv_diff_x) % modulo x = (m * m - Px - Qx) % modulo y = (m * (Px - x) - Py) % modulo return (x, y)
# Scalar Multiplication on Elliptic Curve def mul(k, P=PG): R0, R1 = (0, 0), P for i in reversed(range(k.bit_length())): if (k >> i) & 1: R0, R1 = add(R0, R1), add(R1, R1) else: R1, R0 = add(R0, R1), add(R0, R0) return R0
# Point Subtraction def point_subtraction(P, Q): Q_neg = (Q[0], (-Q[1]) % modulo) return add(P, Q_neg)
# Compute Y from X using curve equation def X2Y(X, y_parity, p=modulo): X3_7 = (pow(X, 3, p) + 7) % p if jacobi(X3_7, p) != 1: return None Y = powmod(X3_7, (p + 1) >> 2, p) return Y if (Y & 1) == y_parity else (p - Y)
# Convert point to compressed public key def point_to_cpub(point): x, y = point y_parity = y & 1 prefix = '02' if y_parity == 0 else '03' compressed_pubkey = prefix + format(x, '064x') return compressed_pubkey
# Hash a compressed public key using xxhash and store only the first 8 characters def hash_cpub(cpub): return xxhash.xxh64(cpub.encode()).hexdigest()[:8]
# Main Script if __name__ == "__main__": # Puzzle Parameters puzzle = 40 start_range, end_range = 2**(puzzle-1), (2**puzzle) - 1 puzzle_pubkey = '03a2efa402fd5268400c77c20e574ba86409ededee7c4020e4b9f0edbee53de0d4'
# Parse Public Key if len(puzzle_pubkey) != 66: print("[error] Public key length invalid!") sys.exit(1) prefix = puzzle_pubkey[:2] X = mpz(int(puzzle_pubkey[2:], 16)) y_parity = int(prefix) - 2 Y = X2Y(X, y_parity) if Y is None: print("[error] Invalid compressed public key!") sys.exit(1) P = (X, Y) # Uncompressed public key
# Precompute m and mP for BSGS m = int(math.floor(math.sqrt(end_range - start_range))) m_P = mul(m)
# Create Baby Table with SortedDict print('[+] Creating babyTable...') baby_table = SortedDict() Ps = (0, 0) # Start with the point at infinity for i in range(m + 1): cpub = point_to_cpub(Ps) cpub_hash = hash_cpub(cpub) # Use xxhash and store only 8 characters baby_table[cpub_hash] = i # Store the hash as the key and index as the value Ps = add(Ps, PG) # Incrementally add PG
# BSGS Search print('[+] BSGS Search in progress') S = point_subtraction(P, mul(start_range)) step = 0 st = time.time() while step < (end_range - start_range): cpub = point_to_cpub(S) cpub_hash = hash_cpub(cpub) # Hash the current compressed public key # Check if the hash exists in the baby_table if cpub_hash in baby_table: b = baby_table[cpub_hash] k = start_range + step + b if point_to_cpub(mul(k)) == puzzle_pubkey: print(f'[+] m={m} step={step} b={b}') print(f'[+] Key found: {k}') print("[+] Time Spent : {0:.2f} seconds".format(time.time() - st)) sys.exit() S = point_subtraction(S, m_P) step += m
print('[+] Key not found') print("[+] Time Spent : {0:.2f} seconds".format(time.time() - st)) puzzle 40 - BSGS: Thu Feb 20 21:49:30 2025
- Creating babyTable...
- BSGS Search in progress
- m=741455 step=453895024440 b=574622
- Key found: 1003651412950
- Time Spent : 2.90 seconds
puzzle 50 - BSGS: Thu Feb 20 22:13:12 2025
- Creating babyTable...
- BSGS Search in progress
- m=23726566 step=48190529944714 b=12801738
- Key found: 611140496167764
- Time Spent : 12.71 seconds
This is the result... on a single core  P.S. For puzzles above 50, you'll need a Bloom Filter Who wrote this code?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Share your donation address I can see light at the end of a tunnel. Yes, I agree that NoMachine is great for coding, but did you know it only works if you have a public key!!? That’s clearly tied to the current puzzles. Also, there's a better option from RC that uses GPU. Regards.
|
|
|
|
Vilandro
Newbie
Offline
Activity: 3
Merit: 0
|
 |
June 04, 2025, 05:03:52 AM |
|
Does anyone know who the author of the puzzle is?JPL?…
Adam Back
|
|
|
|
|