use crate::{Limb, Uint, WideWord, Word}; /// Returns `(hi, lo)` such that `hi * R + lo = x * y + z + w`. #[inline(always)] const fn muladdcarry(x: Word, y: Word, z: Word, w: Word) -> (Word, Word) { let res = (x as WideWord) .wrapping_mul(y as WideWord) .wrapping_add(z as WideWord) .wrapping_add(w as WideWord); ((res >> Word::BITS) as Word, res as Word) } /// Algorithm 14.32 in Handbook of Applied Cryptography pub const fn montgomery_reduction( lower_upper: &(Uint, Uint), modulus: &Uint, mod_neg_inv: Limb, ) -> Uint { let (mut lower, mut upper) = *lower_upper; let mut meta_carry = Limb(0); let mut new_sum; let mut i = 0; while i < LIMBS { let u = lower.limbs[i].0.wrapping_mul(mod_neg_inv.0); let (mut carry, _) = muladdcarry(u, modulus.limbs[0].0, lower.limbs[i].0, 0); let mut new_limb; let mut j = 1; while j < (LIMBS - i) { (carry, new_limb) = muladdcarry(u, modulus.limbs[j].0, lower.limbs[i + j].0, carry); lower.limbs[i + j] = Limb(new_limb); j += 1; } while j < LIMBS { (carry, new_limb) = muladdcarry(u, modulus.limbs[j].0, upper.limbs[i + j - LIMBS].0, carry); upper.limbs[i + j - LIMBS] = Limb(new_limb); j += 1; } (new_sum, meta_carry) = upper.limbs[i].adc(Limb(carry), meta_carry); upper.limbs[i] = new_sum; i += 1; } // Division is simply taking the upper half of the limbs // Final reduction (at this point, the value is at most 2 * modulus, // so `meta_carry` is either 0 or 1) upper.sub_mod_with_carry(meta_carry, modulus, modulus) }