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

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) :
# 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
#!/usr/bin/env python3
# coding: utf-8
"""
proof_prefilter2.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@vmi2512290:~# 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.

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