@@ -512,8 +512,18 @@ where
512
512
}
513
513
let self_affine = self . to_affine ( ) ?;
514
514
let ( x, y, infinity) = ( self_affine. x , self_affine. y , self_affine. infinity ) ;
515
- // We first handle the non-zero case, and then later
516
- // will conditionally select zero if `self` was zero.
515
+ // We first handle the non-zero case, and then later will conditionally select
516
+ // zero if `self` was zero. However, we also want to make sure that generated
517
+ // constraints are satisfiable in both cases.
518
+ //
519
+ // In particular, using non-sensible values for `x` and `y` in zero-case may cause
520
+ // `unchecked` operations to generate constraints that can never be satisfied, depending
521
+ // on the curve equation coefficients.
522
+ //
523
+ // The safest approach is to use coordinates of some point from the curve, thus not
524
+ // violating assumptions of `NonZeroAffine`. For instance, generator point.
525
+ let x = infinity. select ( & F :: constant ( P :: GENERATOR . x ) , & x) ?;
526
+ let y = infinity. select ( & F :: constant ( P :: GENERATOR . y ) , & y) ?;
517
527
let non_zero_self = NonZeroAffineVar :: new ( x, y) ;
518
528
519
529
let mut bits = bits. collect :: < Vec < _ > > ( ) ;
@@ -968,3 +978,61 @@ where
968
978
Ok ( bytes)
969
979
}
970
980
}
981
+
982
+ #[ cfg( test) ]
983
+ mod test_sw_curve {
984
+ use crate :: {
985
+ alloc:: AllocVar ,
986
+ eq:: EqGadget ,
987
+ fields:: { fp:: FpVar , nonnative:: NonNativeFieldVar } ,
988
+ groups:: { curves:: short_weierstrass:: ProjectiveVar , CurveVar } ,
989
+ ToBitsGadget ,
990
+ } ;
991
+ use ark_ec:: {
992
+ short_weierstrass:: { Projective , SWCurveConfig } ,
993
+ CurveGroup ,
994
+ } ;
995
+ use ark_ff:: PrimeField ;
996
+ use ark_relations:: r1cs:: { ConstraintSystem , Result } ;
997
+ use ark_std:: UniformRand ;
998
+ use num_traits:: Zero ;
999
+
1000
+ fn zero_point_scalar_mul_satisfied < G > ( ) -> Result < bool >
1001
+ where
1002
+ G : CurveGroup ,
1003
+ G :: BaseField : PrimeField ,
1004
+ G :: Config : SWCurveConfig ,
1005
+ {
1006
+ let mut rng = ark_std:: test_rng ( ) ;
1007
+
1008
+ let cs = ConstraintSystem :: new_ref ( ) ;
1009
+ let point_in = Projective :: < G :: Config > :: zero ( ) ;
1010
+ let point_out = Projective :: < G :: Config > :: zero ( ) ;
1011
+ let scalar = G :: ScalarField :: rand ( & mut rng) ;
1012
+
1013
+ let point_in =
1014
+ ProjectiveVar :: < G :: Config , FpVar < G :: BaseField > > :: new_witness ( cs. clone ( ) , || {
1015
+ Ok ( point_in)
1016
+ } ) ?;
1017
+ let point_out =
1018
+ ProjectiveVar :: < G :: Config , FpVar < G :: BaseField > > :: new_input ( cs. clone ( ) , || {
1019
+ Ok ( point_out)
1020
+ } ) ?;
1021
+ let scalar = NonNativeFieldVar :: new_input ( cs. clone ( ) , || Ok ( scalar) ) ?;
1022
+
1023
+ let mul = point_in. scalar_mul_le ( scalar. to_bits_le ( ) . unwrap ( ) . iter ( ) ) ?;
1024
+
1025
+ point_out. enforce_equal ( & mul) ?;
1026
+
1027
+ cs. is_satisfied ( )
1028
+ }
1029
+
1030
+ #[ test]
1031
+ fn test_zero_point_scalar_mul ( ) {
1032
+ assert ! ( zero_point_scalar_mul_satisfied:: <ark_bls12_381:: G1Projective >( ) . unwrap( ) ) ;
1033
+ assert ! ( zero_point_scalar_mul_satisfied:: <ark_pallas:: Projective >( ) . unwrap( ) ) ;
1034
+ assert ! ( zero_point_scalar_mul_satisfied:: <ark_mnt4_298:: G1Projective >( ) . unwrap( ) ) ;
1035
+ assert ! ( zero_point_scalar_mul_satisfied:: <ark_mnt6_298:: G1Projective >( ) . unwrap( ) ) ;
1036
+ assert ! ( zero_point_scalar_mul_satisfied:: <ark_bn254:: G1Projective >( ) . unwrap( ) ) ;
1037
+ }
1038
+ }
0 commit comments