Skip to content

Commit 7693d58

Browse files
slumberPratyush
andauthored
Handle zero-case in group scalar multiplication (#124)
Co-authored-by: Pratyush Mishra <[email protected]>
1 parent f58b7b7 commit 7693d58

File tree

5 files changed

+75
-6
lines changed

5 files changed

+75
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Pending
44
- [\#117](https://github.com/arkworks-rs/r1cs-std/pull/117) Fix result of `precomputed_base_scalar_mul_le` to not discard previous value.
5+
- [\#124](https://github.com/arkworks-rs/r1cs-std/pull/124) Fix `scalar_mul_le` constraints unsatisfiability when short Weierstrass point is zero.
56

67
### Breaking changes
78

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ ark-mnt4-753 = { version = "0.4.0", features = ["curve"], default-features = fal
3636
ark-mnt6-298 = { version = "0.4.0", default-features = false }
3737
ark-mnt6-753 = { version = "0.4.0", default-features = false }
3838
ark-pallas = { version = "0.4.0", features = ["curve"], default-features = false }
39+
ark-bn254 = { version = "0.4.0", features = ["curve"], default-features = false }
3940

4041
[features]
4142
default = ["std"]
@@ -85,4 +86,4 @@ ark-mnt4-298 = { git = "https://github.com/arkworks-rs/curves/" }
8586
ark-mnt4-753 = { git = "https://github.com/arkworks-rs/curves/" }
8687
ark-mnt6-298 = { git = "https://github.com/arkworks-rs/curves/" }
8788
ark-mnt6-753 = { git = "https://github.com/arkworks-rs/curves/" }
88-
ark-pallas = { git = "https://github.com/arkworks-rs/curves/" }
89+
ark-pallas = { git = "https://github.com/arkworks-rs/curves/" }

src/groups/curves/short_weierstrass/mod.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,18 @@ where
512512
}
513513
let self_affine = self.to_affine()?;
514514
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)?;
517527
let non_zero_self = NonZeroAffineVar::new(x, y);
518528

519529
let mut bits = bits.collect::<Vec<_>>();
@@ -968,3 +978,61 @@ where
968978
Ok(bytes)
969979
}
970980
}
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+
}

src/groups/curves/short_weierstrass/non_zero_affine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::*;
2-
use ark_ec::AdditiveGroup;
2+
use ark_ff::AdditiveGroup;
33
use ark_std::ops::Add;
44

55
/// An affine representation of a prime order curve point that is guaranteed

src/pairing/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::prelude::*;
2-
use ark_ec::pairing::Pairing;
3-
use ark_ec::CurveGroup;
2+
use ark_ec::{pairing::Pairing, CurveGroup};
43
use ark_ff::Field;
54
use ark_relations::r1cs::SynthesisError;
65
use core::fmt::Debug;

0 commit comments

Comments
 (0)