Post
Topic
Board Bitcoin Discussion
Re: Bitcoin puzzle transaction ~32 BTC prize to who solves it
by
Virtuose
on 28/04/2025, 10:28:26 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


That won't change anything, my friend. Are you sure you're coding it yourself? Maybe you're a chatgpt or a fiverr fan but I'm not. ^^
You can't compete with a c-bit prefilter for your linear.


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

Hash160 linear scan vs c-bit prefilter on puzzle 21.
Uses only hash160 comparisons and no Base58 encoding.
"""

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

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

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

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

# Compute RIPEMD-160(SHA256(pubkey))
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()

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

# Simple linear scan comparing hash160 directly
def linear_scan(start: int, end: int, target_h: bytes):
    ops = 0
    for x in range(start, end+1):
        ops += 1
        if hash160_pubkey(x) == target_h:
            return x, ops
    return None, ops

# Worker for prefilter scan chunk
def prefilter_chunk(args):
    idx, start, end, c, t1, target_h = args
    for i, x in enumerate(range(start, end+1), start=1):
        h2 = hash160_pubkey(x)
        if (int.from_bytes(h2, 'big') >> (160-c)) != t1:
            continue
        if h2 == target_h:
            return idx, i, x
    return idx, None, None

# Parallel prefilter scan using hash160 comparisons
def parallel_prefilter(start: int, end: int, c: int, target_h: bytes, workers: int):
    N = end - start + 1
    chunk = math.ceil(N / workers)
    t1 = int.from_bytes(target_h, 'big') >> (160 - c)
    args = [(i, start + i*chunk, min(start + (i+1)*chunk - 1, end), c, t1, target_h)
            for i in range(workers)]
    with Pool(workers) as p:
        results = p.map(prefilter_chunk, args)
    for idx, ops, x in sorted(results, key=lambda r: r[0]):
        if ops:
            return x, ops
    return None, 0

# Main entry
def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--workers", type=int, default=0,
                        help="number of processes (default = CPU count)")
    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}, Processes: {workers}\n")

    target_h = get_target_h160()

    # 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")

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

    # 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"\nPercent 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
Target address: 14oFNXucftsHiUMY8uctg6N487riuyXs4h
Range: 0x100000 .. 0x1fffff (N = 1048576)
Filter bits: 2, Processes: 4

→ Linear hash160 scan…
  ✅ Found x = 0x1ba534 in 763189 H160 ops

→ Parallel prefilter scan…
  ✅ 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

I'm going to end up believing that you're just lucky  Tongue