2
2
3
3
use crate :: { BoxedUint , CheckedDiv , Limb , NonZero , Wrapping } ;
4
4
use core:: ops:: { Div , DivAssign , Rem , RemAssign } ;
5
- use subtle:: { Choice , ConstantTimeEq , CtOption } ;
5
+ use subtle:: { Choice , ConstantTimeEq , ConstantTimeLess , CtOption } ;
6
6
7
7
impl BoxedUint {
8
+ /// Computes self / rhs, returns the quotient, remainder.
9
+ pub fn div_rem ( & self , rhs : & NonZero < Self > ) -> ( Self , Self ) {
10
+ // Since `rhs` is nonzero, this should always hold.
11
+ self . div_rem_unchecked ( rhs. as_ref ( ) )
12
+ }
13
+
14
+ /// Computes self % rhs, returns the remainder.
15
+ pub fn rem ( & self , rhs : & NonZero < Self > ) -> Self {
16
+ self . div_rem ( rhs) . 1
17
+ }
18
+
8
19
/// Computes self / rhs, returns the quotient, remainder.
9
20
///
10
21
/// Variable-time with respect to `rhs`
11
22
pub fn div_rem_vartime ( & self , rhs : & NonZero < Self > ) -> ( Self , Self ) {
23
+ // Since `rhs` is nonzero, this should always hold.
12
24
self . div_rem_vartime_unchecked ( rhs. as_ref ( ) )
13
25
}
14
26
@@ -45,23 +57,60 @@ impl BoxedUint {
45
57
///
46
58
/// Panics if `rhs == 0`.
47
59
pub fn wrapping_div ( & self , rhs : & NonZero < Self > ) -> Self {
48
- self . div_rem_vartime ( rhs) . 0
60
+ self . div_rem ( rhs) . 0
49
61
}
50
62
51
63
/// Perform checked division, returning a [`CtOption`] which `is_some`
52
64
/// only if the rhs != 0
53
65
pub fn checked_div ( & self , rhs : & Self ) -> CtOption < Self > {
54
- CtOption :: new ( self . div_rem_vartime_unchecked ( rhs) . 0 , rhs. is_zero ( ) )
66
+ let q = self . div_rem_unchecked ( rhs) . 0 ;
67
+ CtOption :: new ( q, !rhs. is_zero ( ) )
55
68
}
56
69
57
- /// Compute divison and remainder without checking `rhs` is zero.
58
- fn div_rem_vartime_unchecked ( & self , rhs : & Self ) -> ( Self , Self ) {
70
+ /// Computes `self` / `rhs`, returns the quotient (q), remainder (r) without checking if `rhs`
71
+ /// is zero.
72
+ ///
73
+ /// This function is constant-time with respect to both `self` and `rhs`.
74
+ fn div_rem_unchecked ( & self , rhs : & Self ) -> ( Self , Self ) {
59
75
debug_assert_eq ! ( self . bits_precision( ) , rhs. bits_precision( ) ) ;
60
76
let mb = rhs. bits ( ) ;
77
+ let bits_precision = self . bits_precision ( ) ;
78
+ let mut rem = self . clone ( ) ;
79
+ let mut quo = Self :: zero_with_precision ( bits_precision) ;
80
+ let mut c = rhs. shl ( bits_precision - mb) ;
81
+ let mut i = bits_precision;
82
+ let mut done = Choice :: from ( 0u8 ) ;
83
+
84
+ loop {
85
+ let ( mut r, borrow) = rem. sbb ( & c, Limb :: ZERO ) ;
86
+ rem = Self :: conditional_select ( & r, & rem, Choice :: from ( ( borrow. 0 & 1 ) as u8 ) | done) ;
87
+ r = quo. bitor ( & Self :: one ( ) ) ;
88
+ quo = Self :: conditional_select ( & r, & quo, Choice :: from ( ( borrow. 0 & 1 ) as u8 ) | done) ;
89
+ if i == 0 {
90
+ break ;
91
+ }
92
+ i -= 1 ;
93
+ // when `i < mb`, the computation is actually done, so we ensure `quo` and `rem`
94
+ // aren't modified further (but do the remaining iterations anyway to be constant-time)
95
+ done = i. ct_lt ( & mb) ;
96
+ c. shr1_assign ( ) ;
97
+ quo = Self :: conditional_select ( & quo. shl1 ( ) , & quo, done) ;
98
+ }
99
+
100
+ ( quo, rem)
101
+ }
102
+
103
+ /// Computes `self` / `rhs`, returns the quotient (q), remainder (r) without checking if `rhs`
104
+ /// is zero.
105
+ ///
106
+ /// This function operates in variable-time.
107
+ fn div_rem_vartime_unchecked ( & self , rhs : & Self ) -> ( Self , Self ) {
108
+ debug_assert_eq ! ( self . bits_precision( ) , rhs. bits_precision( ) ) ;
109
+ let mb = rhs. bits_vartime ( ) ;
61
110
let mut bd = self . bits_precision ( ) - mb;
62
111
let mut remainder = self . clone ( ) ;
63
112
let mut quotient = Self :: zero_with_precision ( self . bits_precision ( ) ) ;
64
- let mut c = rhs. shl ( bd) ;
113
+ let mut c = rhs. shl_vartime ( bd) ;
65
114
66
115
loop {
67
116
let ( mut r, borrow) = remainder. sbb ( & c, Limb :: ZERO ) ;
@@ -74,7 +123,7 @@ impl BoxedUint {
74
123
}
75
124
bd -= 1 ;
76
125
c. shr1_assign ( ) ;
77
- quotient = quotient . shl ( 1 ) ;
126
+ quotient. shl1_assign ( ) ;
78
127
}
79
128
80
129
( quotient, remainder)
@@ -125,7 +174,7 @@ impl Div<NonZero<BoxedUint>> for BoxedUint {
125
174
type Output = BoxedUint ;
126
175
127
176
fn div ( self , rhs : NonZero < BoxedUint > ) -> Self :: Output {
128
- self . div_rem_vartime ( & rhs) . 0
177
+ self . div_rem ( & rhs) . 0
129
178
}
130
179
}
131
180
@@ -190,7 +239,7 @@ impl Rem<&NonZero<BoxedUint>> for &BoxedUint {
190
239
191
240
#[ inline]
192
241
fn rem ( self , rhs : & NonZero < BoxedUint > ) -> Self :: Output {
193
- self . rem_vartime ( rhs)
242
+ self . rem ( rhs)
194
243
}
195
244
}
196
245
@@ -199,7 +248,7 @@ impl Rem<&NonZero<BoxedUint>> for BoxedUint {
199
248
200
249
#[ inline]
201
250
fn rem ( self , rhs : & NonZero < BoxedUint > ) -> Self :: Output {
202
- self . rem_vartime ( rhs)
251
+ Self :: rem ( & self , rhs)
203
252
}
204
253
}
205
254
@@ -208,7 +257,7 @@ impl Rem<NonZero<BoxedUint>> for &BoxedUint {
208
257
209
258
#[ inline]
210
259
fn rem ( self , rhs : NonZero < BoxedUint > ) -> Self :: Output {
211
- self . rem_vartime ( & rhs)
260
+ self . rem ( & rhs)
212
261
}
213
262
}
214
263
@@ -217,26 +266,33 @@ impl Rem<NonZero<BoxedUint>> for BoxedUint {
217
266
218
267
#[ inline]
219
268
fn rem ( self , rhs : NonZero < BoxedUint > ) -> Self :: Output {
220
- self . rem_vartime ( & rhs)
269
+ self . rem ( & rhs)
221
270
}
222
271
}
223
272
224
273
impl RemAssign < & NonZero < BoxedUint > > for BoxedUint {
225
274
fn rem_assign ( & mut self , rhs : & NonZero < BoxedUint > ) {
226
- * self = self . rem_vartime ( rhs)
275
+ * self = Self :: rem ( self , rhs)
227
276
}
228
277
}
229
278
230
279
impl RemAssign < NonZero < BoxedUint > > for BoxedUint {
231
280
fn rem_assign ( & mut self , rhs : NonZero < BoxedUint > ) {
232
- * self = self . rem_vartime ( & rhs)
281
+ * self = Self :: rem ( self , & rhs)
233
282
}
234
283
}
235
284
236
285
#[ cfg( test) ]
237
286
mod tests {
238
287
use super :: { BoxedUint , NonZero } ;
239
288
289
+ #[ test]
290
+ fn rem ( ) {
291
+ let n = BoxedUint :: from ( 0xFFEECCBBAA99887766u128 ) ;
292
+ let p = NonZero :: new ( BoxedUint :: from ( 997u128 ) ) . unwrap ( ) ;
293
+ assert_eq ! ( BoxedUint :: from( 648u128 ) , n. rem( & p) ) ;
294
+ }
295
+
240
296
#[ test]
241
297
fn rem_vartime ( ) {
242
298
let n = BoxedUint :: from ( 0xFFEECCBBAA99887766u128 ) ;
0 commit comments