Repository navigation
Unify memcpy, memmove, memset and commit on one accelerator - #984
Merged
Merged
Conversation
Routes the guest's strong `memset` symbol through a bounded DMA ecall, the same shape as the memcpy stub #874 added, and proves each chunk with a new 20-column DMA_SET table. memset is cheaper than memcpy rather than a copy of it: there is no source to read, so a row emits one MEMW write and no read (half the memory traffic per byte), and every byte written is the same constant, so one `fill` column replaces memcpy's eight value lanes. `fill_wide` is `fill` on eight-byte rows and zero on one-byte tail rows, which lets one write tuple serve both widths. `fill <= 255` is proven on the first row; the executor rejects wider values and the guest stub masks a1, mirroring how the byte-count bound is handled. Measured on real mainnet block 25368371 (50,781,394 cycles baseline): #874 memcpy alone 41,642,609 -17.99% + memset (this) 40,338,153 -20.57% mem* routines fall from 24.41% to 4.84% of guest cycles. No existing AIR changes: CPU stays at 38 columns and the new table only adds senders to existing buses.
The DMA memcpy ecall already snapshots its entire source range before writing (all reads at T+1, all writes at T+2), so one chunk has memmove semantics for free. Chunking is what breaks it: copying [0,256) -> [4,260) clobbers source bytes a later forward chunk still needs. So the memmove stub walks chunks from the END backwards exactly when the destination starts inside the source range (src < dst < src+n); every chunk then reads bytes no earlier chunk has written. Disjoint regions, and dst below src, keep forward chunking. This costs one guest symbol and nothing else — no table, no syscall, no constraint. Measured on real mainnet block 25368371: memcpy + memset 40,338,153 + memmove (this) 39,867,443 -0.93% Cumulative vs the 50,781,394 baseline: -21.49%. The guest test covers both overlap directions at offsets either side of the 256-byte chunk boundary, plus exact aliasing.
Resolve the accelerator() conflict: the base gained DMA cycle counting (DmaMemcpy => Some(Accelerator::Dma)) while this branch added DmaMemset and classified both as None. Keep the counting semantics and extend them: DmaMemcpy | DmaMemset => Some(Accelerator::Dma). Two exhaustiveness follow-ups the merged tree needs to compile and pass: - SyscallNumbers::raw() gets the DmaMemset arm (DMA_MEMSET_SYSCALL_NUMBER). - The CLI's EXPECTED_ACCELERATORS gets a DmaMemset row, required by accelerator_of_mirrors_prover_classification's one-row-per-syscall check.
|
Benchmark Results for unmodified programs 🚀
|
Collaborator
Author
|
/bench |
Collaborator
Author
|
/bench-verify |
|
⏳ Benchmark started on the bench server. Two verifier arms (monolithic + continuations over an ethrex 20-tx block), then the recursion-guest cycle comparison, which adds guest builds on top — longer on a cold runner. The bench server is occupied until it finishes. |
jotabulacios
approved these changes
Oct 15, 2026
…he COPY table in disk mode.
) * Correct comments and test data left stale by the COPY unification - Name COPY (not COMMIT) among the ECALL receivers and as the Commit-bus sender. - Count five accelerators, not six, and rename the test that says six. - logs.rs: the row width follows from the count alone; it no longer reads src % 8 / dst % 8. - CLI accel_counts_sizes_dma_calls: derive rows with copy_trace_rows instead of the old terminal-row schedule. - Drop the doubled #[cfg(test)], the DMA/DMA_SET history line, the stale drift-test doc, the allocator and dma_memset_min comments. * Call COPY's Commit-syscall rows commit rows in the comments
MauroToscano
approved these changes
Oct 23, 2026
MauroToscano
enabled auto-merge
October 23, 2026 16:38
MauroToscano
added a commit
that referenced
this pull request
Oct 23, 2026
Resolve the two conflicts with #984 (COPY replaces COMMIT): - trace_builder.rs BITWISE collectors: keep COPY's collector from main and this branch's KECCAK_RND padding count (keccak_rnd::padding_are_bytes). - skip_empty_tables_tests.rs: COMMIT left the optional-table list (17 tables); keep this branch's ARE_BYTES exemption imports.
MauroToscano
added a commit
that referenced
this pull request
Oct 23, 2026
Brings in main's #984 (COPY replaces COMMIT) through #1016's branch. Conflicts resolved by keeping both sides: - TableCounts / statement / VmAirs / Traces: drop commit, keep is_wh and copy. - BusId: IS_WH = 32 next to COPY's CopyNext = 33. 32 was one of the two IDs main's comment listed as unused; 29 and 34 stay unused. - RECURSION_INPUT_VERSION 5 with a v5 note: main's v4 already means the layout without commit, so is_wh needs its own number. - Tests: counts 20 / 18 / 6, the accelerator test renamed to a_run_without_accelerators_omits_all_five_and_is_wh, COMMIT's omission tests dropped as on main, and main's committed-output test kept with this branch's "dropping ..." message style.
MauroToscano
added a commit
that referenced
this pull request
Oct 23, 2026
Brings in #984 (COPY replaces COMMIT, x254 becomes two words) and #1016. Conflicts: - lib.rs: keep the pinned REGISTER commitment and add main's COPY AIR. - register.rs: keep the single OFFSET/INIT/FINI/IS_PC commitment; x254 is at 508-509 now. - trace_builder.rs: drop the COMMIT aux count; REGISTER takes final_pc_ts. - constraint-program tests: CPU with ts_base 0 plus main's COPY check. Changes the merge needs without a textual conflict: - cpu_start: COPY is a fixed table ahead of REGISTER and COMMIT is gone, so the first CPU sub-proof is at 5 + HALT + the five accelerators. The air_refs debug check and cpu_proof_start_matches_air_refs_layout (now 32 masks) follow. - collect_epoch_from_cpu_ops returns Result: main made collect_ops_from_cpu fallible. - multiplicity_forgery_poc: VmAirs::new takes the CPU heights and the REGISTER commitment; the prover commits to its own trace.
MauroToscano
added a commit
that referenced
this pull request
Oct 25, 2026
Brings in main's copy accelerator (#984), table multiplicity fix (#1016), IS_WH table (#1022), and final-PC pin with preprocessed CPU timestamp (#1020, #1025), adapted to the block: - COPY is a counted table in COMMIT's place, cut into tables of 2^20 rows in the block; its bus is 36 and IS_WH's 37. - The multiplicity fix's per-row lookups are counted per chunk in the finish, the streamed walk and the windowed builder. - IS_WH is built at the finish, at most one table, counted last. - Each CPU table has its own AIR (its timestamp base) and a preprocessed TIMESTAMP; REGISTER's FINI is the halted file. The block builds its AIRs from the stated CPU heights (each at most 2^21 rows, at most 2^30 - 1 in all), and the verifier and the recursion leaves evaluate TIMESTAMP themselves (4 + 4 times the row index's value at the point), with no commitment. - Every statement tag over the count list moves (DOMAIN and CONTINUATION EPOCH V6, MULTILINEAR V3, MULTILINEAR BLOCK and MULTILINEAR EPOCH V2), the block proof file is version 2 and RECURSION_INPUT_VERSION is 6, past both sides.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
mainhas no accelerator formemcpy,memmoveormemset, and proves thewritesyscall with a dedicated COMMIT chip. This adds the three memory operations and foldswriteinto the same chip, following the merged COPY spec.Description
One
COPYtable (41 columns, 33 bus interactions, 39 constraints, degree 3) servesmemcpy/memmove,memsetandwrite. The COMMIT chip is deleted.Which operation a row runs is decoded, never chosen by the caller: the ECALL number is a linear function of
is_setandis_write, so the three accepted numbers are exactly 64, -30 and -31 and nothing else; both flags ride inside the chain tuple, so a sequence cannot change operation half way through.memsetis a propagating copy. The stub seeds eight bytes and calls withdst = src + 8; the chip inverts the read/write timestamps so each row observes the previous row's write. The gap is pinned in-circuit: without it adst == srccall would leave the copied value unconstrained.writereads its destination fromx254, the running commit index, writesdst + countback, checks the file descriptor is 1 and returnscountinx10.endis pinned byrestrict_endagainst the borrow out ofcount - step.count == 0.ECALL renumbering:
memsetmoves to -31 to match the spec, andhintto -32.x254becomes a two-word register (addresses 508-509), so the register file grows by one word address. Every guest ELF must be rebuilt: in-tree artifacts are gitignored and rebuild automatically, but build caches and the bench box will not.