Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Int - vartime division operations #735

Merged
merged 14 commits into from
Jan 20, 2025
119 changes: 119 additions & 0 deletions src/int/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,125 @@ impl<const LIMBS: usize> Int<LIMBS> {
}
}

/// Vartime checked division operations.
impl<const LIMBS: usize> Int<LIMBS> {
#[inline]
/// Variable time equivalent of [Self::div_rem_base]
///
/// This is variable only with respect to `rhs`.
///
/// When used with a fixed `rhs`, this function is constant-time with respect
/// to `self`.
const fn div_rem_base_vartime<const RHS_LIMBS: usize>(
&self,
rhs: &NonZero<Int<RHS_LIMBS>>,
) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, ConstChoice, ConstChoice) {
// Step 1: split operands into signs and magnitudes.
let (lhs_mag, lhs_sgn) = self.abs_sign();
let (rhs_mag, rhs_sgn) = rhs.abs_sign();

// Step 2. Divide magnitudes
// safe to unwrap since rhs is NonZero.
let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);

(quotient, remainder, lhs_sgn, rhs_sgn)
}

/// Variable time equivalent of [Self::checked_div_rem]
///
/// This is variable only with respect to `rhs`.
///
/// When used with a fixed `rhs`, this function is constant-time with respect
/// to `self`.
pub const fn checked_div_rem_vartime<const RHS_LIMBS: usize>(
&self,
rhs: &NonZero<Int<RHS_LIMBS>>,
) -> (ConstCtOption<Self>, Int<RHS_LIMBS>) {
let (quotient, remainder, lhs_sgn, rhs_sgn) = self.div_rem_base_vartime(rhs);
let opposing_signs = lhs_sgn.ne(rhs_sgn);
(
Self::new_from_abs_sign(quotient, opposing_signs),
remainder.as_int().wrapping_neg_if(lhs_sgn), // as_int mapping is safe; remainder < 2^{k-1} by construction.
)
}

/// Variable time equivalent of [Self::checked_div]
///
/// This is variable only with respect to `rhs`.
///
/// When used with a fixed `rhs`, this function is constant-time with respect
/// to `self`.
pub fn checked_div_vartime<const RHS_LIMBS: usize>(
&self,
rhs: &Int<RHS_LIMBS>,
) -> CtOption<Self> {
NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_vartime(&rhs).0.into())
}

/// Variable time equivalent of [Self::rem]
///
/// This is variable only with respect to `rhs`.
///
/// When used with a fixed `rhs`, this function is constant-time with respect
/// to `self`.
pub const fn rem_vartime<const RHS_LIMBS: usize>(
&self,
rhs: &NonZero<Int<RHS_LIMBS>>,
) -> Int<RHS_LIMBS> {
self.checked_div_rem_vartime(rhs).1
}
}

/// Vartime checked div-floor operations.
impl<const LIMBS: usize> Int<LIMBS> {
/// Variable time equivalent of [Self::checked_div_rem_floor]
///
/// This is variable only with respect to `rhs`.
///
/// When used with a fixed `rhs`, this function is constant-time with respect
/// to `self`.
pub const fn checked_div_rem_floor_vartime<const RHS_LIMBS: usize>(
&self,
rhs: &NonZero<Int<RHS_LIMBS>>,
) -> (ConstCtOption<Self>, Int<RHS_LIMBS>) {
let (lhs_mag, lhs_sgn) = self.abs_sign();
let (rhs_mag, rhs_sgn) = rhs.abs_sign();
let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);

// Modify quotient and remainder when lhs and rhs have opposing signs and the remainder is
// non-zero.
let opposing_signs = lhs_sgn.xor(rhs_sgn);
let modify = remainder.is_nonzero().and(opposing_signs);

// Increase the quotient by one.
let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); // cannot wrap.
let quotient = Uint::select(&quotient, &quotient_plus_one, modify);

// Invert the remainder.
let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
let remainder = Uint::select(&remainder, &inv_remainder, modify);

// Negate output when lhs and rhs have opposing signs.
let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); // rem always small enough for safe as_int conversion

(quotient, remainder)
}

/// Variable time equivalent of [Self::checked_div_floor]
///
/// This is variable only with respect to `rhs`.
///
/// When used with a fixed `rhs`, this function is constant-time with respect
/// to `self`.
pub fn checked_div_floor_vartime<const RHS_LIMBS: usize>(
&self,
rhs: &Int<RHS_LIMBS>,
) -> CtOption<Self> {
NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_floor_vartime(&rhs).0.into())
}
}

/// Checked div-floor operations.
impl<const LIMBS: usize> Int<LIMBS> {
/// Perform checked floored division, returning a [`ConstCtOption`] which `is_some` only if
Expand Down
Loading