diff --git a/plonky2/src/gadgets/curve.rs b/plonky2/src/gadgets/curve.rs index 908ed66e..83309196 100644 --- a/plonky2/src/gadgets/curve.rs +++ b/plonky2/src/gadgets/curve.rs @@ -4,6 +4,7 @@ use plonky2_field::field_types::Field; use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; use crate::gadgets::nonnative::NonNativeTarget; use crate::hash::hash_types::RichField; +use crate::iop::target::BoolTarget; use crate::plonk::circuit_builder::CircuitBuilder; /// A Target representing an affine point on the curve `C`. We use incomplete arithmetic for efficiency, @@ -117,6 +118,23 @@ impl, const D: usize> CircuitBuilder { AffinePointTarget { x: x3, y: y3 } } + pub fn curve_conditional_add( + &mut self, + p1: &AffinePointTarget, + p2: &AffinePointTarget, + b: BoolTarget, + ) -> AffinePointTarget { + let to_add_x = self.mul_nonnative_by_bool(&p2.x, b); + let to_add_y = self.mul_nonnative_by_bool(&p2.y, b); + let sum_x = self.add_nonnative(&p1.x, &to_add_x); + let sum_y = self.add_nonnative(&p1.y, &to_add_y); + + AffinePointTarget { + x: sum_x, + y: sum_y, + } + } + pub fn curve_scalar_mul( &mut self, p: &AffinePointTarget, @@ -295,6 +313,38 @@ mod tests { verify(proof, &data.verifier_only, &data.common) } + #[test] + fn test_curve_conditional_add() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_ecc_config(); + + let pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let g = Secp256K1::GENERATOR_AFFINE; + let double_g = g.double(); + let g_plus_2g = (g + double_g).to_affine(); + let g_plus_2g_expected = builder.constant_affine_point(g_plus_2g); + + let g_expected = builder.constant_affine_point(g); + let double_g_target = builder.curve_double(&g_expected); + let t = builder._true(); + let f = builder._false(); + let g_plus_2g_actual = builder.curve_conditional_add(&g_expected, &double_g_target, t); + let g_actual = builder.curve_conditional_add(&g_expected, &double_g_target, f); + + builder.connect_affine_point(&g_plus_2g_expected, &g_plus_2g_actual); + builder.connect_affine_point(&g_expected, &g_actual); + + let data = builder.build::(); + let proof = data.prove(pw).unwrap(); + + verify(proof, &data.verifier_only, &data.common) + } + #[test] #[ignore] fn test_curve_mul() -> Result<()> { diff --git a/plonky2/src/gadgets/curve_windowed_mul.rs b/plonky2/src/gadgets/curve_windowed_mul.rs index 9abc4ea3..f9915043 100644 --- a/plonky2/src/gadgets/curve_windowed_mul.rs +++ b/plonky2/src/gadgets/curve_windowed_mul.rs @@ -120,7 +120,7 @@ mod tests { let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); - let num_points = 8; + let num_points = 16; let points: Vec<_> = (0..num_points) .map(|_| { let g = (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE) @@ -130,7 +130,7 @@ mod tests { .collect(); let mut rng = rand::thread_rng(); - let access_index = rng.gen::() % 8; + let access_index = rng.gen::() % num_points; let access_index_target = builder.constant(F::from_canonical_usize(access_index)); let selected = builder.random_access_curve_points(access_index_target, points.clone());