WO-03b — Count-bound Merkle roots¶
7 October 2026 · Local checks passed. DONE WO-03b handoff authorized by the owner; Open entries 4–10 remain for reviews and audits. Claude’s fresh surprise exam is pending. No merge or next work order is authorized by this handoff.
Branch: wo-03b-count-bound, from WO-03 at ac9cd56. New Python reference and
vectors frozen in fc8010a before the C++ change. Implements the owner-approved
CHAIN-DESIGN §2b revision. All earlier golden files and evidence remain unchanged.
Change¶
For both transaction and event roots:
count > 0: SHAKE256("E46-merkle\0" || 0x02 || u64_LE(count) || tree_root), 32 bytes
count = 0: 32 zero bytes
The wrapper is applied once, after the tree is complete. Leaf/node tags and odd carry are unchanged. All nonempty roots, including singleton roots, now use the count seal. The C++ library serializes the count byte by byte; native endianness does not affect the output. There are no difficulty constants in this change.
Proof now owns {leaf, index, leaf_count, siblings}. Index/count are uint64_t.
Tree::proof() returns the complete record; the tree retains leaf bytes to do so.
verify(expected_root, proof) reconstructs the raw tree root and seals it with
the supplied count before comparing. The field-based overload uses the same path.
Zero-count inclusion proofs, impossible indices and extra/missing siblings fail.
The expected root must still come from the caller’s authenticated context. Changing both a proof and an untrusted expected root does not prove membership in a particular block. The count seal addresses the previously demonstrated three-versus-four-leaf ambiguity under the hash’s security assumptions.
Tree::tree_root() is an explicitly documented diagnostic/intermediate value.
Chain callers use root(), merkle_root() or event_root(), all count-bound.
bind_root(raw_root, count) exposes the exact wrapper for independent encoding
tests; its zero-count result is zero regardless of the supplied raw root.
Event sorting, duplicate rejection and the WO-08/09 validation boundary are
unchanged. Supplied IDs are sort keys; leaves contain type || body. WO-03b
neither mines nor validates Rads or commitment stamps.
Results¶
Evidence: summary, source fingerprints and command logs alongside them.
Check |
Result |
|---|---|
Python/C++ comparisons |
104,570 passed |
Altered-count checks in differential run |
30,279 rejected |
Random trees |
1,000 new seeded trees plus the 1,000 earlier frozen trees |
Raw-tree regression cases |
2,015 match the independent reference, including earlier frozen roots |
Required tree sizes |
0, 1, 2, 3, 5, 1,000 for transactions/events; additional real trees at 255, 256, 257 leaves |
Count encoding |
12 wrapper vectors, including byte boundaries, |
C++ unit coverage |
8,385 inclusion paths; wrong counts, leaf/root/index/sibling tampering, missing/extra siblings |
Release suite |
12/12 passed |
ASan/UBSan suite |
12/12 passed, recovery disabled |
New and prior golden regeneration |
Byte-for-byte matches; no frozen files edited |
Formatting |
Changed C++ files pass clang-format |
Fuzz |
101,601 executions in 31 seconds, one worker, no crashes or sanitizer errors |
Benchmark |
1,150.69 roots/second median, 1,000 transaction IDs, one worker, five approximately 0.25-second samples |
The very large count vectors test wrapper encoding, not construction of enormous
trees. Parser checks reject negative and above-uint64_t values. Valid paths are
also tested against the old unbound roots and rejected.
Golden/fuzzer seed: 2026100730. Tools: installed Apple Clang 21 for release and
sanitizers; installed Homebrew LLVM 22 for libFuzzer. Benchmarks include tree
allocation and retained leaf bytes, are host/load-specific, and make no security
claim. An initial build caught an obsolete unit-test call after the Proof API
change; it was corrected before the recorded final checks.
Open decisions and limitations — mandatory handoff¶
Recorded in DECISIONS-NEEDED.md, not only in chat:
Forward status: implementation complete locally and ready for independent review; no known unresolved formula choice or failed test blocks WO-03b. Items 4–9 are retrospective documentation/claim review. Item 10 is a downstream integration handoff. The owner subsequently authorized a DONE handoff while these entries remain Open for reviews and audits. They have not been silently resolved or removed.
Item |
Finding and recommended disposition |
|---|---|
4 — light clients |
Correct the claim that count binding first makes inclusion proofs possible. It authenticates the count; proofs still do not establish full validity or unspent status. Height is inferred from chain position. Qualify QTL/E46i claims with the required context. |
5 — security arithmetic |
CHAIN-DESIGN §2a/§7 quotes about 2^128 classical preimage cost for the combined 256-bit payload; §9 quotes 2^256 for a 512-bit output. Under an ideal-function model the generic classical preimage scales are 2^256 and 2^512 respectively, with Grover scales 2^128 and 2^256. Clarify any alternative attack model; do not label actual joint-address security proven. PHASE3-RESULTS §L.5 already qualifies the combined construction. |
6 — evidence versus security |
White-paper §3 turns Grover simulation and finite collision measurements into stronger statements about full preimage work/equality with SHA-256. Recommend retaining the measured outcomes while labeling ideal-model estimates and structural-security uncertainty, as in PHASE3-RESULTS §L.3–L.7. No quantum hardware or full-width security proof is supplied by WO-03b. |
7 — PoW weakness |
Correct the white paper’s claim that difficulty adjustment makes a weak PoW hash harmless. Restored block cadence does not remove a miner’s relative advantage or reorganization/censorship risk; see PHASE3-RESULTS §L.6. |
8 — QTL sequentiality |
Request the exact assumptions, construction-specific argument and resource model behind the blanket quantum “no shortcut” claim for the planned SHAKE chain. Qualify the text until reviewed. This is not a newly demonstrated QTL attack; QTL was not changed or tested here. |
9 — checksum wording |
Qualify “always catches a typo” using the actual BIP-350 guarantees and preserve WO-04’s separation between framing/checksum acceptance and address/consensus validity. |
10 — integration scope |
Record responsibility for authenticating expected roots, validating event IDs/bodies, defining a proof wire format and enforcing block/P2P resource limits. The diagnostic raw root and test CLI must not become consensus interfaces by accident. Recommend retaining WO-03b’s approved scope and assigning these downstream tasks explicitly. |
Already resolved in the decision log: event sort/format decision 1, count binding decision 2, and provisional mining-cost correction 3. They are not reopened here. The enormous-count fixtures are wrapper tests only; benchmark rates are host-specific; local tests do not replace independent review. Those evidence limits remain explicit in the Results section above.
Reproduce / surprise exam commands¶
cmake --preset release && cmake --build --preset release && ctest --preset release
cmake --preset sanitize && cmake --build --preset sanitize && ctest --preset sanitize
python3 -B e46/golden/generate_wo03b.py --check
Fresh reference: e46/golden/merkle_bound_reference.py. Historical
merkle_reference.py remains frozen and describes the old unbound tree.
The active differential script is e46/tests/verify_wo03b.py; the original
verify_wo03.py remains historical and should not be run against the new API.
python3 -B e46/tests/verify_wo03b.py --cli build/release/merkle_cli --golden e46/golden/wo03b-golden.json --seed <reviewer-seed>
The optional seed adds 1,000 fresh trees and is not printed by the verifier. Builder tests do not constitute Claude’s independent exam.
CLI change¶
Requests retain their WO-03 spelling. proof and event_proof now return:
OK <leaf-hex-or-dash> <index> <leaf_count> <sibling-hex> ...
That record can be supplied directly after verify <bound-root-hex>. Verification
returns OK 1 or OK 0; malformed input returns ERR. Counts/indices in this
test protocol are decimal; the hashed count is always eight little-endian bytes.
No consensus/network proof wire format has been introduced.
Two diagnostic commands are available:
tree_root <leaf-hex> ...
bind <count> <raw-tree-root-hex>
Light-client clarification¶
The transaction and event roots sit alongside each other in the header. Merkle inclusion was possible before count binding; this change also authenticates the claimed count. A proof does not establish full block validity or current unspent status. Header height is inferred from chain position, not a height field in the 120-byte header. QTL depth/decay calculations additionally need the relevant validated chain context and transaction/output data. No light client, ASERT validator or Rad validator was implemented by this work order.
Paradox A remains in force: WO-08/09 must measure exact §2g message formats and nonce-bound puzzles before fixing mining parameters. No installations, pushes, merges or later work orders. Owner map edits and the separate PR proposal remain outside these implementation commits.