@@ -606,30 +606,28 @@ impl UintRef {
606606 /// If the divisor is zero.
607607 #[ inline( always) ]
608608 pub ( crate ) const fn div_exact ( & mut self , rhs : & mut UintRef ) -> Choice {
609- let x_prec = self . bits_precision ( ) ;
610609 let y_bits = rhs. bits ( ) ;
611610 assert ! ( y_bits > 0 , "zero divisor" ) ;
612611
613- let tz = rhs. trailing_zeros ( ) ;
614- // Track whether there are more zeros in the divisor than bits in the dividend
615- let excess_z = Choice :: from_u32_lt ( x_prec, tz) ;
616- let tz = excess_z. select_u32 ( tz, x_prec) ;
612+ let x_tz = self . trailing_zeros ( ) ;
613+ let x_zero = Choice :: from_u32_eq ( x_tz, self . bits_precision ( ) ) ;
614+ let y_tz = rhs. trailing_zeros ( ) ;
617615
618616 // Shift the divisor such that it is odd
619- rhs. shr_assign ( tz ) ;
617+ rhs. shr_assign ( y_tz ) ;
620618
621- // Check that the dividend evenly divides by 2^tz, and shift it to match the divisor
622- let div2s_exact = self . ensure_trailing_zeros ( tz ) . and ( excess_z . not ( ) ) ;
623- self . unbounded_shr_assign ( tz ) ;
619+ // Check that the dividend evenly divides by 2^y+ tz, and shift it to match the divisor
620+ let div2s_exact = Choice :: from_u32_le ( y_tz , x_tz ) . or ( x_zero ) ;
621+ self . unbounded_shr_assign ( y_tz ) ;
624622
625623 let y = Odd :: new_ref_unchecked ( rhs) ;
626624 let y_inv = y. invert_mod_limb ( ) ;
627- let ywords = bitlen:: to_limbs ( y_bits - tz ) ;
625+ let ywords = bitlen:: to_limbs ( y_bits - y_tz ) ;
628626 let is_exact =
629627 Self :: div_exact_odd_with_inverse :: < false > ( self , y, y_inv, ywords) . and ( div2s_exact) ;
630628
631629 // Restore the divisor
632- rhs. shl_assign ( tz ) ;
630+ rhs. shl_assign ( y_tz ) ;
633631
634632 is_exact
635633 }
@@ -643,32 +641,28 @@ impl UintRef {
643641 /// If the divisor is zero.
644642 #[ inline( always) ]
645643 pub ( crate ) const fn div_exact_vartime ( & mut self , rhs : & mut UintRef ) -> Choice {
646- let x_prec = self . bits_precision ( ) ;
647644 let y_bits = rhs. bits_vartime ( ) ;
648645 assert ! ( y_bits > 0 , "zero divisor" ) ;
649646
650- let tz = rhs. trailing_zeros_vartime ( ) ;
651- if tz > x_prec {
652- // The divisor exceeds the dividend precision. Short circuit based on public
653- // information (the divisor and the input size in limbs)
654- return Choice :: FALSE ;
655- }
656- // Reduce the divisor to its populated limbs and shift it such that it is odd
657- let rhs = rhs. leading_mut ( bitlen:: to_limbs ( y_bits) ) ;
658- rhs. unbounded_shr_assign_vartime ( tz) ;
647+ let x_tz = self . trailing_zeros ( ) ;
648+ let x_zero = Choice :: from_u32_eq ( x_tz, self . bits_precision ( ) ) ;
649+ let y_tz = rhs. trailing_zeros_vartime ( ) ;
650+
651+ // Shift the divisor to be odd
652+ rhs. unbounded_shr_assign_vartime ( y_tz) ;
659653
660- // Check that the dividend evenly divides by 2^tz , and shift it to match the divisor
661- let div2s_exact = self . ensure_trailing_zeros ( tz ) ;
662- self . unbounded_shr_assign_vartime ( tz ) ;
654+ // Check that the dividend evenly divides by 2^y_tz , and shift it to match the divisor
655+ let div2s_exact = Choice :: from_u32_le ( y_tz , x_tz ) . or ( x_zero ) ;
656+ self . unbounded_shr_assign_vartime ( y_tz ) ;
663657
664- let ywords = bitlen:: to_limbs ( y_bits - tz ) ;
665- let y = Odd :: new_ref_unchecked ( rhs. leading ( ywords) ) ;
658+ let ywords = bitlen:: to_limbs ( y_bits - y_tz ) ;
659+ let y = Odd :: new_ref_unchecked ( rhs. leading_mut ( ywords) ) ;
666660 let y_inv = y. invert_mod_limb ( ) ;
667661 let is_exact =
668662 Self :: div_exact_odd_with_inverse :: < true > ( self , y, y_inv, ywords) . and ( div2s_exact) ;
669663
670664 // Restore the divisor
671- rhs. unbounded_shl_assign_vartime ( tz ) ;
665+ rhs. unbounded_shl_assign_vartime ( y_tz ) ;
672666
673667 is_exact
674668 }
@@ -696,22 +690,26 @@ impl UintRef {
696690 let y = y. as_ref ( ) ;
697691 let yc = y. nlimbs ( ) ;
698692 let mut meta_carry = Limb :: ZERO ;
693+ let mut zero_hi = Choice :: TRUE ;
699694 let mut xi = 0 ;
700695
701696 while xi < xc {
702697 let y_remain = if yc < ( xc - xi) { yc } else { xc - xi } ;
703698 // This loop is a no-op once there are fewer words remaining than the size of the divisor
704699 let done = usize_lt ( y_remain, ywords) ;
705700 if VARTIME && done. to_bool_vartime ( ) {
706- // Set the upper limbs to zero
707- x. trailing_mut ( xi) . fill ( Limb :: ZERO ) ;
701+ zero_hi = x. trailing ( xi) . is_zero ( ) ;
708702 break ;
709703 }
710704
711705 // Compute the quotient limb that will clear the low dividend limb
712- let quo = Limb :: select ( x. limbs [ xi] . wrapping_mul ( y_inv) , Limb :: ZERO , done) ;
706+ let quo = Limb :: select ( x. limbs [ xi] . wrapping_mul ( y_inv) , x . limbs [ xi ] , done) ;
713707 x. limbs [ xi] = quo;
714708
709+ if !VARTIME {
710+ zero_hi = zero_hi. and ( Limb :: select ( Limb :: ZERO , quo, done) . is_zero ( ) ) ;
711+ }
712+
715713 let ( _, mut carry) = quo. widening_mul ( y. limbs [ 0 ] ) ;
716714 let mut sub;
717715 let mut borrow = Limb :: ZERO ;
@@ -735,20 +733,60 @@ impl UintRef {
735733 xi += 1 ;
736734 }
737735
738- meta_carry. is_zero ( )
736+ meta_carry. is_zero ( ) . and ( zero_hi )
739737 }
738+ }
740739
741- // Check that `self` can be cleanly divided by 2^zs: the bottom zs bits are zero.
742- #[ inline( always) ]
743- const fn ensure_trailing_zeros ( & self , zs : u32 ) -> Choice {
744- let z_words = ( zs >> Limb :: LOG2_BITS ) as usize ;
745- let z_bits = zs & ( Limb :: BITS - 1 ) ;
746- if z_words >= self . nlimbs ( ) {
747- self . is_zero ( )
748- } else {
749- self . leading ( z_words)
750- . is_zero ( )
751- . and ( self . limbs [ z_words] . restrict_bits ( z_bits) . is_zero ( ) )
740+ #[ cfg( test) ]
741+ mod tests {
742+ use crate :: { U64 , U128 , U192 , Uint } ;
743+
744+ #[ test]
745+ fn div_exact_inexact ( ) {
746+ fn check < const L : usize , const R : usize > ( lhs : Uint < L > , rhs : Uint < R > , exact : bool ) {
747+ let ( mut q, mut r) = ( lhs, rhs) ;
748+ let actual = q
749+ . as_mut_uint_ref ( )
750+ . div_exact ( r. as_mut_uint_ref ( ) )
751+ . to_bool_vartime ( ) ;
752+ assert_eq ! ( actual, exact, "{lhs} / {rhs}: exact={actual}" ) ;
753+ let ( mut q, mut r) = ( lhs, rhs) ;
754+ let actual = q
755+ . as_mut_uint_ref ( )
756+ . div_exact_vartime ( r. as_mut_uint_ref ( ) )
757+ . to_bool_vartime ( ) ;
758+ assert_eq ! ( actual, exact, "{lhs} / {rhs}: exact={actual}" ) ;
752759 }
760+
761+ check (
762+ U64 :: from_be_hex ( "0000000000000010" ) ,
763+ U64 :: from_be_hex ( "0000000000000010" ) ,
764+ true ,
765+ ) ;
766+ check (
767+ U64 :: from_be_hex ( "0000000000000010" ) ,
768+ U128 :: from_be_hex ( "00000000000000000000000000000001" ) ,
769+ true ,
770+ ) ;
771+ check (
772+ U64 :: from_be_hex ( "0000000000000000" ) ,
773+ U128 :: from_be_hex ( "10000000000000000000000000000000" ) ,
774+ true ,
775+ ) ;
776+ check (
777+ U64 :: from_be_hex ( "0000000000000001" ) ,
778+ U64 :: from_be_hex ( "0000000000000010" ) ,
779+ false ,
780+ ) ;
781+ check (
782+ U64 :: from_be_hex ( "0000000000000001" ) ,
783+ U128 :: from_be_hex ( "00000000000000100000000000000000" ) ,
784+ false ,
785+ ) ;
786+ check (
787+ U192 :: from_be_hex ( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000" ) ,
788+ U192 :: from_be_hex ( "000000000000000100000000000000003ACEDC010F13471D" ) ,
789+ false ,
790+ ) ;
753791 }
754792}
0 commit comments