Running mpn_add_n at less than 1 cycle/limb

Torbjörn Granlund tg at gmplib.org
Wed Sep 9 15:58:05 CEST 2026


Marc Glisse <marc.glisse at inria.fr> writes:

  Why though?
  Applications that use GMP for crypto in a way where side-channel
  attacks make sense are probably a small minority of all GMP uses, so
  that penalizes all the others. And for the applications that care,
  mpn_sec_* sends a much clearer message about the guarantees provided
  by the function. In most cases, mpn_add_n and mpn_sec_add_n would just
  point to the same code, which should have minimal impact on the size
  of the library.

I think you have a strong point.

It would be cool to code up a modern (i.e., not Pentium4-tailored)
mpn_add_n which breaks the dependency chain between blocks of limbs.

I suppose 4-limb blocks would be a start, and that one every 4th limb
checks if a plain add and the adc from the previous block yield
different carry-out, and if they do, jump to a fixup function (or use
cmov, perhaps).

I think one would need one add and four adc per such 4/limb block.  The
add would be for the top limb of the previous 4/limb block.

The handling of one limb needs at a minimum a load (aka mov from
memory), and adc from memory, and a store (aka mov to memory).  If we
have 4-way instruction issue, we would need >0.75 cycles/limb, and with
6-way issue we sould need >0.6 cycles/limb.  Of course, the code for
checking for a rippling carry (perhaps cmp+jCC or perhaps just a cmovz)
as well as loop control add some overhead.

It is pretty cool that we could add more than 1 limb pair per cycle on
an arch where add-with-carry need one cycle.

Perhaps we could similarly speed up the really important loops, i.e.,
mpn_addmul_[k] on CPUs with good mul/mulx thoughput?


-- 
Torbjörn
Please encrypt, key id 0xC8601622


More information about the gmp-devel mailing list