@@ -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.
80199impl < const LIMBS : usize > Int < LIMBS > {
81200 /// Perform checked floored division, returning a [`ConstCtOption`] which `is_some` only if
0 commit comments