Skip to content

Additional set of CU optimizations - #13

Merged
samkim-crypto merged 18 commits into
solana-program:mainfrom
samkim-crypto:final-opt
Sep 17, 2026
Merged

samkim-crypto merged 18 commits into
solana-program:mainfrom
samkim-crypto:final-opt

Conversation

@samkim-crypto

@samkim-crypto samkim-crypto commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary of Changes

I worked through a series of optimizations and kept the changes that reduced compute units.

I first made a bunch of harness and test improvements:

  • Previously, we didn't meter the Sha512 syscall in the CU, so I fixed this.
  • Added a reproducible 32-case signature corpus coving four signing-eky seeds and eight message lengths
  • Extended scalar reduction comparisons against curve25519-dalek with boundary values and deterministic random inputs
  • Added coverage for 14 ZIP-215 torsion endocindgs
  • Added rejection tests for a non-canonical signature scalar and an invalid public-key encoding

The optimizations I kept are listed below. Each saving compares the change with the preceding retained change.

  • Replaced bit-serial scalar reduction with 32-bit Barrett reduction (368217b): The original reducer processed all 512 input bits individually. Barrett reduction uses a precomputed reciprocal to estimate the quotient and then corrects the remainder. At this stage, the 38-byte signature fixture consumed 5,083 CUs, and the 32-case corpus consumed 164,817 CUs.
  • Unrolled the reciprocal multiplication rows (0eddd88). Expanding the fixed multiplication rows gives the compiler explicit limb operations and removes loop overhead from the Barrett quotient calculation. This reduced the fixture from 5,083 to 4,811 CUs, saving 272 CUs, and saved 8,697 CUs across the corpus.
  • Wrote the challenge directly into the scalar buffer (c9f2d92). The reduced challenge now goes directly into the buffer passed to multiscalar multiplication, avoiding an intermediate scalar return and copy. This reduced the fixture from 4,811 to 4,799 CUs, saving 12 CUs, and saved 375 CUs across the corpus.
  • Simplified the top-limb borrow calculation (2185333). The reducer’s limb bounds allow redundant borrow bookkeeping to be removed from the final correction. This reduced the fixture from 4,799 to 4,798 CUs, saving 1 CU, and saved 67 CUs across the corpus.
  • Used sparse order multiplication in Barrett reduction (e06fbe9). Multiplying the quotient estimate by the group order now takes advantage of the order’s zero limbs, eliminating products that cannot contribute to the result. This reduced the fixture from 4,798 to 4,791 CUs, saving 7 CUs, and saved 224 CUs across the corpus.
  • Inlined the verifier into its caller. Inlining verify_signature lets the compiler optimize the verification path together with the caller’s fixed configuration. This reduced the fixture from 4,791 to 4,777 CUs, saving 14 CUs, and saved 462 CUs across the corpus.
  • Replaced Barrett reduction with radix-21 reduction. The final reducer folds signed 21-bit limbs using the group-order relation 2^252 = -c (mod L), with arithmetic carried out in 64-bit intermediates. This reduced the fixture from 4,777 to 4,145 CUs, saving 632 CUs, and reduced the corpus from 154,992 to 134,776 CUs, saving 20,216 CUs.
  • Batched carry propagation in radix-21 reduction (b6240ee). Carry propagation now runs after groups of folding operations, reducing the number of normalization passes while keeping the intermediate values within their bounds. This saved 262 CUs in every corpus case, reducing the fixture from 4,145 to 3,883 CUs and saving 8,384 CUs across the corpus.
  • Used a torsion lookup for the ZIP-215 fallback. The verifier checks the canonical difference point against the torsion encodings instead of multiplying that point by eight through three doublings. This reduced each tampered-message and tampered-public-key test from 5,952 to 4,430 CUs, saving 1,522 CUs. The 14-case torsion suite dropped from 76,558 to 61,276 CUs, saving 15,282 CUs, with no change to the ordinary valid-signature corpus.
  • Used a fixed two-term multiscalar multiplication wrapper. The SBF path calls the syscall through a wrapper specialized for exactly two scalar-point pairs, while native builds retain the SDK implementation. This saved 27 CUs in every corpus case, reducing the fixture from 3,883 to 3,856 CUs and the corpus from 126,392 to 125,528 CUs.
  • Used a torsion lookup for strict small-order checks. Each input point is validated and converted to a canonical encoding by adding the identity, then checked against the torsion encodings. This replaces three doublings per input while preserving malformed-input rejection and support for permitted non-canonical encodings. Strict verification dropped from 7,019 to 4,989 CUs for the fixture, saving 2,030 CUs (28.92%); the strict corpus dropped from 226,744 to 161,784 CUs, saving 64,960 CUs (28.65%). Default ZIP-215 costs were unchanged.

Overall, we started with ~30k CU for a single ZIP-215 signature verification to ~3.8k CU, which is good.

I do need one additional follow-up to bump the versions of some crates like mollusk and also use sbf arch v3, but I am satisfied with all the optimizations, so once this PR is in, I think we can kick-off the audit.

@samkim-crypto
samkim-crypto marked this pull request as ready for review September 9, 2026 01:36
@samkim-crypto
samkim-crypto requested a review from zz-sol September 9, 2026 01:36
@zz-sol

zz-sol commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

@zz-sol

@zz-sol zz-sol left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. just two nits.

Comment thread README.md Outdated
figure above is the addition syscall charge in the benchmark runtime; the total
check also includes the surrounding SBF instructions.

Canonical `S` (`S < L`) has no knob. Every profile worth targeting requires it —

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo —

Comment thread ed25519-verify/src/verifier.rs Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this still says “before paying for the cofactor multiplication.” This branch replaces multiplication with lookup.

@samkim-crypto

Copy link
Copy Markdown
Contributor Author

Thanks for taking a look! I addressed the wording comments and will merge!

@samkim-crypto
samkim-crypto merged commit a749bd1 into solana-program:main Sep 17, 2026
21 checks passed
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.

2 participants