Special-Prime Tricks
August 25, 20264 min readbeginner
The three general methods work for any modulus. When the modulus has a particular shape, reduction can be done with no multiplication whatsoever.
The three general methods work for any modulus. When the modulus has a particular shape, reduction can be done with no multiplication whatsoever. One of the two standardised moduli has that shape.
01.ML-DSA's modulus is a Solinas prime
A prime of the form with small and is called a Solinas prime, and the useful consequence is immediate. Rearranging,
That is checkable directly: , and .
Now take any and split it at bit 23:
Substituting the congruence,
Read the right-hand side. A shift by 13, an addition, and a subtraction. No multiplication at all.
02.A worked example
Take .
Split it: and .
Fold:
Check: , and . They agree.
Note that one pass did not finish the job. The folded value is about , still too large. A second pass, or one or two conditional subtractions, completes the reduction. That is normal for this technique: each pass shrinks the value substantially, and a small fixed number of passes suffices for the whole input range.
Even counting two passes, the cost is a handful of shifts and adds against the two multiplications a general method needs. Every production ML-DSA implementation uses this.
03.ML-KEM's modulus does not have the shape
That factorisation is the reason was chosen, as Chapter 4 explained: the supports the transform, and the small size keeps coefficients at 12 bits.
But has no Solinas structure. It is not close to a power of two in the way that would let shifts substitute for multiplication, and no comparable trick is known for it. For reduction alone, generic Barrett or Montgomery with a precomputed constant gives the best published throughput.
04.The consequence for a shared accelerator
This asymmetry matters, and it is the sharpest constraint on a design serving both standards.
Almost everything else can be shared. The butterfly skeleton is the same operation in both schemes. The memory banking problem is the same. The Keccak engine is identical, since both schemes use the same permutation. Even the ring degree is the same, at .
The reduction tail cannot be shared. ML-DSA wants shifts and adds against a 23-bit modulus. ML-KEM wants a multiplier-based method against a 12-bit one. Those are different circuits, not one circuit with a parameter.
So a unified design has to either instantiate both reduction paths and select between them, paying area for the one not in use, or use the general method for both and give up the free performance on the signature side.
Which of those is the better trade, and at what efficiency cost, is a concrete open question rather than a settled one. It is the natural companion to the shared-transform question from Chapter 4, and together they are the design space the research arc behind this book is aimed at.
The fact that this constraint exists at all traces back to a decision made for entirely unrelated reasons. ML-KEM's modulus is small because 12-bit coefficients vectorise well, and ML-DSA's is Solinas-shaped because the signature needed dynamic range and the shape came along with it. Neither committee was thinking about a shared accelerator, and the two choices happen not to compose.