1
1
//! [`BoxedUint`] division operations.
2
2
3
3
use crate :: {
4
- uint:: { boxed, div_limb:: div3by2} ,
4
+ uint:: {
5
+ boxed,
6
+ div_limb:: { div2by1, div3by2} ,
7
+ } ,
5
8
BoxedUint , CheckedDiv , ConstChoice , ConstantTimeSelect , DivRemLimb , Limb , NonZero , Reciprocal ,
6
- RemLimb , Word , Wrapping ,
9
+ RemLimb , Wrapping ,
7
10
} ;
8
11
use core:: ops:: { Div , DivAssign , Rem , RemAssign } ;
9
12
use subtle:: CtOption ;
@@ -166,7 +169,7 @@ impl BoxedUint {
166
169
167
170
while xi > 0 {
168
171
// Divide high dividend words by the high divisor word to estimate the quotient word
169
- let ( mut quo, _ ) = div3by2 ( x_hi. 0 , x_lo. 0 , x[ xi - 1 ] . 0 , & reciprocal, y[ size - 2 ] . 0 ) ;
172
+ let mut quo = div3by2 ( x_hi. 0 , x_lo. 0 , x[ xi - 1 ] . 0 , & reciprocal, y[ size - 2 ] . 0 ) ;
170
173
171
174
// This loop is a no-op once xi is smaller than the number of words in the divisor
172
175
let done = ConstChoice :: from_u32_lt ( xi as u32 , dwords - 1 ) ;
@@ -206,14 +209,20 @@ impl BoxedUint {
206
209
}
207
210
208
211
let limb_div = ConstChoice :: from_u32_eq ( 1 , dwords) ;
212
+
209
213
// Calculate quotient and remainder for the case where the divisor is a single word
210
- let ( quo2, rem2) = div3by2 ( x_hi. 0 , x_lo. 0 , 0 , & reciprocal, 0 ) ;
214
+ // Note that `div2by1()` will panic if `x_hi >= reciprocal.divisor_normalized`,
215
+ // but this can only be the case if `limb_div` is falsy,
216
+ // in which case we discard the result anyway,
217
+ // so we conditionally set `x_hi` to zero for this branch.
218
+ 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) ;
211
220
212
221
// Adjust the quotient for single limb division
213
222
x[ 0 ] = Limb :: select ( x[ 0 ] , Limb ( quo2) , limb_div) ;
214
223
215
224
// Copy out the remainder
216
- y[ 0 ] = Limb :: select ( x[ 0 ] , Limb ( rem2 as Word ) , limb_div) ;
225
+ y[ 0 ] = Limb :: select ( x[ 0 ] , Limb ( rem2) , limb_div) ;
217
226
i = 1 ;
218
227
while i < size {
219
228
y[ i] = Limb :: select ( Limb :: ZERO , x[ i] , ConstChoice :: from_u32_lt ( i as u32 , dwords) ) ;
@@ -382,6 +391,42 @@ impl RemLimb for BoxedUint {
382
391
}
383
392
}
384
393
394
+ /// Computes `limbs << shift` inplace, where `0 <= shift < Limb::BITS`, returning the carry.
395
+ fn shl_limb_vartime ( limbs : & mut [ Limb ] , shift : u32 ) -> Limb {
396
+ if shift == 0 {
397
+ return Limb :: ZERO ;
398
+ }
399
+
400
+ let lshift = shift;
401
+ let rshift = Limb :: BITS - shift;
402
+ let limbs_num = limbs. len ( ) ;
403
+
404
+ let carry = limbs[ limbs_num - 1 ] >> rshift;
405
+ for i in ( 1 ..limbs_num) . rev ( ) {
406
+ limbs[ i] = ( limbs[ i] << lshift) | ( limbs[ i - 1 ] >> rshift) ;
407
+ }
408
+ limbs[ 0 ] <<= lshift;
409
+
410
+ carry
411
+ }
412
+
413
+ /// Computes `limbs >> shift` inplace, where `0 <= shift < Limb::BITS`.
414
+ fn shr_limb_vartime ( limbs : & mut [ Limb ] , shift : u32 ) {
415
+ if shift == 0 {
416
+ return ;
417
+ }
418
+
419
+ let lshift = Limb :: BITS - shift;
420
+ let rshift = shift;
421
+
422
+ let limbs_num = limbs. len ( ) ;
423
+
424
+ for i in 0 ..limbs_num - 1 {
425
+ limbs[ i] = ( limbs[ i] >> rshift) | ( limbs[ i + 1 ] << lshift) ;
426
+ }
427
+ limbs[ limbs_num - 1 ] >>= rshift;
428
+ }
429
+
385
430
/// Computes `x` / `y`, returning the quotient in `x` and the remainder in `y`.
386
431
///
387
432
/// This function operates in variable-time. It will panic if the divisor is zero
@@ -408,51 +453,44 @@ pub(crate) fn div_rem_vartime_in_place(x: &mut [Limb], y: &mut [Limb]) {
408
453
}
409
454
410
455
let lshift = y[ yc - 1 ] . leading_zeros ( ) ;
411
- let rshift = if lshift == 0 { 0 } else { Limb :: BITS - lshift } ;
412
- let mut x_hi = Limb :: ZERO ;
413
- let mut carry;
414
-
415
- if lshift != 0 {
416
- // Shift divisor such that it has no leading zeros
417
- // This means that div2by1 requires no extra shifts, and ensures that the high word >= b/2
418
- carry = Limb :: ZERO ;
419
- for i in 0 ..yc {
420
- ( y[ i] , carry) = ( Limb ( ( y[ i] . 0 << lshift) | carry. 0 ) , Limb ( y[ i] . 0 >> rshift) ) ;
421
- }
422
456
423
- // Shift the dividend to match
424
- carry = Limb :: ZERO ;
425
- for i in 0 ..xc {
426
- ( x[ i] , carry) = ( Limb ( ( x[ i] . 0 << lshift) | carry. 0 ) , Limb ( x[ i] . 0 >> rshift) ) ;
427
- }
428
- x_hi = carry;
429
- }
457
+ // Shift divisor such that it has no leading zeros
458
+ // This means that div2by1 requires no extra shifts, and ensures that the high word >= b/2
459
+ shl_limb_vartime ( y, lshift) ;
460
+
461
+ // Shift the dividend to match
462
+ let mut x_hi = shl_limb_vartime ( x, lshift) ;
430
463
431
464
let reciprocal = Reciprocal :: new ( y[ yc - 1 ] . to_nz ( ) . expect ( "zero divisor" ) ) ;
432
465
433
466
for xi in ( yc - 1 ..xc) . rev ( ) {
434
467
// Divide high dividend words by the high divisor word to estimate the quotient word
435
- let ( mut quo, _ ) = div3by2 ( x_hi. 0 , x[ xi] . 0 , x[ xi - 1 ] . 0 , & reciprocal, y[ yc - 2 ] . 0 ) ;
468
+ let mut quo = div3by2 ( x_hi. 0 , x[ xi] . 0 , x[ xi - 1 ] . 0 , & reciprocal, y[ yc - 2 ] . 0 ) ;
436
469
437
470
// Subtract q*divisor from the dividend
438
- carry = Limb :: ZERO ;
439
- let mut borrow = Limb :: ZERO ;
440
- let mut tmp;
441
- for i in 0 ..yc {
442
- ( tmp, carry) = Limb :: ZERO . mac ( y[ i] , Limb ( quo) , carry) ;
443
- ( x[ xi + i + 1 - yc] , borrow) = x[ xi + i + 1 - yc] . sbb ( tmp, borrow) ;
444
- }
445
- ( _, borrow) = x_hi. sbb ( carry, borrow) ;
471
+ let borrow = {
472
+ let mut carry = Limb :: ZERO ;
473
+ let mut borrow = Limb :: ZERO ;
474
+ let mut tmp;
475
+ for i in 0 ..yc {
476
+ ( tmp, carry) = Limb :: ZERO . mac ( y[ i] , Limb ( quo) , carry) ;
477
+ ( x[ xi + i + 1 - yc] , borrow) = x[ xi + i + 1 - yc] . sbb ( tmp, borrow) ;
478
+ }
479
+ ( _, borrow) = x_hi. sbb ( carry, borrow) ;
480
+ borrow
481
+ } ;
446
482
447
483
// If the subtraction borrowed, then decrement q and add back the divisor
448
484
// The probability of this being needed is very low, about 2/(Limb::MAX+1)
449
- let ct_borrow = ConstChoice :: from_word_mask ( borrow. 0 ) ;
450
- carry = Limb :: ZERO ;
451
- for i in 0 ..yc {
452
- ( x[ xi + i + 1 - yc] , carry) =
453
- x[ xi + i + 1 - yc] . adc ( Limb :: select ( Limb :: ZERO , y[ i] , ct_borrow) , carry) ;
454
- }
455
- quo = ct_borrow. select_word ( quo, quo. saturating_sub ( 1 ) ) ;
485
+ quo = {
486
+ let ct_borrow = ConstChoice :: from_word_mask ( borrow. 0 ) ;
487
+ let mut carry = Limb :: ZERO ;
488
+ for i in 0 ..yc {
489
+ ( x[ xi + i + 1 - yc] , carry) =
490
+ x[ xi + i + 1 - yc] . adc ( Limb :: select ( Limb :: ZERO , y[ i] , ct_borrow) , carry) ;
491
+ }
492
+ ct_borrow. select_word ( quo, quo. wrapping_sub ( 1 ) )
493
+ } ;
456
494
457
495
// Store the quotient within dividend and set x_hi to the current highest word
458
496
x_hi = x[ xi] ;
@@ -464,12 +502,7 @@ pub(crate) fn div_rem_vartime_in_place(x: &mut [Limb], y: &mut [Limb]) {
464
502
y[ yc - 1 ] = x_hi;
465
503
466
504
// Unshift the remainder from the earlier adjustment
467
- if lshift != 0 {
468
- carry = Limb :: ZERO ;
469
- for i in ( 0 ..yc) . rev ( ) {
470
- ( y[ i] , carry) = ( Limb ( ( y[ i] . 0 >> lshift) | carry. 0 ) , Limb ( y[ i] . 0 << rshift) ) ;
471
- }
472
- }
505
+ shr_limb_vartime ( y, lshift) ;
473
506
474
507
// Shift the quotient to the low limbs within dividend
475
508
// let x_size = xc - yc + 1;
0 commit comments