Skip to content

refactor(prover): centralize u64 limb decomposition (dword_wl/dword_hl)#697

Open
MauroToscano wants to merge 2 commits into
mainfrom
refactor/dword-limb-helpers
Open

refactor(prover): centralize u64 limb decomposition (dword_wl/dword_hl)#697
MauroToscano wants to merge 2 commits into
mainfrom
refactor/dword-limb-helpers

Conversation

@MauroToscano

@MauroToscano MauroToscano commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What

Centralizes the repeated u64 -> little-endian limb decomposition that was open-coded across ~20 VM trace tables into two helpers in prover/src/tables/types.rs:

pub fn dword_wl(x: u64) -> [FE; 2]   // [x[0..32], x[32..64]]        (DWordWL)
pub fn dword_hl(x: u64) -> [FE; 4]   // [x[0..16], .., x[48..64]]    (DWordHL)

Call sites destructure and assign, so only the decomposition is dedup'd — the column assignments stay explicit:

let [pc_0, pc_1] = dword_wl(op.pc);
data[base + cols::PC_0] = pc_0;
data[base + cols::PC_1] = pc_1;

Why plain functions, not methods on Table

The limb width is field-size-specific: FE::from(u64) reduces mod p, so a 32-bit limb is only faithful because Goldilocks is ~64-bit. On a ~31-bit field (e.g. BabyBear) it would silently corrupt. So this belongs in the prover (which fixes the field), not the field-generic Table<F> storage type.

Scope

Converted only consecutive-column FE writes (verified consecutive in each cols module). Deliberately left as-is: parametric column indices (cols_i[..], lo_col), DWordWHH (Word+Half+Half) groups, byte/nibble splits, sign-extended [u64; 8] arrays (mul), and [u16;4]/[u32;4] bus/struct arrays.

Correctness

Byte-identical trace output. cargo test -p lambda-vm-prover --lib: 416 passed; the only 5 failures are *ecsm* prove tests that fail identically on main (pre-existing UnknownSyscall in the executor, upstream of trace generation). cargo fmt + cargo clippy clean.

Relationship to #693

Supersedes #693 (the original set_limbs_* approach) — part 1 of 2. Part 2 is a separate PR that makes Table.data private and routes the post-build multiplicity updaters through set_main (fixing a latent disk-spill hazard).

…rd_hl

Replace the open-coded little-endian limb decomposition repeated across ~20
trace tables with two helpers in tables::types:

  dword_wl(x) -> [FE; 2]   2x32-bit limbs (DWordWL)
  dword_hl(x) -> [FE; 4]   4x16-bit limbs (DWordHL)

Kept as plain prover functions rather than methods on the generic Table: the
limb width is field-size-specific (a 32-bit limb only fits because Goldilocks
is ~64-bit, since FE::from reduces mod p), so this logic belongs in the prover,
not the field-generic storage type.

Only consecutive-column FE writes were converted (consecutiveness checked in
each cols module). Parametric column indices, DWordWHH/byte/nibble groupings,
sign-extended arrays, and bus-value arrays were left as-is.

Byte-identical: prover lib tests pass 416 (the 5 ecsm failures are
pre-existing/environmental, identical on main). fmt + clippy clean.

Supersedes #693 (1/2).
…ites

Address review on #697: route the last few open-coded decompositions through
dword_wl/dword_hl so the split is truly single-source:

- ecsm::write_dword_wl now calls dword_wl(value) internally (keeps its
  parametric-column flexibility, drops the duplicated 2x32 split)
- cpu res loop -> zip cols::RES with dword_hl(res)
- memw old_timestamp loop -> dword_wl(op.old_timestamp[i])

Byte-identical: prover lib tests 416 pass (the 5 ecsm failures are
pre-existing/environmental); fmt + clippy clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant