From 294a738dc9232cf8a5f85023bde0307f7c650fb6 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Fri, 11 Feb 2022 09:01:02 -0800 Subject: [PATCH] moved to new file, and curve random access test --- plonky2/src/gadgets/curve.rs | 120 +-------------- plonky2/src/gadgets/curve_windowed_mul.rs | 175 ++++++++++++++++++++++ plonky2/src/gadgets/mod.rs | 1 + 3 files changed, 177 insertions(+), 119 deletions(-) create mode 100644 plonky2/src/gadgets/curve_windowed_mul.rs diff --git a/plonky2/src/gadgets/curve.rs b/plonky2/src/gadgets/curve.rs index 21981f9b..908ed66e 100644 --- a/plonky2/src/gadgets/curve.rs +++ b/plonky2/src/gadgets/curve.rs @@ -1,18 +1,11 @@ -use std::marker::PhantomData; - use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::Field; use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; -use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; use crate::gadgets::nonnative::NonNativeTarget; use crate::hash::hash_types::RichField; -use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; -const WINDOW_SIZE: usize = 4; - /// A Target representing an affine point on the curve `C`. We use incomplete arithmetic for efficiency, /// so we assume these points are not zero. #[derive(Clone, Debug)] @@ -164,85 +157,6 @@ impl, const D: usize> CircuitBuilder { result } - - // TODO: fix if p is the generator - pub fn precompute_window( - &mut self, - p: &AffinePointTarget, - ) -> Vec> { - let mut multiples = Vec::new(); - multiples.push(self.constant_affine_point(C::GENERATOR_AFFINE)); - let mut cur = p.clone(); - for _pow in 0..WINDOW_SIZE { - for existing in multiples.clone() { - multiples.push(self.curve_add(&cur, &existing)); - } - cur = self.curve_double(&cur); - } - - println!("SIZE OF WINDOW: {}", multiples.len()); - - multiples - } - - pub fn random_access_curve_points( - &mut self, - access_index: Target, - v: Vec>, - ) -> AffinePointTarget { - let num_limbs = v[0].x.value.num_limbs(); - let x_limbs: Vec> = (0..num_limbs) - .map(|i| v.iter().map(|p| p.x.value.limbs[i].0).collect()) - .collect(); - let y_limbs: Vec> = (0..num_limbs) - .map(|i| v.iter().map(|p| p.y.value.limbs[i].0).collect()) - .collect(); - - let selected_x_limbs: Vec<_> = x_limbs - .iter() - .map(|limbs| U32Target(self.random_access(access_index, limbs.clone()))) - .collect(); - let selected_y_limbs: Vec<_> = y_limbs - .iter() - .map(|limbs| U32Target(self.random_access(access_index, limbs.clone()))) - .collect(); - - let x = NonNativeTarget { - value: BigUintTarget { - limbs: selected_x_limbs, - }, - _phantom: PhantomData, - }; - let y = NonNativeTarget { - value: BigUintTarget { - limbs: selected_y_limbs, - }, - _phantom: PhantomData, - }; - AffinePointTarget { x, y } - } - - pub fn curve_scalar_mul_windowed( - &mut self, - p: &AffinePointTarget, - n: &NonNativeTarget, - ) -> AffinePointTarget { - let mut result = self.constant_affine_point(C::GENERATOR_AFFINE); - - let precomputation = self.precompute_window(p); - - let windows = self.split_nonnative_to_4_bit_limbs(n); - let m = C::ScalarField::BITS / WINDOW_SIZE; - for i in (0..m).rev() { - result = self.curve_double(&result); - let window = windows[i]; - - let to_add = self.random_access_curve_points(window, precomputation.clone()); - result = self.curve_add(&result, &to_add); - } - - result - } } #[cfg(test)] @@ -393,7 +307,7 @@ mod tests { let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); - let g = Secp256K1::GENERATOR_AFFINE; + let g = Secp256K1::GENERATOR_PROJECTIVE.to_affine(); let five = Secp256K1Scalar::from_canonical_usize(5); let neg_five = five.neg(); let neg_five_scalar = CurveScalar::(neg_five); @@ -414,38 +328,6 @@ mod tests { verify(proof, &data.verifier_only, &data.common) } - #[test] - fn test_curve_mul_windowed() -> 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 = (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let five = Secp256K1Scalar::from_canonical_usize(5); - let neg_five = five.neg(); - let neg_five_scalar = CurveScalar::(neg_five); - let neg_five_g = (neg_five_scalar * g.to_projective()).to_affine(); - let neg_five_g_expected = builder.constant_affine_point(neg_five_g); - builder.curve_assert_valid(&neg_five_g_expected); - - let g_target = builder.constant_affine_point(g); - let neg_five_target = builder.constant_nonnative(neg_five); - let neg_five_g_actual = builder.curve_scalar_mul_windowed(&g_target, &neg_five_target); - builder.curve_assert_valid(&neg_five_g_actual); - - builder.connect_affine_point(&neg_five_g_expected, &neg_five_g_actual); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } - #[test] #[ignore] fn test_curve_random() -> Result<()> { diff --git a/plonky2/src/gadgets/curve_windowed_mul.rs b/plonky2/src/gadgets/curve_windowed_mul.rs new file mode 100644 index 00000000..77bc6f3f --- /dev/null +++ b/plonky2/src/gadgets/curve_windowed_mul.rs @@ -0,0 +1,175 @@ +use std::marker::PhantomData; + +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; + +use crate::curve::curve_types::Curve; +use crate::gadgets::arithmetic_u32::U32Target; +use crate::gadgets::biguint::BigUintTarget; +use crate::gadgets::curve::AffinePointTarget; +use crate::gadgets::nonnative::NonNativeTarget; +use crate::hash::hash_types::RichField; +use crate::iop::target::Target; +use crate::plonk::circuit_builder::CircuitBuilder; + +const WINDOW_SIZE: usize = 4; + +impl, const D: usize> CircuitBuilder { + // TODO: fix if p is the generator + pub fn precompute_window( + &mut self, + p: &AffinePointTarget, + ) -> Vec> { + let mut multiples = Vec::new(); + multiples.push(self.constant_affine_point(C::GENERATOR_AFFINE)); + let mut cur = p.clone(); + for _pow in 0..WINDOW_SIZE { + for existing in multiples.clone() { + multiples.push(self.curve_add(&cur, &existing)); + } + cur = self.curve_double(&cur); + } + + multiples + } + + pub fn random_access_curve_points( + &mut self, + access_index: Target, + v: Vec>, + ) -> AffinePointTarget { + let num_limbs = v[0].x.value.num_limbs(); + let x_limbs: Vec> = (0..num_limbs) + .map(|i| v.iter().map(|p| p.x.value.limbs[i].0).collect()) + .collect(); + let y_limbs: Vec> = (0..num_limbs) + .map(|i| v.iter().map(|p| p.y.value.limbs[i].0).collect()) + .collect(); + + let selected_x_limbs: Vec<_> = x_limbs + .iter() + .map(|limbs| U32Target(self.random_access(access_index, limbs.clone()))) + .collect(); + let selected_y_limbs: Vec<_> = y_limbs + .iter() + .map(|limbs| U32Target(self.random_access(access_index, limbs.clone()))) + .collect(); + + let x = NonNativeTarget { + value: BigUintTarget { + limbs: selected_x_limbs, + }, + _phantom: PhantomData, + }; + let y = NonNativeTarget { + value: BigUintTarget { + limbs: selected_y_limbs, + }, + _phantom: PhantomData, + }; + AffinePointTarget { x, y } + } + + pub fn curve_scalar_mul_windowed( + &mut self, + p: &AffinePointTarget, + n: &NonNativeTarget, + ) -> AffinePointTarget { + let mut result = self.constant_affine_point(C::GENERATOR_AFFINE); + + let precomputation = self.precompute_window(p); + + let windows = self.split_nonnative_to_4_bit_limbs(n); + let m = C::ScalarField::BITS / WINDOW_SIZE; + for i in (0..m).rev() { + result = self.curve_double(&result); + let window = windows[i]; + + let to_add = self.random_access_curve_points(window, precomputation.clone()); + result = self.curve_add(&result, &to_add); + } + + result + } +} + +#[cfg(test)] +mod tests { + use std::ops::Neg; + + use anyhow::Result; + use plonky2_field::field_types::Field; + use plonky2_field::secp256k1_scalar::Secp256K1Scalar; + use rand::Rng; + + use crate::curve::curve_types::{Curve, CurveScalar}; + use crate::curve::secp256k1::Secp256K1; + use crate::iop::witness::PartialWitness; + 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_random_access_curve_points() -> 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 num_points = 8; + let points: Vec<_> = (0..num_points).map(|_| { + let g = (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); + builder.constant_affine_point(g) + }).collect(); + + let mut rng = rand::thread_rng(); + let mut access_index = rng.gen::() % 8; + + let access_index_target = builder.constant(F::from_canonical_usize(access_index)); + let selected = builder.random_access_curve_points(access_index_target, points.clone()); + let expected = points[access_index].clone(); + builder.connect_affine_point(&selected, &expected); + + let data = builder.build::(); + let proof = data.prove(pw).unwrap(); + + verify(proof, &data.verifier_only, &data.common) + } + + #[test] + fn test_curve_mul_windowed() -> 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 = (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); + let five = Secp256K1Scalar::from_canonical_usize(5); + let neg_five = five.neg(); + let neg_five_scalar = CurveScalar::(neg_five); + let neg_five_g = (neg_five_scalar * g.to_projective()).to_affine(); + let neg_five_g_expected = builder.constant_affine_point(neg_five_g); + builder.curve_assert_valid(&neg_five_g_expected); + + let g_target = builder.constant_affine_point(g); + let neg_five_target = builder.constant_nonnative(neg_five); + let neg_five_g_actual = builder.curve_scalar_mul_windowed(&g_target, &neg_five_target); + builder.curve_assert_valid(&neg_five_g_actual); + + builder.connect_affine_point(&neg_five_g_expected, &neg_five_g_actual); + + 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 95e46b42..d9c93db3 100644 --- a/plonky2/src/gadgets/mod.rs +++ b/plonky2/src/gadgets/mod.rs @@ -3,6 +3,7 @@ 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 ecdsa; pub mod glv;