rvf-wasm: verify_checksum always succeeds, witness_count always fails, store_open transposes count/dim and accepts anything
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 4.5k
- Forks
- 603
- Avg merge
- 23h 32m
- Merged PRs (30d)
- 59
Description
Three defects in the published @ruvector/rvf-wasm@0.1.9 microkernel, found while building an independent browser RVF viewer (rvQR) against the C-ABI. All reproduced directly against pkg/rvf_wasm_bg.wasm with a genuine 2304-byte container from rvf-cli (24 vectors, dim 16, 4 segments).
1. rvf_verify_checksum never detects corruption (most serious)
pristine container -> 0 (success)
one payload byte flipped -> 0 (success)
2304 bytes random noise -> 0 (success)
empty buffer -> -1 (error)
It succeeds on everything except an empty buffer. A verification primitive that always returns success is worse than an absent one, because callers reasonably surface it as "integrity verified" — a false guarantee, and this is a security-relevant API.
Note the container also carries no reference CRC to compare against: I checked all 64 header bytes of every segment. So it isn't clear the function can do what its name promises with the current segment format. Either give segment headers a stored checksum and verify against it, or rename/remove the export so nobody builds a trust decision on it.
2. rvf_witness_count returns -1 for every non-zero length
rvf_witness_count(68) -> -1
rvf_witness_count(0) -> 0
The demo container has a real 68-byte WITNESS segment. The chain cannot be counted or verified through the wasm API.
3. rvf_store_open transposes count/dim, and opens anything
store_open(valid container) -> handle 1, count=16, dim=24 (container is 24 vectors x dim 16)
store_open(random noise) -> handle 2 (no error)
The count/dim swap is confirmed by arithmetic: the Vec segment is 1734 bytes = 6 + 24 x (8 + 16 x 4), which only works for 24 vectors of dimension 16. Because the fields are swapped, rvf_store_query strides at the wrong record size and returns ids that are fragments of vector data rather than real ids.
Separately, store_open returns a valid-looking handle for arbitrary bytes — random noise and the wasm binary itself — so a successful open must not be treated as validation by any caller.
Reproduction
const w = (await WebAssembly.instantiate(fs.readFileSync('pkg/rvf_wasm_bg.wasm'), {})).instance.exports;
const put = b => { const p = w.rvf_alloc(b.length); new Uint8Array(w.memory.buffer, p, b.length).set(b); return p; };
const p = put(bytes);
w.rvf_verify_checksum(p, bytes.length); // 0 for anything non-empty
const h = w.rvf_store_open(p, bytes.length);
w.rvf_store_count(h); w.rvf_store_dimension(h); // transposed
(The kernel takes zero imports, so {} is the whole instantiation contract — pleasant to work with otherwise.)
Impact / workaround in the meantime
rvQR now surfaces all three as unavailable/warn rather than as passing checks, reads the Vec segment directly for count/dim/search instead of trusting store_open, and displays the kernel-vs-direct disagreement rather than silently picking a winner. Happy to send that probe harness if useful.
Also worth noting for the ADR-009 discussion in #775: the segment walker itself is correct — segment_count/segment_info enumerate all 4 segments accurately and account for every one of the 2304 bytes.
🤖 Generated with claude-flow
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the rvf_verify_checksum, rvf_witness_count, rvf_store_open, rvf_store_count, and rvf_store_dimension exports in pkg/rvf_wasm_bg.wasm and reproduce the results using the supplied JavaScript harness and 2304-byte container. Compare the exports with the segment format and C-ABI expectations. Done means checksum behavior and witness counting are defined and correct, count/dimension are not transposed, and invalid input is rejected or explicitly documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, wasm
- Domain
- backend-api-design, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100