crypto_bigint/uint/boxed/
div.rs1use crate::{
4 uint::{
5 boxed,
6 div_limb::{div2by1, div3by2},
7 },
8 BoxedUint, CheckedDiv, ConstChoice, ConstantTimeSelect, DivRemLimb, Limb, NonZero, Reciprocal,
9 RemLimb, RemMixed, Wrapping,
10};
11use core::ops::{Div, DivAssign, Rem, RemAssign};
12use subtle::CtOption;
13
14impl BoxedUint {
15 pub fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
18 boxed::div_limb::div_rem_limb_with_reciprocal(self, reciprocal)
19 }
20
21 pub fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
23 boxed::div_limb::div_rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
24 }
25
26 #[inline(always)]
28 pub fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
29 boxed::div_limb::rem_limb_with_reciprocal(self, reciprocal)
30 }
31
32 #[inline(always)]
34 pub fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
35 boxed::div_limb::rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
36 }
37
38 pub fn div_rem(&self, rhs: &NonZero<Self>) -> (Self, Self) {
40 self.div_rem_unchecked(rhs.as_ref())
42 }
43
44 pub fn rem(&self, rhs: &NonZero<Self>) -> Self {
46 self.div_rem(rhs).1
47 }
48
49 pub fn div_rem_vartime(&self, rhs: &NonZero<Self>) -> (Self, Self) {
53 let yc = rhs.0.bits_vartime().div_ceil(Limb::BITS) as usize;
54
55 match yc {
56 0 => panic!("zero divisor"),
57 1 => {
58 let (quo, rem_limb) =
60 self.div_rem_limb(rhs.0.limbs[0].to_nz().expect("zero divisor"));
61 let mut rem = Self::zero_with_precision(rhs.bits_precision());
62 rem.limbs[0] = rem_limb;
63 (quo, rem)
64 }
65 _ => {
66 let mut quo = self.clone();
67 let mut rem = rhs.0.clone();
68 div_rem_vartime_in_place(&mut quo.limbs, &mut rem.limbs[..yc]);
69 (quo, rem)
70 }
71 }
72 }
73
74 pub fn rem_vartime(&self, rhs: &NonZero<Self>) -> Self {
78 let yc = rhs.0.bits_vartime().div_ceil(Limb::BITS) as usize;
79
80 match yc {
81 0 => panic!("zero divisor"),
82 1 => {
83 let rem_limb = self.rem_limb(rhs.0.limbs[0].to_nz().expect("zero divisor"));
85 let mut rem = Self::zero_with_precision(rhs.bits_precision());
86 rem.limbs[0] = rem_limb;
87 rem
88 }
89 _ if yc > self.limbs.len() => {
90 let mut rem = Self::zero_with_precision(rhs.bits_precision());
91 rem.limbs[..self.limbs.len()].copy_from_slice(&self.limbs);
92 rem
93 }
94 _ => {
95 let mut quo = self.clone();
96 let mut rem = rhs.0.clone();
97 div_rem_vartime_in_place(&mut quo.limbs, &mut rem.limbs[..yc]);
98 rem
99 }
100 }
101 }
102
103 pub fn wrapping_div(&self, rhs: &NonZero<Self>) -> Self {
110 self.div_rem(rhs).0
111 }
112
113 pub fn wrapping_div_vartime(&self, rhs: &NonZero<Self>) -> Self {
118 self.div_rem_vartime(rhs).0
119 }
120
121 pub fn checked_div(&self, rhs: &Self) -> CtOption<Self> {
124 let is_nz = rhs.is_nonzero();
125 let nz = NonZero(Self::ct_select(
126 &Self::one_with_precision(self.bits_precision()),
127 rhs,
128 is_nz,
129 ));
130 let q = self.div_rem_unchecked(&nz).0;
131 CtOption::new(q, is_nz)
132 }
133
134 fn div_rem_unchecked(&self, rhs: &Self) -> (Self, Self) {
135 let size = self.limbs.len();
139 assert_eq!(
140 size,
141 rhs.limbs.len(),
142 "the precision of the divisor must match the dividend"
143 );
144
145 if size == 1 {
147 let (quo, rem_limb) = self.div_rem_limb(rhs.limbs[0].to_nz().expect("zero divisor"));
148 let mut rem = Self::zero_with_precision(self.bits_precision());
149 rem.limbs[0] = rem_limb;
150 return (quo, rem);
151 }
152
153 let dbits = rhs.bits();
154 assert!(dbits > 0, "zero divisor");
155 let dwords = dbits.div_ceil(Limb::BITS);
156 let lshift = (Limb::BITS - (dbits % Limb::BITS)) % Limb::BITS;
157
158 let mut y = rhs.shl((size as u32) * Limb::BITS - dbits).to_limbs();
160 let (x, mut x_hi) = self.shl_limb(lshift);
162 let mut x = x.to_limbs();
163 let mut xi = size - 1;
164 let mut x_lo = x[size - 1];
165 let mut i;
166 let mut carry;
167
168 let reciprocal = Reciprocal::new(y[size - 1].to_nz().expect("zero divisor"));
169
170 while xi > 0 {
171 let mut quo = div3by2(x_hi.0, x_lo.0, x[xi - 1].0, &reciprocal, y[size - 2].0);
173
174 let done = ConstChoice::from_u32_lt(xi as u32, dwords - 1);
176 quo = done.select_word(quo, 0);
177
178 carry = Limb::ZERO;
180 let mut borrow = Limb::ZERO;
181 let mut tmp;
182 i = 0;
183 while i <= xi {
184 (tmp, carry) = Limb::ZERO.mac(y[size - xi + i - 1], Limb(quo), carry);
185 (x[i], borrow) = x[i].sbb(tmp, borrow);
186 i += 1;
187 }
188 (_, borrow) = x_hi.sbb(carry, borrow);
189
190 let ct_borrow = ConstChoice::from_word_mask(borrow.0);
193 carry = Limb::ZERO;
194 i = 0;
195 while i <= xi {
196 (x[i], carry) = x[i].adc(
197 Limb::select(Limb::ZERO, y[size - xi + i - 1], ct_borrow),
198 carry,
199 );
200 i += 1;
201 }
202 quo = ct_borrow.select_word(quo, quo.saturating_sub(1));
203
204 x_hi = Limb::select(x[xi], x_hi, done);
206 x[xi] = Limb::select(Limb(quo), x[xi], done);
207 x_lo = Limb::select(x[xi - 1], x_lo, done);
208 xi -= 1;
209 }
210
211 let limb_div = ConstChoice::from_u32_eq(1, dwords);
212
213 let x_hi_adjusted = Limb::select(Limb::ZERO, x_hi, limb_div);
219 let (quo2, rem2) = div2by1(x_hi_adjusted.0, x_lo.0, &reciprocal);
220
221 x[0] = Limb::select(x[0], Limb(quo2), limb_div);
223
224 y[0] = Limb::select(x[0], Limb(rem2), limb_div);
226 i = 1;
227 while i < size {
228 y[i] = Limb::select(Limb::ZERO, x[i], ConstChoice::from_u32_lt(i as u32, dwords));
229 y[i] = Limb::select(y[i], x_hi, ConstChoice::from_u32_eq(i as u32, dwords - 1));
230 i += 1;
231 }
232
233 (
234 Self { limbs: x }.shr((dwords - 1) * Limb::BITS),
235 Self { limbs: y }.shr(lshift),
236 )
237 }
238}
239
240impl CheckedDiv for BoxedUint {
241 fn checked_div(&self, rhs: &BoxedUint) -> CtOption<Self> {
242 self.checked_div(rhs)
243 }
244}
245
246impl Div<&NonZero<BoxedUint>> for &BoxedUint {
247 type Output = BoxedUint;
248
249 fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
250 self.wrapping_div(rhs)
251 }
252}
253
254impl Div<&NonZero<BoxedUint>> for BoxedUint {
255 type Output = BoxedUint;
256
257 fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
258 self.wrapping_div(rhs)
259 }
260}
261
262impl Div<NonZero<BoxedUint>> for &BoxedUint {
263 type Output = BoxedUint;
264
265 fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
266 self.wrapping_div(&rhs)
267 }
268}
269
270impl Div<NonZero<BoxedUint>> for BoxedUint {
271 type Output = BoxedUint;
272
273 fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
274 self.div_rem(&rhs).0
275 }
276}
277
278impl DivAssign<&NonZero<BoxedUint>> for BoxedUint {
279 fn div_assign(&mut self, rhs: &NonZero<BoxedUint>) {
280 *self = self.wrapping_div(rhs);
281 }
282}
283
284impl DivAssign<NonZero<BoxedUint>> for BoxedUint {
285 fn div_assign(&mut self, rhs: NonZero<BoxedUint>) {
286 *self = self.wrapping_div(&rhs);
287 }
288}
289
290impl Div<NonZero<BoxedUint>> for Wrapping<BoxedUint> {
291 type Output = Wrapping<BoxedUint>;
292
293 fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
294 Wrapping(self.0 / rhs)
295 }
296}
297
298impl Div<NonZero<BoxedUint>> for &Wrapping<BoxedUint> {
299 type Output = Wrapping<BoxedUint>;
300
301 fn div(self, rhs: NonZero<BoxedUint>) -> Self::Output {
302 Wrapping(self.0.wrapping_div(&rhs))
303 }
304}
305
306impl Div<&NonZero<BoxedUint>> for &Wrapping<BoxedUint> {
307 type Output = Wrapping<BoxedUint>;
308
309 fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
310 Wrapping(self.0.wrapping_div(rhs))
311 }
312}
313
314impl Div<&NonZero<BoxedUint>> for Wrapping<BoxedUint> {
315 type Output = Wrapping<BoxedUint>;
316
317 fn div(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
318 Wrapping(self.0.wrapping_div(rhs))
319 }
320}
321
322impl DivAssign<&NonZero<BoxedUint>> for Wrapping<BoxedUint> {
323 fn div_assign(&mut self, rhs: &NonZero<BoxedUint>) {
324 *self = Wrapping(&self.0 / rhs);
325 }
326}
327
328impl DivAssign<NonZero<BoxedUint>> for Wrapping<BoxedUint> {
329 fn div_assign(&mut self, rhs: NonZero<BoxedUint>) {
330 *self /= &rhs;
331 }
332}
333
334impl Rem<&NonZero<BoxedUint>> for &BoxedUint {
335 type Output = BoxedUint;
336
337 #[inline]
338 fn rem(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
339 self.rem(rhs)
340 }
341}
342
343impl Rem<&NonZero<BoxedUint>> for BoxedUint {
344 type Output = BoxedUint;
345
346 #[inline]
347 fn rem(self, rhs: &NonZero<BoxedUint>) -> Self::Output {
348 Self::rem(&self, rhs)
349 }
350}
351
352impl Rem<NonZero<BoxedUint>> for &BoxedUint {
353 type Output = BoxedUint;
354
355 #[inline]
356 fn rem(self, rhs: NonZero<BoxedUint>) -> Self::Output {
357 self.rem(&rhs)
358 }
359}
360
361impl Rem<NonZero<BoxedUint>> for BoxedUint {
362 type Output = BoxedUint;
363
364 #[inline]
365 fn rem(self, rhs: NonZero<BoxedUint>) -> Self::Output {
366 self.rem(&rhs)
367 }
368}
369
370impl RemAssign<&NonZero<BoxedUint>> for BoxedUint {
371 fn rem_assign(&mut self, rhs: &NonZero<BoxedUint>) {
372 *self = Self::rem(self, rhs)
373 }
374}
375
376impl RemAssign<NonZero<BoxedUint>> for BoxedUint {
377 fn rem_assign(&mut self, rhs: NonZero<BoxedUint>) {
378 *self = Self::rem(self, &rhs)
379 }
380}
381
382impl DivRemLimb for BoxedUint {
383 fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
384 Self::div_rem_limb_with_reciprocal(self, reciprocal)
385 }
386}
387
388impl RemLimb for BoxedUint {
389 fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
390 Self::rem_limb_with_reciprocal(self, reciprocal)
391 }
392}
393
394impl RemMixed<BoxedUint> for BoxedUint {
395 fn rem_mixed(&self, reductor: &NonZero<BoxedUint>) -> BoxedUint {
396 Self::div_rem_vartime(self, reductor).1
397 }
398}
399
400fn shl_limb_vartime(limbs: &mut [Limb], shift: u32) -> Limb {
402 if shift == 0 {
403 return Limb::ZERO;
404 }
405
406 let lshift = shift;
407 let rshift = Limb::BITS - shift;
408 let limbs_num = limbs.len();
409
410 let carry = limbs[limbs_num - 1] >> rshift;
411 for i in (1..limbs_num).rev() {
412 limbs[i] = (limbs[i] << lshift) | (limbs[i - 1] >> rshift);
413 }
414 limbs[0] <<= lshift;
415
416 carry
417}
418
419fn shr_limb_vartime(limbs: &mut [Limb], shift: u32) {
421 if shift == 0 {
422 return;
423 }
424
425 let lshift = Limb::BITS - shift;
426 let rshift = shift;
427
428 let limbs_num = limbs.len();
429
430 for i in 0..limbs_num - 1 {
431 limbs[i] = (limbs[i] >> rshift) | (limbs[i + 1] << lshift);
432 }
433 limbs[limbs_num - 1] >>= rshift;
434}
435
436pub(crate) fn div_rem_vartime_in_place(x: &mut [Limb], y: &mut [Limb]) {
441 let xc = x.len();
442 let yc = y.len();
443 assert!(
444 yc > 0 && y[yc - 1].0 != 0,
445 "divisor must have a non-zero leading word"
446 );
447
448 if xc == 0 {
449 y.fill(Limb::ZERO);
451 return;
452 } else if yc > xc {
453 y[..xc].copy_from_slice(&x[..xc]);
456 y[xc..].fill(Limb::ZERO);
457 x.fill(Limb::ZERO);
458 return;
459 }
460
461 let lshift = y[yc - 1].leading_zeros();
462
463 shl_limb_vartime(y, lshift);
466
467 let mut x_hi = shl_limb_vartime(x, lshift);
469
470 let reciprocal = Reciprocal::new(y[yc - 1].to_nz().expect("zero divisor"));
471
472 for xi in (yc - 1..xc).rev() {
473 let mut quo = div3by2(x_hi.0, x[xi].0, x[xi - 1].0, &reciprocal, y[yc - 2].0);
475
476 let borrow = {
478 let mut carry = Limb::ZERO;
479 let mut borrow = Limb::ZERO;
480 let mut tmp;
481 for i in 0..yc {
482 (tmp, carry) = Limb::ZERO.mac(y[i], Limb(quo), carry);
483 (x[xi + i + 1 - yc], borrow) = x[xi + i + 1 - yc].sbb(tmp, borrow);
484 }
485 (_, borrow) = x_hi.sbb(carry, borrow);
486 borrow
487 };
488
489 quo = {
492 let ct_borrow = ConstChoice::from_word_mask(borrow.0);
493 let mut carry = Limb::ZERO;
494 for i in 0..yc {
495 (x[xi + i + 1 - yc], carry) =
496 x[xi + i + 1 - yc].adc(Limb::select(Limb::ZERO, y[i], ct_borrow), carry);
497 }
498 ct_borrow.select_word(quo, quo.wrapping_sub(1))
499 };
500
501 x_hi = x[xi];
503 x[xi] = Limb(quo);
504 }
505
506 y[..yc - 1].copy_from_slice(&x[..yc - 1]);
508 y[yc - 1] = x_hi;
509
510 shr_limb_vartime(y, lshift);
512
513 x.copy_within(yc - 1..xc, 0);
516 x[xc - yc + 1..].fill(Limb::ZERO);
517}
518
519#[cfg(test)]
520mod tests {
521 use super::{BoxedUint, Limb, NonZero};
522
523 #[test]
524 fn rem() {
525 let n = BoxedUint::from(0xFFEECCBBAA99887766u128);
526 let p = NonZero::new(BoxedUint::from(997u128)).unwrap();
527 assert_eq!(BoxedUint::from(648u128), n.rem(&p));
528 }
529
530 #[test]
531 fn rem_vartime() {
532 let n = BoxedUint::from(0xFFEECCBBAA99887766u128);
533 let p = NonZero::new(BoxedUint::from(997u128)).unwrap();
534 assert_eq!(BoxedUint::from(648u128), n.rem_vartime(&p));
535 }
536
537 #[test]
538 fn rem_limb() {
539 let n = BoxedUint::from(0xFFEECCBBAA99887766u128);
540 let pl = NonZero::new(Limb(997)).unwrap();
541 let p = NonZero::new(BoxedUint::from(997u128)).unwrap();
542 assert_eq!(n.rem(&p).limbs[0], n.rem_limb(pl));
543 }
544}