diff --git a/src/modular/boxed_residue.rs b/src/modular/boxed_residue.rs index 627d8956..ddf9ed36 100644 --- a/src/modular/boxed_residue.rs +++ b/src/modular/boxed_residue.rs @@ -21,6 +21,18 @@ use std::sync::Arc; #[cfg(feature = "zeroize")] use zeroize::Zeroize; +fn div_by_2(a: &BoxedUint, modulus: &BoxedUint) -> BoxedUint { + let (half, is_odd) = a.shr1_with_carry(); + let half_modulus = modulus.shr1(); + + let if_even = half.clone(); + let if_odd = half + .wrapping_add(&half_modulus) + .wrapping_add(&BoxedUint::one_with_precision(a.bits_precision())); + + BoxedUint::conditional_select(&if_even, &if_odd, is_odd) +} + /// Parameters to efficiently go to/from the Montgomery form for an odd modulus whose size and value /// are both chosen at runtime. #[derive(Clone, Debug, Eq, PartialEq)] @@ -159,6 +171,18 @@ impl BoxedResidue { } } + /// Performs the modular division by 2, that is for given `x` returns `y` + /// such that `y * 2 = x mod p`. This means: + /// - if `x` is even, returns `x / 2`, + /// - if `x` is odd, returns `(x + p) / 2` + /// (since the modulus `p` in Montgomery form is always odd, this divides entirely). + pub fn div_by_2(&self) -> Self { + Self { + montgomery_form: div_by_2(&self.montgomery_form, &self.residue_params.modulus), + residue_params: self.residue_params.clone(), + } + } + /// Instantiates a new [`BoxedResidue`] that represents an integer modulo the provided params. #[cfg(feature = "std")] pub fn new_with_arc(mut integer: BoxedUint, residue_params: Arc) -> Self {