Try 4095 Instead of 5000. I already explained this a few posts ago. Same results
o.k, i'll check.
Interesting results. Looks like when you tweak the parameters like you said, both methods end up working similar. But you're kinda proving mcd right here, even though you're not directly hunting for a single prefix, you're still using a prefix-based strategy with that 4095 pick. You're just not targeting something specific. So this doesn't wreck his theory... if anything, it backs it up.
import hashlib
import random
import time
# Configuration
TOTAL_SIZE = 100_000
RANGE_SIZE = 4_095
PREFIX_LENGTH = 3
SIMULATIONS = 500
SECP256K1_ORDER = int("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
print(f"""
=== Configuration ===
Total numbers: {TOTAL_SIZE:,}
Block size: {RANGE_SIZE:,}
Prefix: {PREFIX_LENGTH} characters (16^{PREFIX_LENGTH} combinations)
Simulations: {SIMULATIONS}
secp256k1 Order: {SECP256K1_ORDER}
""")
def generate_h160(data):
h = hashlib.new('ripemd160', str(data).encode('utf-8'))
return h.hexdigest()
def shuffled_range(n):
arr = list(range(n + 1))
random.shuffle(arr)
return arr
def Scooby_Doo(dataset, block, target_hash, order):
checks = 0
ranges = []
for idx in order:
start = idx * block
end = start + block
marked = False
for i in range(start, end):
checks += 1
h = generate_h160(dataset[i])
if h == target_hash:
return {"checks": checks, "found": True}
if not marked and random.randint(0, 4095) == 0: # ktimesg randomness
marked = True
ranges.append({"start": i + 1, "end": end})
break
for r in ranges:
for i in range(r["end"] - 1, r["start"] - 1, -1):
checks += 1
if generate_h160(dataset[i]) == target_hash:
return {"checks": checks, "found": True}
return {"checks": checks, "found": False}
def prefixes_search(dataset, block, prefix, target_hash, order):
prefix_hash = target_hash[:prefix]
checks = 0
ranges = []
for idx in order:
start = idx * block
end = start + block
found_prefix = False
for i in range(start, end):
checks += 1
h = generate_h160(dataset[i])
if h == target_hash:
return {"checks": checks, "found": True}
if not found_prefix and h.startswith(prefix_hash):
found_prefix = True
ranges.append({"start": i + 1, "end": end})
break
for r in ranges:
for i in range(r["end"] - 1, r["start"] - 1, -1):
checks += 1
if generate_h160(dataset[i]) == target_hash:
return {"checks": checks, "found": True}
return {"checks": checks, "found": False}
def compare_methods():
results = {
"Scooby_Doo": {"wins": 0, "total_checks": 0, "total_time": 0},
"prefixes": {"wins": 0, "total_checks": 0, "total_time": 0},
"ties": 0
}
for i in range(SIMULATIONS):
max_range = SECP256K1_ORDER - TOTAL_SIZE - 1
random_offset = random.randrange(max_range)
R = 1 + random_offset
dataset = [R + i for i in range(TOTAL_SIZE)]
target_num = random.choice(dataset)
target_hash = generate_h160(target_num)
blocks = TOTAL_SIZE // RANGE_SIZE
order = shuffled_range(blocks - 1)
start_time = time.perf_counter()
seq_result = Scooby_Doo(dataset, RANGE_SIZE, target_hash, order)
end_time = time.perf_counter()
seq_time = end_time - start_time
start_time = time.perf_counter()
pre_result = prefixes_search(dataset, RANGE_SIZE, PREFIX_LENGTH, target_hash, order)
end_time = time.perf_counter()
pre_time = end_time - start_time
results["Scooby_Doo"]["total_checks"] += seq_result["checks"]
results["prefixes"]["total_checks"] += pre_result["checks"]
results["Scooby_Doo"]["total_time"] += seq_time
results["prefixes"]["total_time"] += pre_time
if seq_result["checks"] < pre_result["checks"]:
results["Scooby_Doo"]["wins"] += 1
elif seq_result["checks"] > pre_result["checks"]:
results["prefixes"]["wins"] += 1
else:
results["ties"] += 1
print(f"Simulation {i + 1}: Scooby_Doo = {seq_result['checks']} checks in {seq_time:.6f}s | Prefix = {pre_result['checks']} checks in {pre_time:.6f}s")
avg_success_rate_Scooby_Doo = (results["Scooby_Doo"]["total_checks"] / results["Scooby_Doo"]["wins"]
if results["Scooby_Doo"]["wins"] > 0 else float('inf'))
avg_success_rate_prefixes = (results["prefixes"]["total_checks"] / results["prefixes"]["wins"]
if results["prefixes"]["wins"] > 0 else float('inf'))
avg_time_Scooby_Doo = (results["Scooby_Doo"]["total_time"] / results["Scooby_Doo"]["wins"]
if results["Scooby_Doo"]["wins"] > 0 else float('inf'))
avg_time_prefixes = (results["prefixes"]["total_time"] / results["prefixes"]["wins"]
if results["prefixes"]["wins"] > 0 else float('inf'))
print(f"""
=== FINAL RESULTS ===
Wins:
Scooby_Doo: {results['Scooby_Doo']['wins']}
Prefix: {results['prefixes']['wins']}
Ties: {results['ties']}
Total Checks:
Scooby_Doo: {results['Scooby_Doo']['total_checks']}
Prefix: {results['prefixes']['total_checks']}
Total Time:
Scooby_Doo: {results['Scooby_Doo']['total_time']:.6f} seconds
Prefix: {results['prefixes']['total_time']:.6f} seconds
Averages (Total Time / Wins):
Scooby_Doo : {avg_time_Scooby_Doo:.6f} seconds/victory
Prefix : {avg_time_prefixes:.6f} seconds/victory
Checks per Win:
Scooby_Doo : {avg_success_rate_Scooby_Doo:.2f} checks/win
Prefix : {avg_success_rate_prefixes:.2f} checks/win
""")
if __name__ == '__main__':
compare_methods()
I’m just going by what each side posts here. not trying to mess with anyone’s opinions. I’m no mathematician, so I can’t be sure of anything. Just ‘cause I think different than you doesn’t make it wrong. If anything, prefix search doesn’t break math, it actually backs up uniform distribution. You get what you’d expect in the long run.