@@ -238,12 +238,17 @@ impl<TargetF: PrimeField, BaseF: PrimeField> AllocatedEmulatedFpVar<TargetF, Bas
238238 }
239239 }
240240
241+ let padding_bit_len = {
242+ let mut one = BaseF :: ONE . into_bigint ( ) ;
243+ one <<= surfeit as u32 ;
244+ BaseF :: from ( one)
245+ } ;
241246 let result = AllocatedEmulatedFpVar :: < TargetF , BaseF > {
242247 cs : self . cs ( ) ,
243248 limbs,
244- num_of_additions_over_normal_form : self . num_of_additions_over_normal_form
245- + ( other . num_of_additions_over_normal_form + BaseF :: one ( ) )
246- + ( other . num_of_additions_over_normal_form + BaseF :: one ( ) ) ,
249+ num_of_additions_over_normal_form : self . num_of_additions_over_normal_form // this_limb
250+ + padding_bit_len // pad_non_top_limb / pad_top_limb
251+ + BaseF :: one ( ) , // pad_to_kp_limb
247252 is_in_the_normal_form : false ,
248253 target_phantom : PhantomData ,
249254 } ;
@@ -424,9 +429,19 @@ impl<TargetF: PrimeField, BaseF: PrimeField> AllocatedEmulatedFpVar<TargetF, Bas
424429 Ok ( AllocatedMulResultVar {
425430 cs : self . cs ( ) ,
426431 limbs : prod_limbs,
432+ // New number is upper bounded by:
433+ //
434+ // (a+1)2^{bits_per_limb} * (b+1)2^{bits_per_limb} * m = (ab+a+b+1)*m*2^{2*bits_per_limb}
435+ //
436+ // where `a = self_reduced.num_of_additions_over_normal_form` and
437+ // `b = other_reduced.num_of_additions_over_normal_form`
438+ // - why m pair: at cell m, there are m possible pairs (one limb from each var) that can add to cell m
439+ //
440+ // In theory, we can let `prod_of_num_of_additions = (m(ab+a+b+1)-1)`. But below, we use an overestimation.
427441 prod_of_num_of_additions : ( self_reduced. num_of_additions_over_normal_form
428442 + BaseF :: one ( ) )
429- * ( other_reduced. num_of_additions_over_normal_form + BaseF :: one ( ) ) ,
443+ * ( other_reduced. num_of_additions_over_normal_form + BaseF :: one ( ) )
444+ * BaseF :: from ( ( params. num_limbs ) as u32 ) ,
430445 target_phantom : PhantomData ,
431446 } )
432447 }
@@ -459,13 +474,6 @@ impl<TargetF: PrimeField, BaseF: PrimeField> AllocatedEmulatedFpVar<TargetF, Bas
459474 for limb in p_representations. iter ( ) {
460475 p_gadget_limbs. push ( FpVar :: < BaseF > :: Constant ( * limb) ) ;
461476 }
462- let p_gadget = Self {
463- cs : self . cs ( ) ,
464- limbs : p_gadget_limbs,
465- num_of_additions_over_normal_form : BaseF :: one ( ) ,
466- is_in_the_normal_form : false ,
467- target_phantom : PhantomData ,
468- } ;
469477
470478 // Get delta = self - other
471479 let cs = self . cs ( ) . or ( other. cs ( ) ) . or ( should_enforce. cs ( ) ) ;
@@ -489,7 +497,7 @@ impl<TargetF: PrimeField, BaseF: PrimeField> AllocatedEmulatedFpVar<TargetF, Bas
489497
490498 // Compute k * p
491499 let mut kp_gadget_limbs = Vec :: new ( ) ;
492- for limb in p_gadget . limbs . iter ( ) {
500+ for limb in p_gadget_limbs . iter ( ) {
493501 kp_gadget_limbs. push ( limb * & k_gadget) ;
494502 }
495503
@@ -911,3 +919,108 @@ impl<TargetF: PrimeField, BaseF: PrimeField> Clone for AllocatedEmulatedFpVar<Ta
911919 }
912920 }
913921}
922+
923+ #[ cfg( test) ]
924+ mod test {
925+ use ark_ec:: { bls12:: Bls12Config , pairing:: Pairing } ;
926+ use ark_ff:: PrimeField ;
927+ use ark_relations:: gr1cs:: ConstraintSystem ;
928+
929+ use crate :: {
930+ alloc:: AllocVar ,
931+ fields:: {
932+ emulated_fp:: { test:: check_constraint, AllocatedEmulatedFpVar } ,
933+ fp:: FpVar ,
934+ } ,
935+ } ;
936+
937+ #[ test]
938+ fn pr_157 ( ) {
939+ type TargetF = <ark_bls12_381:: Config as Bls12Config >:: Fp ;
940+ type BaseF = <ark_bls12_377:: Bls12_377 as Pairing >:: ScalarField ;
941+
942+ let cs = ConstraintSystem :: new_ref ( ) ;
943+
944+ let l0: AllocatedEmulatedFpVar < TargetF , BaseF > =
945+ AllocatedEmulatedFpVar :: new_input ( cs. clone ( ) , || {
946+ Ok ( TargetF :: from (
947+ TargetF :: from ( 1 ) . into_bigint ( )
948+ << ( <TargetF as PrimeField >:: MODULUS_BIT_SIZE - 1 ) ,
949+ ) + TargetF :: from ( -1 ) )
950+ } )
951+ . unwrap ( ) ;
952+
953+ // Accumulate errors
954+ let l1 = l0. sub ( & l0) . unwrap ( ) ;
955+ let l1 = l1. sub ( & l1) . unwrap ( ) ;
956+ let l1 = l1. sub ( & l1) . unwrap ( ) ;
957+ let l1 = l1. sub ( & l1) . unwrap ( ) ;
958+ let l1 = l1. sub ( & l1) . unwrap ( ) ;
959+
960+ let l2 = l1. add ( & l1) . unwrap ( ) ;
961+
962+ // Increase l1's surfeit
963+ // - The goal is to ensure that the number of limbs, as grouped by `group_and_check_equality`,
964+ // falls near the threshold between 17 and 18 limbs.
965+ // - This increases the chance that accumulated error in `sub` causes an overflow within
966+ // `group_and_check_equality`.
967+ let mut l1 = l1;
968+ for _ in 0 ..( 293 - 242 ) {
969+ l1 = l1. add ( & l0) . unwrap ( ) ;
970+ }
971+
972+ let _ = l1. mul ( & l2) . unwrap ( ) ;
973+ assert ! ( cs. is_satisfied( ) . unwrap( ) ) ;
974+ }
975+
976+ #[ test]
977+ fn pr_157_sub ( ) {
978+ type TargetF = <ark_bls12_381:: Config as Bls12Config >:: Fp ;
979+ type BaseF = <ark_bls12_377:: Bls12_377 as Pairing >:: ScalarField ;
980+
981+ let self_limb_values = [
982+ 100 , 2618 , 1428 , 2152 , 2602 , 1242 , 2823 , 511 , 1752 , 2058 , 3599 , 1113 , 3207 , 3601 , 2736 ,
983+ 435 , 1108 , 2965 , 2685 , 1705 , 1016 , 1343 , 1760 , 2039 , 1355 , 1767 , 2355 , 1945 , 3594 ,
984+ 4066 , 1913 , 2646 ,
985+ ] ;
986+ let self_num_of_additions_over_normal_form = 1 ;
987+ let self_is_in_the_normal_form = false ;
988+ let other_limb_values = [
989+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
990+ 0 , 0 , 4 ,
991+ ] ;
992+ let other_num_of_additions_over_normal_form = 1 ;
993+ let other_is_in_the_normal_form = false ;
994+
995+ let cs = ConstraintSystem :: new_ref ( ) ;
996+
997+ let left_limb = self_limb_values
998+ . iter ( )
999+ . map ( |v| FpVar :: new_input ( cs. clone ( ) , || Ok ( BaseF :: from ( * v) ) ) . unwrap ( ) )
1000+ . collect ( ) ;
1001+ let left: AllocatedEmulatedFpVar < TargetF , BaseF > = AllocatedEmulatedFpVar {
1002+ cs : cs. clone ( ) ,
1003+ limbs : left_limb,
1004+ num_of_additions_over_normal_form : BaseF :: from ( self_num_of_additions_over_normal_form) ,
1005+ is_in_the_normal_form : self_is_in_the_normal_form,
1006+ target_phantom : std:: marker:: PhantomData ,
1007+ } ;
1008+
1009+ let other_limb = other_limb_values
1010+ . iter ( )
1011+ . map ( |v| FpVar :: new_input ( cs. clone ( ) , || Ok ( BaseF :: from ( * v) ) ) . unwrap ( ) )
1012+ . collect ( ) ;
1013+ let right: AllocatedEmulatedFpVar < TargetF , BaseF > = AllocatedEmulatedFpVar {
1014+ cs : cs. clone ( ) ,
1015+ limbs : other_limb,
1016+ num_of_additions_over_normal_form : BaseF :: from ( other_num_of_additions_over_normal_form) ,
1017+ is_in_the_normal_form : other_is_in_the_normal_form,
1018+ target_phantom : std:: marker:: PhantomData ,
1019+ } ;
1020+
1021+ let result = left. sub_without_reduce ( & right) . unwrap ( ) ;
1022+ assert ! ( check_constraint( & left) ) ;
1023+ assert ! ( check_constraint( & right) ) ;
1024+ assert ! ( check_constraint( & result) ) ;
1025+ }
1026+ }
0 commit comments