@@ -16,14 +16,6 @@ fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
1616 tmp as u64
1717}
1818
19- /// a + b * c → (result, carry) (no input carry)
20- #[ inline( always) ]
21- fn mac_no_carry ( a : u64 , b : u64 , c : u64 , carry : & mut u64 ) -> u64 {
22- let tmp = ( a as u128 ) + ( b as u128 ) * ( c as u128 ) ;
23- * carry = ( tmp >> 64 ) as u64 ;
24- tmp as u64
25- }
26-
2719/// *a += b + carry → new carry
2820#[ inline( always) ]
2921fn adc ( a : & mut u64 , b : u64 , carry : u64 ) -> u64 {
@@ -45,8 +37,6 @@ const N: usize = 4;
4537const MODULUS : [ u64 ; N ] = <FrConfig as MontConfig < N > >:: MODULUS . 0 ;
4638const INV : u64 = <FrConfig as MontConfig < N > >:: INV ;
4739const R : BigInt < N > = <FrConfig as MontConfig < N > >:: R ;
48- #[ allow( dead_code) ]
49- const R2 : BigInt < N > = <FrConfig as MontConfig < N > >:: R2 ;
5040
5141const MODULUS_HAS_SPARE_BIT : bool = MODULUS [ N - 1 ] >> 63 == 0 ;
5242const MODULUS_NUM_SPARE_BITS : u32 = MODULUS [ N - 1 ] . leading_zeros ( ) ;
@@ -124,7 +114,6 @@ const PRECOMP_TABLE_SIZE: usize = 1 << 14;
124114/// `PRECOMP_TABLE[i]` = Montgomery form of `i` for BN254 Fr.
125115///
126116/// Uses `Fp::new()` which converts standard form → Montgomery form at compile time.
127- #[ allow( long_running_const_eval) ]
128117static PRECOMP_TABLE : [ Fr ; PRECOMP_TABLE_SIZE ] = {
129118 let mut table: [ Fr ; PRECOMP_TABLE_SIZE ] =
130119 [ Fp :: new_unchecked ( BigInt ( [ 0u64 ; N ] ) ) ; PRECOMP_TABLE_SIZE ] ;
@@ -165,6 +154,7 @@ fn nplus1_from_low_n_and_top(low_n: [u64; N], top: u64) -> BigInt<5> {
165154/// Conditional subtraction for Barrett reduction: reduce a 5-limb intermediate
166155/// that is known to be < 4p down to < p (4 limbs).
167156#[ inline( always) ]
157+ #[ expect( clippy:: unwrap_used) ]
168158fn barrett_cond_subtract ( r_tmp : BigInt < 5 > ) -> BigInt < N > {
169159 let ( m2_lo, _m2_hi) = MODULUS_TIMES_2 ;
170160 let ( m3_lo, _m3_hi) = MODULUS_TIMES_3 ;
@@ -268,26 +258,10 @@ fn mul_bigint5_by_u64_in_place(a: &mut BigInt<5>, b: u64) {
268258 // Overflow is discarded (caller ensures result fits in 5 limbs)
269259}
270260
271- /// Barrett reduce an L-limb BigInt to a field element.
272- ///
273- /// Folds from high limb to low, applying the 5→4 kernel at each step.
274- #[ inline( always) ]
275- pub ( crate ) fn from_barrett_reduce < const L : usize > ( unreduced : BigInt < L > ) -> Fr {
276- debug_assert ! ( L >= N ) ;
277- let mut acc = BigInt :: < N > ( [ 0u64 ; N ] ) ;
278- let mut i = L ;
279- while i > 0 {
280- i -= 1 ;
281- let c5 = nplus1_from_low_and_high ( unreduced. 0 [ i] , acc. 0 ) ;
282- acc = barrett_reduce_5_to_4 ( c5) ;
283- }
284- Fp :: new_unchecked ( acc)
285- }
286-
287261/// Perform N Montgomery reduction steps on a mutable buffer of L >= 2N limbs.
288262/// Returns carry from the final step.
289263#[ inline( always) ]
290- #[ allow ( clippy:: needless_range_loop) ]
264+ #[ expect ( clippy:: needless_range_loop) ]
291265fn montgomery_reduce_in_place < const L : usize > ( limbs : & mut [ u64 ; L ] ) -> u64 {
292266 debug_assert ! ( L >= 2 * N ) ;
293267 let mut carry2 = 0u64 ;
@@ -396,6 +370,7 @@ fn from_unchecked_nplus1(element: BigInt<5>) -> Fr {
396370
397371/// Barrett reduce BigInt<6> → Fr via two rounds
398372#[ inline( always) ]
373+ #[ expect( clippy:: unwrap_used) ]
399374fn from_unchecked_nplus2 ( element : BigInt < 6 > ) -> Fr {
400375 // Round 1: reduce top 5 limbs (indices 1..6)
401376 let c1 = BigInt :: < 5 > ( element. 0 [ 1 ..6 ] . try_into ( ) . unwrap ( ) ) ;
@@ -486,74 +461,14 @@ pub(crate) fn from_u128(n: u128) -> Fr {
486461 }
487462}
488463
489- /// Multiply by a sparse RHS with exactly 2 non-zero high limbs at positions N-2 and N-1.
490- ///
491- /// This is used in the Challenge × Field hot path where the challenge value
492- /// has only its top 2 limbs set (128-bit challenge stored in high position).
493- ///
494- /// Interleaves multiplication with Montgomery reduction for efficiency.
495- #[ inline( always) ]
496- pub ( crate ) fn mul_by_hi_2limbs ( a : Fr , limb_lo : u64 , limb_hi : u64 ) -> Fr {
497- let a_limbs = a. 0 . 0 ;
498- let mut r = [ 0u64 ; N ] ;
499-
500- // Process limb at position N-2 (limb_lo), with interleaved Montgomery step
501- {
502- let mut carry1 = 0u64 ;
503- r[ 0 ] = mac_no_carry ( r[ 0 ] , a_limbs[ 0 ] , limb_lo, & mut carry1) ;
504- let k = r[ 0 ] . wrapping_mul ( INV ) ;
505- let mut carry2 = 0u64 ;
506- let _ = mac_no_carry ( r[ 0 ] , k, MODULUS [ 0 ] , & mut carry2) ;
507- for j in 1 ..N {
508- let new_rj = mac_with_carry ( r[ j] , a_limbs[ j] , limb_lo, & mut carry1) ;
509- let new_rj_minus_1 = mac_with_carry ( new_rj, k, MODULUS [ j] , & mut carry2) ;
510- r[ j] = new_rj;
511- r[ j - 1 ] = new_rj_minus_1;
512- }
513- r[ N - 1 ] = carry1. wrapping_add ( carry2) ;
514- }
515-
516- // Process limb at position N-1 (limb_hi), with interleaved Montgomery step
517- {
518- let mut carry1 = 0u64 ;
519- r[ 0 ] = mac_no_carry ( r[ 0 ] , a_limbs[ 0 ] , limb_hi, & mut carry1) ;
520- let k = r[ 0 ] . wrapping_mul ( INV ) ;
521- let mut carry2 = 0u64 ;
522- let _ = mac_no_carry ( r[ 0 ] , k, MODULUS [ 0 ] , & mut carry2) ;
523- for j in 1 ..N {
524- let new_rj = mac_with_carry ( r[ j] , a_limbs[ j] , limb_hi, & mut carry1) ;
525- let new_rj_minus_1 = mac_with_carry ( new_rj, k, MODULUS [ j] , & mut carry2) ;
526- r[ j] = new_rj;
527- r[ j - 1 ] = new_rj_minus_1;
528- }
529- r[ N - 1 ] = carry1. wrapping_add ( carry2) ;
530- }
531-
532- let mut out = Fp :: new_unchecked ( BigInt :: < N > ( r) ) ;
533- if compare_4 ( out. 0 . 0 , MODULUS ) != core:: cmp:: Ordering :: Less {
534- out. 0 = BigInt ( sub_4 ( out. 0 . 0 , MODULUS ) ) ;
535- }
536- out
537- }
538-
539464/// Wrap a raw BigInt<4> as Fr without any reduction (caller guarantees it's valid).
540465#[ inline( always) ]
541466pub ( crate ) fn from_bigint_unchecked ( r : BigInt < N > ) -> Fr {
542467 Fp :: new_unchecked ( r)
543468}
544469
545- /// Multiply `BigInt<N>` by `u64` and accumulate into `BigInt<5>`.
546- #[ inline( always) ]
547- pub ( crate ) fn mul_u64_accumulate ( acc : & mut BigInt < 5 > , a : & BigInt < N > , b : u64 ) {
548- let mut carry = 0u64 ;
549- for i in 0 ..N {
550- acc. 0 [ i] = mac_with_carry ( acc. 0 [ i] , a. 0 [ i] , b, & mut carry) ;
551- }
552- let final_carry = adc ( & mut acc. 0 [ N ] , carry, 0 ) ;
553- debug_assert ! ( final_carry == 0 , "overflow in mul_u64_accumulate" ) ;
554- }
555-
556470#[ cfg( test) ]
471+ #[ expect( clippy:: unwrap_used) ]
557472mod tests {
558473 use super :: * ;
559474 use ark_ff:: { PrimeField , UniformRand } ;
@@ -697,35 +612,6 @@ mod tests {
697612 }
698613 }
699614
700- #[ test]
701- fn barrett_reduce_correct ( ) {
702- let mut rng = test_rng ( ) ;
703- // Barrett reduce of a product a*b should equal a*b in the field
704- for _ in 0 ..200 {
705- let a = Fr :: rand ( & mut rng) ;
706- let b = Fr :: rand ( & mut rng) ;
707- // Compute unreduced product in 8 limbs
708- let a_bigint = a. into_bigint ( ) ;
709- let b_bigint = b. into_bigint ( ) ;
710- let mut prod = BigInt :: < 8 > :: zero ( ) ;
711- for i in 0 ..N {
712- let mut carry = 0u64 ;
713- for j in 0 ..N {
714- prod. 0 [ i + j] =
715- mac_with_carry ( prod. 0 [ i + j] , a_bigint. 0 [ i] , b_bigint. 0 [ j] , & mut carry) ;
716- }
717- prod. 0 [ i + N ] = carry;
718- }
719- // Barrett reduce should give the same result as Montgomery reduce
720- // (both map from standard 8-limb → 4-limb Montgomery)
721- let reduced = from_barrett_reduce :: < 8 > ( prod) ;
722- // Verify it's a valid field element by roundtripping
723- let _ = reduced. into_bigint ( ) ;
724- }
725- // Barrett reduce of zero should give zero
726- assert_eq ! ( from_barrett_reduce:: <5 >( BigInt :: <5 >:: zero( ) ) , Fr :: zero( ) ) ;
727- }
728-
729615 #[ test]
730616 fn montgomery_reduce_roundtrip ( ) {
731617 let mut rng = test_rng ( ) ;
@@ -751,23 +637,4 @@ mod tests {
751637 assert_eq ! ( got, expected, "Montgomery reduce roundtrip mismatch" ) ;
752638 }
753639 }
754-
755- #[ test]
756- fn mul_by_hi_2limbs_correct ( ) {
757- let mut rng = test_rng ( ) ;
758- for _ in 0 ..200 {
759- let a = Fr :: rand ( & mut rng) ;
760- let lo: u64 = rng. gen ( ) ;
761- let hi: u64 = rng. gen ( ) ;
762- // mul_by_hi_2limbs treats [0, 0, lo, hi] as a raw Montgomery-form scalar
763- let scalar = Fp :: new_unchecked ( BigInt :: new ( [ 0 , 0 , lo, hi] ) ) ;
764- let expected = a * scalar;
765- let got = mul_by_hi_2limbs ( a, lo, hi) ;
766- assert_eq ! (
767- got, expected,
768- "mul_by_hi_2limbs mismatch: lo={}, hi={}" ,
769- lo, hi
770- ) ;
771- }
772- }
773640}
0 commit comments