Skip to content

Commit

Permalink
Int - vartime division operations (#735)
Browse files Browse the repository at this point in the history
  • Loading branch information
erik-3milabs authored Jan 20, 2025
1 parent 302a165 commit 7dc373d
Showing 1 changed file with 119 additions and 0 deletions.
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

0 comments on commit 7dc373d

Please sign in to comment.