Search content
Sort by

Showing 7 of 7 results by drpxxx
Post
Topic
Board Development & Technical Discussion
Re: Solving ECDLP with Kangaroos: Part 1 + 2 + RCKangaroo
by
drpxxx
on 04/05/2025, 09:09:09 UTC
...I saw that you have discovered the key to puzzle 69...

Great.
I did not solve #69. Moreover, I never searched for low-level puzzles and I'm not going to do it in the future.
Now crack #135 my only hope is your mini puzzles Cheesy
Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
drpxxx
on 03/05/2025, 13:10:57 UTC
What if someone proves that no such method exists including the prefix one, is the bounty valid for such proof ?

I doubt it, since you'd simply prove that something is, by its own definition, as true. A really hard thing to prove indeed, requiring vast amounts of funding and research, in order to get to a definitive conclusion (e.g. reaching the definitions we started with). But while we're at it, let's also prove these stringent problems which also have no definitive answer so far:

- is the sky really blue? it may look more like white; and why does it go black during the night?
- does free will actually exist, or are we living in a simulation of a type 7 civilization, living in a simulation of a type 42 civilization?
- can we live forever? seems like we die at some point, makes no sense;
- does light actually go through glass? has anyone proved it yet without a doubt?
- is there a way to prove that all of the above are unprovable?

I'm offering a 9000 trillion multiverse BTC bounty if someone proves that the last one is unprovable to be proven. Or something like that. Please no AI.

I imagine you are aware that big data already uses AI for their code, as is the case with GitHub itself. Your reasoning is ridiculous. Whether it is code that comes out of AI or human, it is still code. It is the way it is worked that matters.

Except that the code generated by AI is a total non-sense that doesn't really actually work. But script kiddies think it's enterprise-level code, when in reality its complete bullshit. This is how some people inhere think that they know how to count the number of matching bits between two hashes, and the result is a total disaster.

If you want the plane you're boarding to crash 5 minutes after departure, throw some AI-generated firmware on its control circuits.

Indeed no bounty for the reverse proof.
I think it has already been proven that sha256 distribution is uniform anyway ? So that would directly translate as a proof that no such method exist.
Well I doubt anyone will be able to solve this without breaking the cryptographic functions. This is a hard one.
Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
drpxxx
on 03/05/2025, 09:04:07 UTC
I think I’ve approached all of this the wrong way.

I’m offering a 0.1 BTC bounty for the formal proof of any traversal method that provides a statistical edge over a linear scan for puzzle 69. By statistical edge I mean that this new traversal method running on a statistically significant number of executions requires significantly fewer checks (let’s put the threshold at 5%) to find the key.

Conditions :
- Has to be written using math semantics. Not “where does John lives” metaphors.
- Has to be empirically validated using a python / nodeJS script.
- First one posting it to this thread will be recipient of the bounty.
What if someone proves that no such method exists including the prefix one, is the bounty valid for such proof ?
Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
drpxxx
on 28/04/2025, 14:50:13 UTC
What's the point of showing a solution that can be faster than 99.5%? For the sake of a 0.1 BTC reward? If you can use this method yourself and get more  Grin
Well if a method exists it would be useful to only someone with the computing power.
Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
drpxxx
on 28/04/2025, 14:10:47 UTC
I think I’ve approached all of this the wrong way.

I’m offering a 0.1 BTC bounty for the formal proof of any traversal method that provides a statistical edge over a linear scan for puzzle 69. By statistical edge I mean that this new traversal method running on a statistically significant number of executions requires significantly fewer checks (let’s put the threshold at 5%) to find the key.

Conditions :
- Has to be written using math semantics. Not “where does John lives” metaphors.
- Has to be empirically validated using a python / nodeJS script.
- First one posting it to this thread will be recipient of the bounty.
I think If we assume that the key is uniformly distributed within this range, then every key within the range has an equal probability of being the correct private key. Since the key has a uniform distribution, uniform distribution provides no bias in how the key is distributed, all traversal methods will, on average, require the same number of checks. This means that no method will significantly reduce the number of checks required to find the key.
The key is uniformly distributed, meaning every number within the range has an equal probability of being the correct key. In a linear search, we check keys one by one, starting from the beginning of the range and moving towards the end. The expected number of trials in a linear search for a uniformly distributed key is the average of the number of trials required to find the key. Since the key can be anywhere in the range, the expected number of trials is given by N/2, where N is the number of possible keys in the range.
Because any traversal method still needs to explore a random and uniformly distributed key space, and the expected number of trials is N/2 for any such strategy.
Well using middle search or jumping around may increase your luck but the probability of finding the key is still the same.
Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
drpxxx
on 28/04/2025, 12:18:19 UTC
Um, no, I can't afford chatgpt and I only have a old desktop computer with 4 cpu  ^^

ChatGPT is free to use on lower tiers which is more than enough to generate code.

But if you could give me your linear in that case, share it and I'll show you, based on your code, that linear is crap in a box Smiley

You can simply update your own script doing something like this (Did not test it, but you should be able to understand the change required) :

Code:

# Decode address target to hex
ADDRESS_TARGET = b58decode(ADDRESS_TARGET)

# Compare with hex version of target instead of B58
def linear_scan(start: int, end: int, target: str):
    ops = 0
    for x in range(start, end+1):
        ops += 1
        if hash160_pubkey(x) == target:
            return x, ops
    return None, ops



Here just for you my friend improved version if you have the pubkey c-bit find it more quickly

Code:
#!/usr/bin/env python3
# coding: utf-8
"""
proof.py

Hash160 linear scan vs double c-bit on puzzle 21.
Uses only hash160 comparisons and no Base58 encoding. Added a progress bars tqdm.
"""

import hashlib, math
from ecdsa import SECP256k1, util
from multiprocessing import Pool, cpu_count
from tqdm import tqdm

# --- Configuration ---
ADDRESS_TARGET        = "114oFNXucftsHiUMY8uctg6N487riuyXs4h"
HASH160_TARGET        = "29a78213caa9eea824acf08022ab9dfc83414f56"
RANGE_HEX             = "100000:1fffff"
FILTER_BITS           = 2     # c ≥ 1 ⇒ >5% reduction
SHA_PREFILTER_BITS    = 8     # double bits
THRESHOLD             = 5.0   # percent
# -------------------------------

G     = SECP256k1.generator
ORDER = SECP256k1.order
B58   = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"


def b58decode(s: str) -> bytes:
    num = 0
    for ch in s:
        num = num * 58 + B58.index(ch)
    full = num.to_bytes((num.bit_length() + 7) // 8, 'big')
    # leading-zero pad
    pad = len(s) - len(s.lstrip('1'))
    full = b'\x00'*pad + full
    payload, chk = full[:-4], full[-4:]
    if hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] != chk:
        raise ValueError("Invalid Base58 checksum")
    return payload

def hash160_pubkey(x: int) -> bytes:
    P = x * G
    prefix = b'\x02' if (P.y() & 1)==0 else b'\x03'
    pub = prefix + util.number_to_string(P.x(), ORDER)
    return hashlib.new('ripemd160', hashlib.sha256(pub).digest()).digest()

def get_target_h160() -> bytes:
    if HASH160_TARGET:
        return bytes.fromhex(HASH160_TARGET)
    payload = b58decode(ADDRESS_TARGET)
    return payload[1:]


def linear_scan(start: int, end: int, target_h: bytes):
    ops = 0
    for x in tqdm(range(start, end+1), desc="Linear scan", unit="key"):
        ops += 1
        if hash160_pubkey(x) == target_h:
            return x, ops
    return None, ops


def prefilter_chunk(args):
    idx, start, end, c, d, t1, t2, target_h = args
    # si d>0 et t2 défini, on fait le SHA256-prefilter
    for i, x in enumerate(range(start, end+1), start=1):
        # 1er filtre: SHA256(pub)
        P = x * G
        prefix = b'\x02' if (P.y() & 1)==0 else b'\x03'
        pub = prefix + util.number_to_string(P.x(), ORDER)
        sha = hashlib.sha256(pub).digest()
        if d and t2 is not None:
            if (int.from_bytes(sha, 'big') >> (256 - d)) != t2:
                continue

        # 2e filtre + comparaison finale: RIPEMD-160
        rip = hashlib.new('ripemd160', sha).digest()
        if (int.from_bytes(rip, 'big') >> (160 - c)) != t1:
            continue
        if rip == target_h:
            return idx, i, x
    return idx, None, None


def parallel_prefilter(start: int, end: int, c: int, d: int,
                       target_h: bytes, t2: int, workers: int):
    N     = end - start + 1
    chunk = math.ceil(N / workers)
    t1    = int.from_bytes(target_h, 'big') >> (160 - c)

    args = []
    for i in range(workers):
        s = start + i*chunk
        e = min(start + (i+1)*chunk - 1, end)
        args.append((i, s, e, c, d, t1, t2, target_h))

    with Pool(workers) as p:
        # imap_unordered + barre de progression sur les chunks
        for idx, ops, x in tqdm(p.imap_unordered(prefilter_chunk, args),
                                 total=len(args),
                                 desc="Prefilter chunks",
                                 unit="chunk"):
            if ops:
                return x, ops
    return None, 0


def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--workers", type=int, default=0,
                        help="nombre de processus (défaut = CPU count)")
    parser.add_argument("--pubkey", type=str, default=None,
                        help="hex compressed pubkey cible (pour SHA256-prefilter)")
    args = parser.parse_args()

    workers = args.workers or cpu_count()
    s_hex, e_hex = RANGE_HEX.split(':')
    start, end   = int(s_hex, 16), int(e_hex, 16)
    N            = end - start + 1

    print(f"Target address: {ADDRESS_TARGET}")
    print(f"Range: 0x{s_hex} .. 0x{e_hex} (N = {N})")
    print(f"Filter bits: {FILTER_BITS}, SHA256 bits: {SHA_PREFILTER_BITS}, "
          f"Processes: {workers}\n")

    target_h = get_target_h160()

    # Calculate the SHA256-prefilter threshold if pubkey is provided
    t2 = None
    if args.pubkey:
        pub_bytes = bytes.fromhex(args.pubkey)
        sha_target = hashlib.sha256(pub_bytes).digest()
        t2 = int.from_bytes(sha_target, 'big') >> (256 - SHA_PREFILTER_BITS)

    # Linear scan
    print("→ Linear hash160 scan…")
    x_lin, ops_lin = linear_scan(start, end, target_h)
    print(f"  ✅ Found x = 0x{x_lin:x} in {ops_lin} H160 ops\n")

    # Prefilter scan
    print("→ Parallel double-prefilter scan…")
    x_pre, ops_pre = parallel_prefilter(start, end,
                                        FILTER_BITS,
                                        SHA_PREFILTER_BITS,
                                        target_h,
                                        t2,
                                        workers)
    print(f"  ✅ Found x = 0x{x_pre:x} in {ops_pre} heavy ops\n")

    # Statistics
    pct_lin = 100.0
    pct_pre = ops_pre / ops_lin * 100.0 if ops_lin else 0.0
    reduction = pct_lin - pct_pre

    print(f"Percent checks: hash160 = {pct_lin:.2f}%, prefilter = {pct_pre:.2f}%")
    print(f"Reduction = {reduction:.2f}%")
    print(("✅" if reduction>THRESHOLD else "⚠️") +
          f" Reduction {'exceeds' if reduction>THRESHOLD else 'below'} {THRESHOLD}%")
    winner = "Prefilter" if ops_pre < ops_lin else "Hash160"
    print("🏆 Winner: " + winner + " scan")


if __name__ == "__main__":
    main()

root:~# python3 proof.py --pubkey 031a746c78f72754e0be046186df8a20cdce5c79b2eda76013c647af08d306e49e
Target address: 114oFNXucftsHiUMY8uctg6N487riuyXs4h
Range: 0x100000 .. 0x1fffff (N = 1048576)
Filter bits: 2, SHA256 bits: 8, Processes: 4

→ Linear hash160 scan…
Linear scan:  73%|███████████████████████████████████████████████████████████████████████████████████████████████████████████▋                                        | 763188/1048576 [01:06<00:24, 11441.10key/s]
  ✅ Found x = 0x1ba534 in 763189 H160 ops

→ Parallel double-prefilter scan…
Prefilter chunks:   0%|                                                                                                                                                                   | 0/4 [00:38<?, ?chunk/s]
  ✅ Found x = 0x1ba534 in 238901 heavy ops

Percent checks: hash160 = 100.00%, prefilter = 31.30%
Reduction = 68.70%
✅ Reduction exceeds 5.0%
🏆 Winner: Prefilter scan

My old computer doesn’t have the balls to scan the remaining keys, so I hope I’ve at least opened your eyes, you seem smarter than Ktimes ^^ Think of me if you use it! Your welcome my friend.  Cheesy

And come take a tour to my github https://github.com/lfgcampos Smiley

In your parallel_prefilter function, you still return immediately when the first chunk finds a solution
This means you lose the operations done by the other threads.
#!/usr/bin/env python3
# coding: utf-8
"""
proof_fixed.py

Hash160 linear scan vs double c-bit prefilter on puzzle 21 (or custom range).
Corrected version: counts all ops from all threads.
"""

import hashlib, math
from ecdsa import SECP256k1, util
from multiprocessing import Pool, cpu_count
from tqdm import tqdm

# --- Configuration ---
ADDRESS_TARGET        = "114oFNXucftsHiUMY8uctg6N487riuyXs4h"
HASH160_TARGET        = "29a78213caa9eea824acf08022ab9dfc83414f56"
RANGE_HEX             = "100000:1fffff"
FILTER_BITS           = 2
SHA_PREFILTER_BITS    = 8
THRESHOLD             = 5.0
# -------------------------------

G     = SECP256k1.generator
ORDER = SECP256k1.order
B58   = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

def b58decode(s: str) -> bytes:
    num = 0
    for ch in s:
        num = num * 58 + B58.index(ch)
    full = num.to_bytes((num.bit_length() + 7) // 8, 'big')
    pad = len(s) - len(s.lstrip('1'))
    full = b'\x00'*pad + full
    payload, chk = full[:-4], full[-4:]
    if hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] != chk:
        raise ValueError("Invalid Base58 checksum")
    return payload

def hash160_pubkey(x: int) -> bytes:
    P = x * G
    prefix = b'\x02' if (P.y() & 1)==0 else b'\x03'
    pub = prefix + util.number_to_string(P.x(), ORDER)
    return hashlib.new('ripemd160', hashlib.sha256(pub).digest()).digest()

def get_target_h160() -> bytes:
    if HASH160_TARGET:
        return bytes.fromhex(HASH160_TARGET)
    payload = b58decode(ADDRESS_TARGET)
    return payload[1:]

def linear_scan(start: int, end: int, target_h: bytes):
    ops = 0
    for x in tqdm(range(start, end+1), desc="Linear scan", unit="key"):
        ops += 1
        if hash160_pubkey(x) == target_h:
            return x, ops
    return None, ops

def prefilter_chunk(args):
    idx, start, end, c, d, t1, t2, target_h = args
    local_ops = 0
    found_x = None
    for x in range(start, end+1):
        local_ops += 1
        P = x * G
        prefix = b'\x02' if (P.y() & 1)==0 else b'\x03'
        pub = prefix + util.number_to_string(P.x(), ORDER)
        sha = hashlib.sha256(pub).digest()
        if d and t2 is not None:
            if (int.from_bytes(sha, 'big') >> (256 - d)) != t2:
                continue
        rip = hashlib.new('ripemd160', sha).digest()
        if (int.from_bytes(rip, 'big') >> (160 - c)) != t1:
            continue
        if rip == target_h:
            found_x = x
            break
    return idx, local_ops, found_x

def parallel_prefilter(start: int, end: int, c: int, d: int,
                       target_h: bytes, t2: int, workers: int):
    N     = end - start + 1
    chunk = math.ceil(N / workers)
    t1    = int.from_bytes(target_h, 'big') >> (160 - c)

    args = []
    for i in range(workers):
        s = start + i*chunk
        e = min(start + (i+1)*chunk - 1, end)
        args.append((i, s, e, c, d, t1, t2, target_h))

    total_ops = 0
    found_x = None

    with Pool(workers) as p:
        for idx, ops, x in tqdm(p.imap_unordered(prefilter_chunk, args),
                                 total=len(args),
                                 desc="Prefilter chunks",
                                 unit="chunk"):
            total_ops += ops
            if x is not None and found_x is None:
                found_x = x

    return found_x, total_ops

def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--workers", type=int, default=0,
                        help="nombre de processus (défaut = CPU count)")
    parser.add_argument("--pubkey", type=str, default=None,
                        help="hex compressed pubkey cible (pour SHA256-prefilter)")
    args = parser.parse_args()

    workers = args.workers or cpu_count()
    s_hex, e_hex = RANGE_HEX.split(':')
    start, end   = int(s_hex, 16), int(e_hex, 16)
    N            = end - start + 1

    print(f"Target address: {ADDRESS_TARGET}")
    print(f"Range: 0x{s_hex} .. 0x{e_hex} (N = {N})")
    print(f"Filter bits: {FILTER_BITS}, SHA256 bits: {SHA_PREFILTER_BITS}, "
          f"Processes: {workers}\n")

    target_h = get_target_h160()

    t2 = None
    if args.pubkey:
        pub_bytes = bytes.fromhex(args.pubkey)
        sha_target = hashlib.sha256(pub_bytes).digest()
        t2 = int.from_bytes(sha_target, 'big') >> (256 - SHA_PREFILTER_BITS)

    # Linear scan
    print("→ Linear hash160 scan…")
    x_lin, ops_lin = linear_scan(start, end, target_h)
    print(f"  ✅ Found x = 0x{x_lin:x} in {ops_lin} H160 ops\n")

    # Prefilter scan
    print("→ Parallel double-prefilter scan…")
    x_pre, ops_pre = parallel_prefilter(start, end,
                                        FILTER_BITS,
                                        SHA_PREFILTER_BITS,
                                        target_h,
                                        t2,
                                        workers)
    print(f"  ✅ Found x = 0x{x_pre:x} in {ops_pre} heavy ops\n")

    # Statistics
    pct_lin = 100.0
    pct_pre = ops_pre / ops_lin * 100.0 if ops_lin else 0.0
    reduction = pct_lin - pct_pre

    print(f"Percent checks: hash160 = {pct_lin:.2f}%, prefilter = {pct_pre:.2f}%")
    print(f"Reduction = {reduction:.2f}%")
    print(("✅" if reduction>THRESHOLD else "⚠️") +
          f" Reduction {'exceeds' if reduction>THRESHOLD else 'below'} {THRESHOLD}%")
    winner = "Prefilter" if ops_pre < ops_lin else "Hash160"
    print("🏆 Winner: " + winner + " scan")

if __name__ == "__main__":
    main()
Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
drpxxx
on 28/04/2025, 12:09:11 UTC
Um, no, I can't afford chatgpt and I only have a old desktop computer with 4 cpu  ^^

ChatGPT is free to use on lower tiers which is more than enough to generate code.

But if you could give me your linear in that case, share it and I'll show you, based on your code, that linear is crap in a box Smiley

You can simply update your own script doing something like this (Did not test it, but you should be able to understand the change required) :

Code:

# Decode address target to hex
ADDRESS_TARGET = b58decode(ADDRESS_TARGET)

# Compare with hex version of target instead of B58
def linear_scan(start: int, end: int, target: str):
    ops = 0
    for x in range(start, end+1):
        ops += 1
        if hash160_pubkey(x) == target:
            return x, ops
    return None, ops



Here just for you my friend improved version if you have the pubkey c-bit find it more quickly

Code:
#!/usr/bin/env python3
# coding: utf-8
"""
proof.py

Hash160 linear scan vs double c-bit on puzzle 21.
Uses only hash160 comparisons and no Base58 encoding. Added a progress bars tqdm.
"""

import hashlib, math
from ecdsa import SECP256k1, util
from multiprocessing import Pool, cpu_count
from tqdm import tqdm

# --- Configuration ---
ADDRESS_TARGET        = "114oFNXucftsHiUMY8uctg6N487riuyXs4h"
HASH160_TARGET        = "29a78213caa9eea824acf08022ab9dfc83414f56"
RANGE_HEX             = "100000:1fffff"
FILTER_BITS           = 2     # c ≥ 1 ⇒ >5% reduction
SHA_PREFILTER_BITS    = 8     # double bits
THRESHOLD             = 5.0   # percent
# -------------------------------

G     = SECP256k1.generator
ORDER = SECP256k1.order
B58   = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"


def b58decode(s: str) -> bytes:
    num = 0
    for ch in s:
        num = num * 58 + B58.index(ch)
    full = num.to_bytes((num.bit_length() + 7) // 8, 'big')
    # leading-zero pad
    pad = len(s) - len(s.lstrip('1'))
    full = b'\x00'*pad + full
    payload, chk = full[:-4], full[-4:]
    if hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] != chk:
        raise ValueError("Invalid Base58 checksum")
    return payload

def hash160_pubkey(x: int) -> bytes:
    P = x * G
    prefix = b'\x02' if (P.y() & 1)==0 else b'\x03'
    pub = prefix + util.number_to_string(P.x(), ORDER)
    return hashlib.new('ripemd160', hashlib.sha256(pub).digest()).digest()

def get_target_h160() -> bytes:
    if HASH160_TARGET:
        return bytes.fromhex(HASH160_TARGET)
    payload = b58decode(ADDRESS_TARGET)
    return payload[1:]


def linear_scan(start: int, end: int, target_h: bytes):
    ops = 0
    for x in tqdm(range(start, end+1), desc="Linear scan", unit="key"):
        ops += 1
        if hash160_pubkey(x) == target_h:
            return x, ops
    return None, ops


def prefilter_chunk(args):
    idx, start, end, c, d, t1, t2, target_h = args
    # si d>0 et t2 défini, on fait le SHA256-prefilter
    for i, x in enumerate(range(start, end+1), start=1):
        # 1er filtre: SHA256(pub)
        P = x * G
        prefix = b'\x02' if (P.y() & 1)==0 else b'\x03'
        pub = prefix + util.number_to_string(P.x(), ORDER)
        sha = hashlib.sha256(pub).digest()
        if d and t2 is not None:
            if (int.from_bytes(sha, 'big') >> (256 - d)) != t2:
                continue

        # 2e filtre + comparaison finale: RIPEMD-160
        rip = hashlib.new('ripemd160', sha).digest()
        if (int.from_bytes(rip, 'big') >> (160 - c)) != t1:
            continue
        if rip == target_h:
            return idx, i, x
    return idx, None, None


def parallel_prefilter(start: int, end: int, c: int, d: int,
                       target_h: bytes, t2: int, workers: int):
    N     = end - start + 1
    chunk = math.ceil(N / workers)
    t1    = int.from_bytes(target_h, 'big') >> (160 - c)

    args = []
    for i in range(workers):
        s = start + i*chunk
        e = min(start + (i+1)*chunk - 1, end)
        args.append((i, s, e, c, d, t1, t2, target_h))

    with Pool(workers) as p:
        # imap_unordered + barre de progression sur les chunks
        for idx, ops, x in tqdm(p.imap_unordered(prefilter_chunk, args),
                                 total=len(args),
                                 desc="Prefilter chunks",
                                 unit="chunk"):
            if ops:
                return x, ops
    return None, 0


def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--workers", type=int, default=0,
                        help="nombre de processus (défaut = CPU count)")
    parser.add_argument("--pubkey", type=str, default=None,
                        help="hex compressed pubkey cible (pour SHA256-prefilter)")
    args = parser.parse_args()

    workers = args.workers or cpu_count()
    s_hex, e_hex = RANGE_HEX.split(':')
    start, end   = int(s_hex, 16), int(e_hex, 16)
    N            = end - start + 1

    print(f"Target address: {ADDRESS_TARGET}")
    print(f"Range: 0x{s_hex} .. 0x{e_hex} (N = {N})")
    print(f"Filter bits: {FILTER_BITS}, SHA256 bits: {SHA_PREFILTER_BITS}, "
          f"Processes: {workers}\n")

    target_h = get_target_h160()

    # Calculate the SHA256-prefilter threshold if pubkey is provided
    t2 = None
    if args.pubkey:
        pub_bytes = bytes.fromhex(args.pubkey)
        sha_target = hashlib.sha256(pub_bytes).digest()
        t2 = int.from_bytes(sha_target, 'big') >> (256 - SHA_PREFILTER_BITS)

    # Linear scan
    print("→ Linear hash160 scan…")
    x_lin, ops_lin = linear_scan(start, end, target_h)
    print(f"  ✅ Found x = 0x{x_lin:x} in {ops_lin} H160 ops\n")

    # Prefilter scan
    print("→ Parallel double-prefilter scan…")
    x_pre, ops_pre = parallel_prefilter(start, end,
                                        FILTER_BITS,
                                        SHA_PREFILTER_BITS,
                                        target_h,
                                        t2,
                                        workers)
    print(f"  ✅ Found x = 0x{x_pre:x} in {ops_pre} heavy ops\n")

    # Statistics
    pct_lin = 100.0
    pct_pre = ops_pre / ops_lin * 100.0 if ops_lin else 0.0
    reduction = pct_lin - pct_pre

    print(f"Percent checks: hash160 = {pct_lin:.2f}%, prefilter = {pct_pre:.2f}%")
    print(f"Reduction = {reduction:.2f}%")
    print(("✅" if reduction>THRESHOLD else "⚠️") +
          f" Reduction {'exceeds' if reduction>THRESHOLD else 'below'} {THRESHOLD}%")
    winner = "Prefilter" if ops_pre < ops_lin else "Hash160"
    print("🏆 Winner: " + winner + " scan")


if __name__ == "__main__":
    main()

root:~# python3 proof.py --pubkey 031a746c78f72754e0be046186df8a20cdce5c79b2eda76013c647af08d306e49e
Target address: 114oFNXucftsHiUMY8uctg6N487riuyXs4h
Range: 0x100000 .. 0x1fffff (N = 1048576)
Filter bits: 2, SHA256 bits: 8, Processes: 4

→ Linear hash160 scan…
Linear scan:  73%|███████████████████████████████████████████████████████████████████████████████████████████████████████████▋                                        | 763188/1048576 [01:06<00:24, 11441.10key/s]
  ✅ Found x = 0x1ba534 in 763189 H160 ops

→ Parallel double-prefilter scan…
Prefilter chunks:   0%|                                                                                                                                                                   | 0/4 [00:38<?, ?chunk/s]
  ✅ Found x = 0x1ba534 in 238901 heavy ops

Percent checks: hash160 = 100.00%, prefilter = 31.30%
Reduction = 68.70%
✅ Reduction exceeds 5.0%
🏆 Winner: Prefilter scan

My old computer doesn’t have the balls to scan the remaining keys, so I hope I’ve at least opened your eyes, you seem smarter than Ktimes ^^ Think of me if you use it! Your welcome my friend.  Cheesy

And come take a tour to my github https://github.com/lfgcampos Smiley

In your parallel_prefilter function, you still return immediately when the first chunk finds a solution
This means you lose the operations done by the other threads.