only
Looking forward to it !
I only modified the prefix function that @ktimesg intentionally miscompares. I'm certain that the only exact comparison method is for both to follow the same path... but he simply avoids doing so to deceive—a "fool hunter".
import hashlib
import random
import time
# Configuration
TOTAL_SIZE = 100_000
RANGE_SIZE = 5_000
PREFIX_LENGTH = 3
SIMULATIONS = 500
SECP256K1_ORDER = int("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
# ENABLE REPRODUCIBLE TESTING
# Note: this line can be safely kept for a release build
random.seed(int.from_bytes(b'mcdouglasx'))
def ScoobyDoo_ReturnOfTheSequential(dataset, block, target_hash, order):
checks = 0
for k in reversed(dataset):
checks += 1
if generate_h160(k) == target_hash:
return {"checks": checks, "found": True}
raise Exception('OHNOES. Your Programming Language Is Rigged!')
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 prefixes_search(dataset, block, prefix, target_hash, order):
prefix_hash = target_hash[:prefix]
checks = 0
skipped_indices = []
skip_window = 4096
skip_percentage = 0.3
i = len(dataset) - 1
while i >= 0:
checks += 1
h = generate_h160(dataset[i])
if h == target_hash:
return {"checks": checks, "found": True}
if h.startswith(prefix_hash):
skip_count = int(skip_window * skip_percentage)
for j in range(i-1, max(i-1 - skip_count, -1), -1):
skipped_indices.append(j)
i -= skip_count + 1 # +1
else:
i -= 1
for idx in sorted(skipped_indices, reverse=True):
checks += 1
if generate_h160(dataset[idx]) == 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 = ScoobyDoo_ReturnOfTheSequential(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
""")
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}
""")
if __name__ == '__main__':
compare_methods()
test=== FINAL RESULTS ===
Wins:
Scooby_Doo: 106
Prefix: 371
Ties: 23
Total Checks:
Scooby_Doo: 24626075
Prefix: 24558252
Total Time:
Scooby_Doo: 295.013752 seconds
Prefix: 312.924599 seconds
Averages (Total Time / Wins):
Scooby_Doo : 2.783149 seconds/victory
Prefix : 0.843463 seconds/victory
Checks per Win:
Scooby_Doo : 232321.46 checks/win
Prefix : 66194.75 checks/win
The prefix search has sparked quite a lot of discussion in recent months, and I admit—that was my goal from the start.
However, some people crave the spotlight and refuse to accept mathematics for what they are. I’ve had a lot of fun with this, truly, but at this point, I find the meaningless debates here rather dull.
As you can see, all the scripts shared here intending to discredit the use of prefixes have actually served as practice for me and as examples. Even though their initial purpose was far from supporting me, they indirectly strengthened my theory, and now I have several practical cases to use as examples—proving my point.
Since all their failed attempts to discredit the prefix technique have only led me to refine the method by incorporating prefixes into their own ideas, it’s clear I have demonstrated far more than I intended. The undeniable fact remains: prefix-based brute force methods are versatile and adaptable to any idea or strategy, improving them 100% of the time.
So, now that there is ample proof, I won’t be integrating prefixes into their future theories or implementations—I’ve grown tired of it.
Their repeated and unsuccessful efforts to sideline me have only reinforced my stance. By integrating probabilistic prefix usage, I’ve definitively shown that it is superior.
Final conclusion of my research:
All linear brute force methods can be improved by incorporating probabilistic search using prefixes.
Therefore, I strongly recommend applying this approach to any brute force implementation involving hashes.
If you don’t find the idea appealing or can’t grasp it yet, I suggest simply adding prefix-based logic to any concept or strategy you have—and you’ll witness the magic in action.