smallmoduli.h 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. /*
  2. * Shared code between algorithms whose state consists of a large
  3. * collection of residues mod a small prime.
  4. */
  5. /*
  6. * We need to do modular arithmetic on small values (considerably
  7. * smaller than 2^16), and we need to do it without using integer
  8. * division which might not be time-safe. Input values might not fit
  9. * in a 16-bit int, because we'll also be multiplying mod q.
  10. *
  11. * The strategy for this is the same as I used in
  12. * mp_mod_known_integer: see there for the proofs. The basic idea is
  13. * that we precompute the reciprocal of our modulus as a fixed-point
  14. * number, and use that to get an approximate quotient which we
  15. * subtract off. For these integer sizes, precomputing a fixed-point
  16. * reciprocal of the form (2^48 / modulus) leaves us at most off by 1
  17. * in the quotient, so there's a single (time-safe) trial subtraction
  18. * at the end.
  19. *
  20. * (It's possible that some speed could be gained by not reducing
  21. * fully at every step. But then you'd have to carefully identify all
  22. * the places in the algorithm where things are compared to zero. This
  23. * was the easiest way to get it all working in the first place.)
  24. */
  25. /* Precompute the reciprocal */
  26. static inline uint64_t reciprocal_for_reduction(uint16_t q)
  27. {
  28. return ((uint64_t)1 << 48) / q;
  29. }
  30. /* Reduce x mod q, assuming qrecip == reciprocal_for_reduction(q) */
  31. static inline uint16_t reduce(uint32_t x, uint16_t q, uint64_t qrecip)
  32. {
  33. uint64_t unshifted_quot = x * qrecip;
  34. uint64_t quot = unshifted_quot >> 48;
  35. uint16_t reduced = x - quot * q;
  36. reduced -= q * (1 & ((q-1 - reduced) >> 15));
  37. return reduced;
  38. }
  39. /* Reduce x mod q as above, but also return the quotient */
  40. static inline uint16_t reduce_with_quot(uint32_t x, uint32_t *quot_out,
  41. uint16_t q, uint64_t qrecip)
  42. {
  43. uint64_t unshifted_quot = x * qrecip;
  44. uint64_t quot = unshifted_quot >> 48;
  45. uint16_t reduced = x - quot * q;
  46. uint64_t extraquot = (1 & ((q-1 - reduced) >> 15));
  47. reduced -= extraquot * q;
  48. *quot_out = quot + extraquot;
  49. return reduced;
  50. }