Skip to content

Commit 7dc373d

Browse files
authored
Int - vartime division operations (#735)
1 parent 302a165 commit 7dc373d

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

src/int/div.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,125 @@ impl<const LIMBS: usize> Int<LIMBS> {
7676
}
7777
}
7878

79+
/// Vartime checked division operations.
80+
impl<const LIMBS: usize> Int<LIMBS> {
81+
#[inline]
82+
/// Variable time equivalent of [Self::div_rem_base]
83+
///
84+
/// This is variable only with respect to `rhs`.
85+
///
86+
/// When used with a fixed `rhs`, this function is constant-time with respect
87+
/// to `self`.
88+
const fn div_rem_base_vartime<const RHS_LIMBS: usize>(
89+
&self,
90+
rhs: &NonZero<Int<RHS_LIMBS>>,
91+
) -> (Uint<LIMBS>, Uint<RHS_LIMBS>, ConstChoice, ConstChoice) {
92+
// Step 1: split operands into signs and magnitudes.
93+
let (lhs_mag, lhs_sgn) = self.abs_sign();
94+
let (rhs_mag, rhs_sgn) = rhs.abs_sign();
95+
96+
// Step 2. Divide magnitudes
97+
// safe to unwrap since rhs is NonZero.
98+
let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);
99+
100+
(quotient, remainder, lhs_sgn, rhs_sgn)
101+
}
102+
103+
/// Variable time equivalent of [Self::checked_div_rem]
104+
///
105+
/// This is variable only with respect to `rhs`.
106+
///
107+
/// When used with a fixed `rhs`, this function is constant-time with respect
108+
/// to `self`.
109+
pub const fn checked_div_rem_vartime<const RHS_LIMBS: usize>(
110+
&self,
111+
rhs: &NonZero<Int<RHS_LIMBS>>,
112+
) -> (ConstCtOption<Self>, Int<RHS_LIMBS>) {
113+
let (quotient, remainder, lhs_sgn, rhs_sgn) = self.div_rem_base_vartime(rhs);
114+
let opposing_signs = lhs_sgn.ne(rhs_sgn);
115+
(
116+
Self::new_from_abs_sign(quotient, opposing_signs),
117+
remainder.as_int().wrapping_neg_if(lhs_sgn), // as_int mapping is safe; remainder < 2^{k-1} by construction.
118+
)
119+
}
120+
121+
/// Variable time equivalent of [Self::checked_div]
122+
///
123+
/// This is variable only with respect to `rhs`.
124+
///
125+
/// When used with a fixed `rhs`, this function is constant-time with respect
126+
/// to `self`.
127+
pub fn checked_div_vartime<const RHS_LIMBS: usize>(
128+
&self,
129+
rhs: &Int<RHS_LIMBS>,
130+
) -> CtOption<Self> {
131+
NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_vartime(&rhs).0.into())
132+
}
133+
134+
/// Variable time equivalent of [Self::rem]
135+
///
136+
/// This is variable only with respect to `rhs`.
137+
///
138+
/// When used with a fixed `rhs`, this function is constant-time with respect
139+
/// to `self`.
140+
pub const fn rem_vartime<const RHS_LIMBS: usize>(
141+
&self,
142+
rhs: &NonZero<Int<RHS_LIMBS>>,
143+
) -> Int<RHS_LIMBS> {
144+
self.checked_div_rem_vartime(rhs).1
145+
}
146+
}
147+
148+
/// Vartime checked div-floor operations.
149+
impl<const LIMBS: usize> Int<LIMBS> {
150+
/// Variable time equivalent of [Self::checked_div_rem_floor]
151+
///
152+
/// This is variable only with respect to `rhs`.
153+
///
154+
/// When used with a fixed `rhs`, this function is constant-time with respect
155+
/// to `self`.
156+
pub const fn checked_div_rem_floor_vartime<const RHS_LIMBS: usize>(
157+
&self,
158+
rhs: &NonZero<Int<RHS_LIMBS>>,
159+
) -> (ConstCtOption<Self>, Int<RHS_LIMBS>) {
160+
let (lhs_mag, lhs_sgn) = self.abs_sign();
161+
let (rhs_mag, rhs_sgn) = rhs.abs_sign();
162+
let (quotient, remainder) = lhs_mag.div_rem_vartime(&rhs_mag);
163+
164+
// Modify quotient and remainder when lhs and rhs have opposing signs and the remainder is
165+
// non-zero.
166+
let opposing_signs = lhs_sgn.xor(rhs_sgn);
167+
let modify = remainder.is_nonzero().and(opposing_signs);
168+
169+
// Increase the quotient by one.
170+
let quotient_plus_one = quotient.wrapping_add(&Uint::ONE); // cannot wrap.
171+
let quotient = Uint::select(&quotient, &quotient_plus_one, modify);
172+
173+
// Invert the remainder.
174+
let inv_remainder = rhs_mag.0.wrapping_sub(&remainder);
175+
let remainder = Uint::select(&remainder, &inv_remainder, modify);
176+
177+
// Negate output when lhs and rhs have opposing signs.
178+
let quotient = Int::new_from_abs_sign(quotient, opposing_signs);
179+
let remainder = remainder.as_int().wrapping_neg_if(opposing_signs); // rem always small enough for safe as_int conversion
180+
181+
(quotient, remainder)
182+
}
183+
184+
/// Variable time equivalent of [Self::checked_div_floor]
185+
///
186+
/// This is variable only with respect to `rhs`.
187+
///
188+
/// When used with a fixed `rhs`, this function is constant-time with respect
189+
/// to `self`.
190+
pub fn checked_div_floor_vartime<const RHS_LIMBS: usize>(
191+
&self,
192+
rhs: &Int<RHS_LIMBS>,
193+
) -> CtOption<Self> {
194+
NonZero::new(*rhs).and_then(|rhs| self.checked_div_rem_floor_vartime(&rhs).0.into())
195+
}
196+
}
197+
79198
/// Checked div-floor operations.
80199
impl<const LIMBS: usize> Int<LIMBS> {
81200
/// Perform checked floored division, returning a [`ConstCtOption`] which `is_some` only if

0 commit comments

Comments
 (0)