ML-DSA on x86-64: the norm check and MakeHint with AVX2 (sign −8% instructions) - #519
Merged
alex merged 6 commits intoOct 2, 2026
Conversation
vg_mldsa_norm_lt_avx2 and vg_mldsa_make_hint_avx2 compute on eight coefficients at a time, in the VEX.256 form of SSE2 code on the four doublewords of each 128-bit lane, as HighBits and LowBits do. norm_lt clamps the public bound to q (which changes no result), so that a - b and (q - b) - a fit in 32 bits and one of them is negative exactly when a coefficient is out of bounds; it ANDs their ORs into an accumulator, spreads its sign bits and returns (vpmovmskb + 1) >> 32. There is no branch on data. make_hint computes r₁ of r and of (r + z) mod q with hbX, the hint as (r₁ ^ r₁' + 63) >> 6, and counts the eight hints of an iteration from the byte mask of the hints shifted to bit 7 (vpmovmskb), summing its nibbles with three shifts and additions. Both join the polynomial arithmetic's backend, as variants of vg_mldsa_norm_lt and vg_mldsa_make_hint, so signing (both) and verification (norm_lt) with AVX2 call them. The proofs: YNorm (the differences, the mask and the result) and YHint (the hint in a doubleword, the count, the loop, and the count is hintOnes). Instructions (callgrind, AVX2), 20 deterministic signatures: ML-DSA-44 58.2M → 53.5M (−8.0%), ML-DSA-65 82.2M → 75.5M (−8.2%), ML-DSA-87 113.8M → 106.1M (−6.8%); 20 verifications: 23.5M → 23.0M (−2.0%), 35.7M → 35.4M (−0.8%), 72.0M → 70.2M (−2.4%). The baseline is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
This was referenced Oct 1, 2026
…ent-einstein-ukl7t7-ynorm Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
…ent-einstein-ukl7t7-ynorm Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
…ent-einstein-ukl7t7-ynorm Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
…ent-einstein-ukl7t7-ynorm The Backend has highBits, lowBits, normLt, makeHint and rej4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
alex
pushed a commit
that referenced
this pull request
Oct 2, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
alex
pushed a commit
that referenced
this pull request
Oct 2, 2026
Main has #513, #519 and #523, which this branch already has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
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.
Stacked on #513 (HighBits and LowBits with AVX2); only the last commit is new.
This PR is an implementation only. It changes nothing in
Spec/orTCB/.What
vg_mldsa_norm_lt_avx2andvg_mldsa_make_hint_avx2work on eight coefficients at a time. In each 128-bit lane they run the VEX.256 form of SSE2 code over the lane's four doublewords, the same wayhigh_bits/low_bitsdo in #513.norm_ltqfirst. This branches only on the public bound and doesn't change the result, because every reduced coefficient is belowq.a - band(q - b) - aboth fit in 32 bits, and one of them is negative exactly when a coefficient is out of bounds.vpsrad31), and the result is(vpmovmskb + 1) >> 32.make_hintr₁ofrand of(r + z) mod qcomes fromhbX(from ML-DSA on x86-64: HighBits and LowBits with AVX2 (sign −4% instructions) #513), withvcsubin between. The hint is((r₁ ^ r₁') + 63) >> 6.vpmovmskbbyte mask of the hints shifted to bit 7, computed with three shift-and-adds and added tor9.Both are added to the
MlDsaArithbackend as variants ofvg_mldsa_norm_ltandvg_mldsa_make_hint. With AVX2, signing calls both and verification callsnorm_lt.check_variantspasses.The sign and verify call lemmas for these two callees (
normCall_ok/_tr,hintCall_ok/_tr) now take any callee name, asbitsAt_okalready did.Proofs
Round/YNorm.leannlL_msb)vpmovmskbof all-set sign bits giving the resultRound/YHint.leanmakeHint(mhL_toNat)nib_bools, decided over the 256 cases, andbsum_sp)hintOnes(csum_onesFrom)Constant time for both uses
taint_decide.Measurements
Instructions measured with callgrind, AVX2 configuration, compared with #513:
With
VG_CPU_FEATURES=nonethe counts are unchanged.Checks
Run locally, all passing:
lake buildEmit.leancheck_lean_imports,check_lean_speed,check_vectors,check_arch_gates,check_variants,check_mcdtcargo fmt/clippycargo testwith Wycheproof, both with default features and withVG_CPU_FEATURES=none --features cpu-features-envThe README algorithm table was regenerated with
ci/algorithms_table.py.🤖 Generated with Claude Code
https://claude.ai/code/session_01Ddof3szoTi7HB8iCsM2MCr
Generated by Claude Code