Skip to content

perf: use double-and-add for MSMs below 32 bases - #3594

Draft
cbeck88 wants to merge 2 commits into
stagingfrom
perf/small-msm-double-and-add
Draft

cbeck88 wants to merge 2 commits into
stagingfrom
perf/small-msm-double-and-add

Conversation

@cbeck88

@cbeck88 cbeck88 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

batched::msm uses double-and-add below 15 bases.
From 15 to 31 bases, it uses the bucket method with a window of one bit.
That is 253 windows, and each window does its own batched inversions over a few points.
At 32 bases and above, the window grows, and the cost drops again.

Verification of a private fee does one G1 MSM of 25 bases, for the record's inclusion circuit.
A public fee and a transfer_public execution do G1 MSMs of 13 bases or fewer.

This PR uses double-and-add below 32 bases. The bucket method with a one-bit window is then not reachable, so the PR removes it.

Commits:

  • test: cover MSM sizes at the batched path's thresholds adds 14, 15, 25, 31, 32 and 33 bases to test_msm. The test passes before and after the change.
  • perf: use double-and-add for MSMs below 32 bases raises the cutoff from 15 to 32.

One G1 MSM, one core (taskset, RAYON_NUM_THREADS=1), median of 300 interleaved repetitions. Host: Intel Xeon w9-3475X.

bases staging standard::msm double-and-add
13 1367 µs 1422 µs 1372 µs
15 8585 µs 1133 µs 1077 µs
25 10687 µs 1747 µs 1696 µs
31 11828 µs 2162 µs 2095 µs
32 2806 µs 2068 µs 2159 µs
64 4050 µs 3551 µs 4236 µs

check_transaction of a credits.aleo/transfer_public at ConsensusVersion::V22 (Varuna V3), with the verified-transaction cache cleared before each call, one core, pinned. Both arms include #3591. Each row is 6 interleaved blocks.

before after change blocks faster
check_fee, private fee 19.21 ms 10.21 ms −46.8% 6 of 6
check_transaction, private fee 26.89 ms 18.16 ms −32.8% 6 of 6
check_fee, public fee 7.88 ms 7.85 ms −1.0% 4 of 6
check_transaction, public fee 15.87 ms 15.50 ms −1.1% 6 of 6

On 72 threads, each iteration checks 72 transactions in parallel. Each row is 6 interleaved blocks.

before after change blocks faster
private fee 922 tx/s 1155 tx/s +25% 6 of 6
public fee 1317 tx/s 1331 tx/s +1% 3 of 6

The public-fee rows do no MSM in the changed range.

Test Plan

  • cargo test --release -p snarkvm-algorithms (115 passed)
  • cargo clippy -p snarkvm-algorithms --all-targets [--features serial] -- -D warnings
  • cargo +nightly-2026-04-02 fmt --all -- --check
  • The end-to-end numbers use ledger/benches/verify_transaction.rs from bench: measure transaction verification without the verified-transaction cache #3592: cargo bench -p snarkvm-ledger --bench verify_transaction --features test_consensus_heights.

Documentation

None.

Backwards compatibility

No consensus change. An MSM returns the same group element; test_msm compares both paths with a naive MSM at every size above.

🤖 Generated with Claude Code

https://claude.ai/code/session_017omPAWn5XC7EA2aMFGn7FC

cbeck88 and others added 2 commits October 20, 2026 21:36
test_msm now checks 14, 15, 25, 31, 32 and 33 bases, on each side of
batched::msm's switch from double-and-add (below 15) and its single-bit
window (below 32).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017omPAWn5XC7EA2aMFGn7FC
batched::msm gave 15 to 31 bases a single-bit window: 253 windows, each
paying for its own batched inversions over a handful of points. At 25
bases that took 11.1 ms on one core, against 1.8 ms for double-and-add,
which batched::msm already uses below 15 bases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017omPAWn5XC7EA2aMFGn7FC

This branch has not been deployed

No deployments
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