diff --git a/plonky2/src/gadgets/curve_msm.rs b/plonky2/src/gadgets/curve_msm.rs index 43a22da2..aa5a8d34 100644 --- a/plonky2/src/gadgets/curve_msm.rs +++ b/plonky2/src/gadgets/curve_msm.rs @@ -1,7 +1,8 @@ +use itertools::Itertools; use num::BigUint; use plonky2_field::extension_field::Extendable; -use crate::curve::curve_types::{Curve, CurveScalar}; +use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; use crate::field::field_types::Field; use crate::gadgets::curve::AffinePointTarget; use crate::gadgets::nonnative::NonNativeTarget; @@ -70,18 +71,126 @@ impl, const D: usize> CircuitBuilder { result } + + // pub fn quad_curve_msm( + // &mut self, + // points: [AffinePointTarget; 4], + // scalars: [NonNativeTarget; 4], + // ) -> AffinePointTarget { + // let limbs = scalars + // .iter() + // .map(|s| self.split_nonnative_to_bits(n)) + // .collect_vec(); + // + // let hash_0 = KeccakHash::<32>::hash_no_pad(&[F::ZERO]); + // let hash_0_scalar = C::ScalarField::from_biguint(BigUint::from_bytes_le( + // &GenericHashOut::::to_bytes(&hash_0), + // )); + // let rando = (CurveScalar(hash_0_scalar) * C::GENERATOR_PROJECTIVE).to_affine(); + // let rando_t = self.constant_affine_point(rando); + // let neg_rando = self.constant_affine_point(-rando); + // + // let mut precomputation = vec![points[0].clone(); 16]; + // for i in 0..4 { + // precomputation[1 << i] = points[i].clone(); + // for j in 1..1 << (i - 1) {} + // } + // let mut cur_p = rando_t.clone(); + // let mut cur_q = rando_t.clone(); + // for i in 0..4 { + // precomputation[i] = cur_p.clone(); + // precomputation[4 * i] = cur_q.clone(); + // cur_p = self.curve_add(&cur_p, p); + // cur_q = self.curve_add(&cur_q, q); + // } + // for i in 1..4 { + // precomputation[i] = self.curve_add(&precomputation[i], &neg_rando); + // precomputation[4 * i] = self.curve_add(&precomputation[4 * i], &neg_rando); + // } + // for i in 1..4 { + // for j in 1..4 { + // precomputation[i + 4 * j] = + // self.curve_add(&precomputation[i], &precomputation[4 * j]); + // } + // } + // + // let four = self.constant(F::from_canonical_usize(4)); + // + // let zero = self.zero(); + // let mut result = rando_t; + // for (limb_n, limb_m) in limbs_n.into_iter().zip(limbs_m).rev() { + // result = self.curve_repeated_double(&result, 2); + // let index = self.mul_add(four, limb_m, limb_n); + // let r = self.random_access_curve_points(index, precomputation.clone()); + // let is_zero = self.is_equal(index, zero); + // let should_add = self.not(is_zero); + // result = self.curve_conditional_add(&result, &r, should_add); + // } + // let starting_point_multiplied = + // (0..C::ScalarField::BITS).fold(rando, |acc, _| acc.double()); + // let to_add = self.constant_affine_point(-starting_point_multiplied); + // result = self.curve_add(&result, &to_add); + // + // result + // } + + pub fn fixed_base_curve_mul( + &mut self, + base: &AffinePoint, + scalar: &NonNativeTarget, + ) -> AffinePointTarget { + let doubled_base = (0..scalar.value.limbs.len() * 8).scan(base.clone(), |acc, _| { + let tmp = acc.clone(); + for _ in 0..4 { + *acc = acc.double(); + } + Some(tmp) + }); + + let bits = self.split_nonnative_to_4_bit_limbs(scalar); + + // let rando = (CurveScalar(C::ScalarField::rand()) * C::GENERATOR_PROJECTIVE).to_affine(); + let hash_0 = KeccakHash::<32>::hash_no_pad(&[F::ZERO]); + let hash_0_scalar = C::ScalarField::from_biguint(BigUint::from_bytes_le( + &GenericHashOut::::to_bytes(&hash_0), + )); + let rando = (CurveScalar(hash_0_scalar) * C::GENERATOR_PROJECTIVE).to_affine(); + let zero = self.zero(); + let mut result = self.constant_affine_point(rando.clone()); + for (limb, point) in bits.into_iter().zip(doubled_base) { + let mul_point = (0..16) + .scan(AffinePoint::ZERO, |acc, _| { + let tmp = acc.clone(); + *acc = (point + *acc).to_affine(); + Some(tmp) + }) + .map(|p| self.constant_affine_point(p)) + .collect::>(); + let is_zero = self.is_equal(limb, zero); + let should_add = self.not(is_zero); + let r = self.random_access_curve_points(limb, mul_point); + result = self.curve_conditional_add(&result, &r, should_add); + } + + let to_add = self.constant_affine_point(-rando); + self.curve_add(&result, &to_add) + } } #[cfg(test)] mod tests { + use std::str::FromStr; use anyhow::Result; + use num::BigUint; + use plonky2_field::field_types::PrimeField; + use plonky2_field::secp256k1_base::Secp256K1Base; use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - use crate::curve::curve_types::{Curve, CurveScalar}; + use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; use crate::curve::secp256k1::Secp256K1; use crate::field::field_types::Field; - use crate::iop::witness::PartialWitness; + use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; @@ -168,4 +277,38 @@ mod tests { verify(proof, &data.verifier_only, &data.common) } + + #[test] + fn test_fixed_base() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_ecc_config(); + + let mut pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let g = Secp256K1::GENERATOR_AFFINE; + let n = Secp256K1Scalar::from_canonical_usize(10); + let n = Secp256K1Scalar::rand(); + + let res = (CurveScalar(n) * g.to_projective()).to_affine(); + let res_expected = builder.constant_affine_point(res); + builder.curve_assert_valid(&res_expected); + + let n_target = builder.add_virtual_nonnative_target::(); + pw.set_biguint_target(&n_target.value, &n.to_canonical_biguint()); + + let res_target = builder.fixed_base_curve_mul(&g, &n_target); + builder.curve_assert_valid(&res_target); + + builder.connect_affine_point(&res_target, &res_expected); + + dbg!(builder.num_gates()); + let data = builder.build::(); + let proof = data.prove(pw).unwrap(); + + verify(proof, &data.verifier_only, &data.common) + } } diff --git a/plonky2/src/gadgets/curve_windowed_mul.rs b/plonky2/src/gadgets/curve_windowed_mul.rs index 879e1ade..46c663a0 100644 --- a/plonky2/src/gadgets/curve_windowed_mul.rs +++ b/plonky2/src/gadgets/curve_windowed_mul.rs @@ -44,12 +44,21 @@ impl, const D: usize> CircuitBuilder { access_index: Target, v: Vec>, ) -> AffinePointTarget { - let num_limbs = v[0].x.value.num_limbs(); + let num_limbs = C::BaseField::BITS / 32; + let zero = self.zero_u32(); let x_limbs: Vec> = (0..num_limbs) - .map(|i| v.iter().map(|p| p.x.value.limbs[i].0).collect()) + .map(|i| { + v.iter() + .map(|p| p.x.value.limbs.get(i).unwrap_or(&zero).0) + .collect() + }) .collect(); let y_limbs: Vec> = (0..num_limbs) - .map(|i| v.iter().map(|p| p.y.value.limbs[i].0).collect()) + .map(|i| { + v.iter() + .map(|p| p.y.value.limbs.get(i).unwrap_or(&zero).0) + .collect() + }) .collect(); let selected_x_limbs: Vec<_> = x_limbs diff --git a/plonky2/src/gadgets/glv.rs b/plonky2/src/gadgets/glv.rs index 89013dd1..b9a3a380 100644 --- a/plonky2/src/gadgets/glv.rs +++ b/plonky2/src/gadgets/glv.rs @@ -19,6 +19,7 @@ impl, const D: usize> CircuitBuilder { self.constant_nonnative(BETA) } + // TODO: Add decomposition check. pub fn decompose_secp256k1_scalar( &mut self, k: &NonNativeTarget, @@ -59,12 +60,24 @@ impl, const D: usize> CircuitBuilder { y: p.y.clone(), }; - let part1 = self.curve_scalar_mul_windowed(p, &k1); - let part1_neg = self.curve_conditional_neg(&part1, k1_neg); - let part2 = self.curve_scalar_mul_windowed(&sp, &k2); - let part2_neg = self.curve_conditional_neg(&part2, k2_neg); - - self.curve_add(&part1_neg, &part2_neg) + // let part1 = self.curve_scalar_mul_windowed(p, &k1); + // let part1_neg = self.curve_conditional_neg(&part1, k1_neg); + // let part2 = self.curve_scalar_mul_windowed(&sp, &k2); + // let part2_neg = self.curve_conditional_neg(&part2, k2_neg); + // + // self.curve_add(&part1_neg, &part2_neg) + // dbg!(k1.value.limbs.len()); + // dbg!(k2.value.limbs.len()); + let p_neg = self.curve_conditional_neg(&p, k1_neg); + let sp_neg = self.curve_conditional_neg(&sp, k2_neg); + // let yo = self.curve_scalar_mul_windowed(&p_neg, &k1); + // let ya = self.curve_scalar_mul_windowed(&sp_neg, &k2); + // dbg!(&yo); + // dbg!(&ya); + // self.connect_affine_point(&part1_neg, &yo); + // self.connect_affine_point(&part2_neg, &ya); + self.curve_msm(&p_neg, &sp_neg, &k1, &k2) + // self.curve_add(&yo, &ya) } } @@ -105,7 +118,7 @@ mod tests { use crate::curve::curve_types::{Curve, CurveScalar}; use crate::curve::glv::glv_mul; use crate::curve::secp256k1::Secp256K1; - use crate::iop::witness::PartialWitness; + use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; @@ -134,6 +147,43 @@ mod tests { let actual = builder.glv_mul(&randot, &scalar_target); builder.connect_affine_point(&expected, &actual); + dbg!(builder.num_gates()); + let data = builder.build::(); + let proof = data.prove(pw).unwrap(); + + verify(proof, &data.verifier_only, &data.common) + } + + #[test] + fn test_wtf() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_ecc_config(); + + let mut pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let rando = + (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); + let randot = builder.constant_affine_point(rando); + + let scalar = Secp256K1Scalar::rand(); + let scalar_target = builder.constant_nonnative(scalar); + + let tr = builder.add_virtual_bool_target(); + pw.set_bool_target(tr, false); + + let randotneg = builder.curve_conditional_neg(&randot, tr); + let y = builder.curve_scalar_mul_windowed(&randotneg, &scalar_target); + + let yy = builder.curve_scalar_mul_windowed(&randot, &scalar_target); + let yy = builder.curve_conditional_neg(&yy, tr); + + builder.connect_affine_point(&y, &yy); + + dbg!(builder.num_gates()); let data = builder.build::(); let proof = data.prove(pw).unwrap(); diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 63f45fec..e0d05c24 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -70,7 +70,7 @@ pub struct CircuitBuilder, const D: usize> { marked_targets: Vec>, /// Generators used to generate the witness. - generators: Vec>>, + pub generators: Vec>>, constants_to_targets: HashMap, targets_to_constants: HashMap,