ML-DSA on x86-64: NTT and NTT⁻¹ in SSE2 (sign −48%, verify −35%) - #464
Merged
Merged
Conversation
vg_mldsa_ntt and vg_mldsa_inv_ntt now compute on four coefficients at a
time in SSE2 registers, as ML-KEM's x86-64 NTT does: a Montgomery
multiplication with pmuludq (the even doublewords, then the odd ones moved
down by pshufd), conditional additions of q with psrad masks, and for the
layers with len 2 and 1 the coefficients of two or four blocks gathered with
punpck{l,h}qdq (and pshufd) and interleaved back. The zetas are a table in
Montgomery form that the prologue stores in scratch; the multiplications run
inside ML-KEM's withMxcsr, so Intel's MCDT mitigation holds.
Proofs: the lanes' arithmetic (VArith), the butterflies on registers
(VLanes), the loads and stores of four coefficients and the zetas (VMem),
the layers (VLay, VLay21), and the functions (Ntt, NttInv). Signing and
verification now check that their code loads MXCSR only to restore it
(ctlOk, through a compositional ctlC for verification) rather than never,
since their primitives now do.
ML-DSA-65 on this machine: sign 1.53 ms -> 0.81 ms, verify 281 us ->
181 us, keygen 276 us -> 248 us.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
Member
Author
|
Generated by Claude Code |
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.
vg_mldsa_nttandvg_mldsa_inv_ntton x86-64 were scalar (a Barrett reduction with threemuls per butterfly) and were over half of signing's time (NTT⁻¹ alone 41%). They now compute on four coefficients at a time in SSE2 registers (baseline x86-64, so no new variant), following ML-KEM's x86-64 NTT:pmuludq(vmont,Impl/MlDsa/X86_64/Arith/Vec.lean): the even doublewords are multiplied directly; the odd ones are moved down withpshufd 0xF5and multiplied by the odd zetas (xmm12). For each productP,m = (P mod 2³²)·(−q⁻¹) mod 2³²is two morepmuludqs, and(P + m·q)/2³²is the high doubleword ofpaddq:psrlqmoves the even results down, and the odd results are already in place, sopormerges them. The result is in[0, 2q)for any doubleword input, andvcsub/vcadd(masks frompsrad) reduce.punpck{l,h}qdq. len = 1 gathers four blocks withpshufd 0xD8+punpck{l,h}qdq, and puts them back withpunpck{l,h}dq. NTT⁻¹ uses the same table ofζ·2³² mod q(the prologue stores it inscratchwith 128 64-bit immediates) and computesζ·(w[j+len] − w[j]), which is−ζ·(w[j] − w[j+len]). It then scales by256⁻¹withvmontby16382.withMxcsr(MXCSR saved throughscratch + 768, which the table overwrites in between).ci/check_mcdt.pypasses.Proofs
All untrusted. No changes to
TCB/orSpec/, and the contracts are unchanged.VArith:dword_montV(each lane of the register ismontof the lane product, viaredc_toNat), plus the conditional add/sub lemmas and butterflies lane by lane.VLanes:vbfly_ok,vibfly_okon registers. Each is onevrunover the SSE-only block.VMem:dlanes_load,polyIs_write2,vzeta_ok.VLay,VLay21: adapted from ML-KEM'sVLay/VLay42to doublewords, operating onfin place.Ntt,NttInv: the table store (dwordTab_ok), the layer chain,vscale_ok, andmx_correct(ML-KEM'swithMxcsr_okplusabiPreserved_of_ctl).ctlOk, as ML-KEM's top-level functions do. For verification, this goes through a new compositional check,ctlC(Proof/Framework/X86_64/Mxcsr.lean), so it keeps its evaluate-with-empty-primitives approach (verify_c).NttBfly,NttLoop,storeTab_ok) andstoreTabare removed. They are now unused.Performance
Criterion (
cargo bench -- mldsa), old and new back to back on the same machine. It is a shared cloud VM, so expect ±10% noise.The README table now reads "SSE2 NTT" for ML-DSA on x86-64 (
docs/algorithms/ml-dsa-*.toml, regenerated).Checks run locally
lake build(all 5527 jobs) andlake env lean --run Emit.lean. Onlysrc/asm/x86_64/mldsa.rschanged.check_lean_imports,check_lean_speed,check_vectors,check_arch_gates,check_variants,check_mcdt,algorithms_table --check: all pass.cargo fmt --checkandcargo clippy --all-targets -- -D warnings: clean.cargo testwith Wycheproof, with and withoutcpu-features-env: all pass.Follow-ups planned in separate PRs: SSE2 pointwise multiplication, AVX2 variants, and faster sampling.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
Generated by Claude Code