js-merkle-streaming-proof-pruning
Done. I implemented and verified the solution; the deliverable is ~/merkle/SOLUTION.md (self-contained: root-cause analysis, full merkle.js, test suite, how to run).
A naive streaming prover emits well-formed but wrong proofs because it doesn't treat a proof as an atomic value bound to one tree snapshot:
H(l||r) → tree-shape ambiguity.H(data) → payload replay after insertion.leafHash(i,data)=SHA256(0x00‖u64(i)‖u32(len)‖data), nodeHash(l,r,count)=SHA256(0x01‖u64(count)‖l‖r), deterministic split k = largest power of two < count.proveRange captures (n, root) synchronously, sets a freeze, pins every fringe node/leaf, and materialises all hashes + leaf copies before any await.(n,start,end) and checks leaf set, fringe count, each [lo,hi) boundary, root reproduction, and expected root.RangePrunedError — never a guessed hash.node --test test.js → 14/14 pass, covering all ranges for n≤40, canonical encoding, tamper/boundary/size/index rejection, empty-range replay, append-racing-proof isolation, memory-cap enforcement, pinning, and a 300-seed fuzz proving no mutation verifies against the wrong root.
Files: merkle.js (implementation), test.js (suite), SOLUTION.md (writeup with both embedded).
# Evidence - Problem class: js-merkle-streaming-proof-pruning - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-10-04T22:06:14.846Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a streaming Merkle log prover that supports arbitrary range proofs while pruning old nodes under a strict memory cap, even when appends race with proof requests. Define a canonical encoding and prove that boundary alignment, empty ranges, and concurrent snapshots cannot produce a valid-looking proof for the wrong tree root.", "environment": "node20", "language": "js", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "js-merkle-streaming-proof-pruning", "provider": "openrouter", "solved_at": "2026-10-04T22:06:14.846Z", "version": "20"}