Skip to content

Intervals above 125 bits silently produce wrong keys instead of erroring #159

Description

@Dileep-Kumar-5

Summary

Exceeding the documented 125-bit interval limit does not fail. It produces wrong private keys with no error, no warning and no crash, while reporting normal progress the whole time.

The README states the limit ("This program is limited to a 125bit interval search") but not the failure mode, so a run above it looks healthy and its output is worthless. Related: #154, #122.

Cause

HashTable.h packs the travelled distance into 128 bits:

typedef struct {
  int128_t  x;    // Poisition of kangaroo (128bit LSB)
  int128_t  d;    // Travelled distance (b127=sign b126=kangaroo type, b125..b0 distance
} ENTRY;

126 bits of magnitude. Distances span the interval width, so a wider interval overflows — and HashTable::Convert() masks the excess away rather than rejecting it:

D->i64[1] = d->bits64[1] & 0x3FFFFFFFFFFFFFFFULL;

The entry is then indistinguishable from a valid one. On collision it yields a wrong key.

Reproduce

Puzzle #140's published range and public key (2^139 interval):

80000000000000000000000000000000000
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
031F6A332D3C5C4F2DE2378C012F429CD109BA07D69690C6C701B6BB87860D6640
./kangaroo -gpu -d 16 -w w140.kcp -wi 20 in140.txt     # let it run, then stop
./kangaroo -t 4 -wcheck w140.kcp

Result on current master:

interval DPs stored -wcheck
2^119 (#120) 17,088 100.000% OK
2^139 (#140) 376,836 0.024% OK — 376,747 corrupt

2^119 is inside the cap and is fine, so this is specifically the over-limit path. Nothing in the 2^139 run's output distinguishes it from the 2^119 run.

Why it matters

Every currently unsolved kangaroo-able puzzle is above the limit — #135 is a 2^134 interval, #140 is 2^139 — so anyone pointing this tool at them today is accumulating corrupt data and cannot tell.

Note for anyone arriving from #154

Chunking the range into sub-intervals below the cap is correct, but expensive. Kangaroo costs ~K·√W, so splitting W into m chunks costs m·K·√(W/m) = √m times more work. The 512 chunks suggested in #154 is √512 ≈ 23× the work of searching 2^134 in one pass. It is a workaround, not a fix.

Fix

PR #158 widens the distance field to 256 bits (254 bits of magnitude, intervals to 253 bits) and makes over-range distances exit(-1) instead of truncating. Same input as above: 100.000% OK. It also fixes a CUDA 13 build break — cudaDeviceProp::computeMode was removed, so GPUEngine.cu does not compile against a current toolkit at all.

Minimal alternative if the format change is unwanted: add a startup check that refuses an interval wider than 125 bits. Failing loudly costs nothing and turns silently-wrong output into an error message.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions