diff --git a/plonky2/src/gadgets/curve_fixed_base.rs b/plonky2/src/gadgets/curve_fixed_base.rs new file mode 100644 index 00000000..3b826f78 --- /dev/null +++ b/plonky2/src/gadgets/curve_fixed_base.rs @@ -0,0 +1,103 @@ +use num::BigUint; +use plonky2_field::extension_field::Extendable; + +use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; +use crate::field::field_types::Field; +use crate::gadgets::curve::AffinePointTarget; +use crate::gadgets::nonnative::NonNativeTarget; +use crate::hash::hash_types::RichField; +use crate::hash::keccak::KeccakHash; +use crate::plonk::circuit_builder::CircuitBuilder; +use crate::plonk::config::{GenericHashOut, Hasher}; + +impl, const D: usize> CircuitBuilder { + 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 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 anyhow::Result; + use plonky2_field::field_types::PrimeField; + use plonky2_field::secp256k1_scalar::Secp256K1Scalar; + + use crate::curve::curve_types::{Curve, CurveScalar}; + use crate::curve::secp256k1::Secp256K1; + use crate::field::field_types::Field; + use crate::iop::witness::{PartialWitness, Witness}; + use crate::plonk::circuit_builder::CircuitBuilder; + use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::verifier::verify; + + #[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::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_msm.rs b/plonky2/src/gadgets/curve_msm.rs index aa5a8d34..43a22da2 100644 --- a/plonky2/src/gadgets/curve_msm.rs +++ b/plonky2/src/gadgets/curve_msm.rs @@ -1,8 +1,7 @@ -use itertools::Itertools; use num::BigUint; use plonky2_field::extension_field::Extendable; -use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; +use crate::curve::curve_types::{Curve, CurveScalar}; use crate::field::field_types::Field; use crate::gadgets::curve::AffinePointTarget; use crate::gadgets::nonnative::NonNativeTarget; @@ -71,126 +70,18 @@ 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::{AffinePoint, Curve, CurveScalar}; + use crate::curve::curve_types::{Curve, CurveScalar}; use crate::curve::secp256k1::Secp256K1; use crate::field::field_types::Field; - use crate::iop::witness::{PartialWitness, Witness}; + use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; @@ -277,38 +168,4 @@ 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/mod.rs b/plonky2/src/gadgets/mod.rs index e35afeed..50fc0437 100644 --- a/plonky2/src/gadgets/mod.rs +++ b/plonky2/src/gadgets/mod.rs @@ -3,9 +3,9 @@ pub mod arithmetic_extension; pub mod arithmetic_u32; pub mod biguint; pub mod curve; -pub mod curve_windowed_mul; -// pub mod curve_msm; +pub mod curve_fixed_base; pub mod curve_msm; +pub mod curve_windowed_mul; pub mod ecdsa; pub mod glv; pub mod hash;