diff --git a/Cargo.toml b/Cargo.toml index cc070d96..00a4b28f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["field", "insertion", "plonky2", "starky", "system_zero", "util", "waksman"] +members = ["field", "insertion", "plonky2", "starky", "system_zero", "util", "waksman", "ecdsa"] [profile.release] opt-level = 3 diff --git a/ecdsa/Cargo.toml b/ecdsa/Cargo.toml new file mode 100644 index 00000000..a7e1024b --- /dev/null +++ b/ecdsa/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "plonky2_ecdsa" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +plonky2 = { path = "../plonky2" } +plonky2_util = { path = "../util" } +plonky2_field = { path = "../field" } +num = "0.4.0" +itertools = "0.10.0" +rayon = "1.5.1" +serde = { version = "1.0", features = ["derive"] } +anyhow = "1.0.40" +rand = "0.8.4" \ No newline at end of file diff --git a/plonky2/src/curve/curve_adds.rs b/ecdsa/src/curve/curve_adds.rs similarity index 100% rename from plonky2/src/curve/curve_adds.rs rename to ecdsa/src/curve/curve_adds.rs diff --git a/plonky2/src/curve/curve_msm.rs b/ecdsa/src/curve/curve_msm.rs similarity index 100% rename from plonky2/src/curve/curve_msm.rs rename to ecdsa/src/curve/curve_msm.rs diff --git a/plonky2/src/curve/curve_multiplication.rs b/ecdsa/src/curve/curve_multiplication.rs similarity index 99% rename from plonky2/src/curve/curve_multiplication.rs rename to ecdsa/src/curve/curve_multiplication.rs index c6fbbd83..9f2accaf 100644 --- a/plonky2/src/curve/curve_multiplication.rs +++ b/ecdsa/src/curve/curve_multiplication.rs @@ -36,6 +36,7 @@ impl ProjectivePoint { MultiplicationPrecomputation { powers } } + #[must_use] pub fn mul_with_precomputation( &self, scalar: C::ScalarField, diff --git a/plonky2/src/curve/curve_summation.rs b/ecdsa/src/curve/curve_summation.rs similarity index 100% rename from plonky2/src/curve/curve_summation.rs rename to ecdsa/src/curve/curve_summation.rs diff --git a/plonky2/src/curve/curve_types.rs b/ecdsa/src/curve/curve_types.rs similarity index 99% rename from plonky2/src/curve/curve_types.rs rename to ecdsa/src/curve/curve_types.rs index 264120c7..be025e12 100644 --- a/plonky2/src/curve/curve_types.rs +++ b/ecdsa/src/curve/curve_types.rs @@ -78,6 +78,7 @@ impl AffinePoint { affine_points.iter().map(Self::to_projective).collect() } + #[must_use] pub fn double(&self) -> Self { let AffinePoint { x: x1, y: y1, zero } = *self; @@ -187,6 +188,7 @@ impl ProjectivePoint { } // From https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/doubling/dbl-2007-bl + #[must_use] pub fn double(&self) -> Self { let Self { x, y, z } = *self; if z == C::BaseField::ZERO { @@ -222,6 +224,7 @@ impl ProjectivePoint { .collect() } + #[must_use] pub fn neg(&self) -> Self { Self { x: self.x, diff --git a/plonky2/src/curve/ecdsa.rs b/ecdsa/src/curve/ecdsa.rs similarity index 94% rename from plonky2/src/curve/ecdsa.rs rename to ecdsa/src/curve/ecdsa.rs index cabe038a..91b2cea9 100644 --- a/plonky2/src/curve/ecdsa.rs +++ b/ecdsa/src/curve/ecdsa.rs @@ -1,8 +1,8 @@ +use plonky2_field::field_types::Field; use serde::{Deserialize, Serialize}; use crate::curve::curve_msm::msm_parallel; use crate::curve::curve_types::{base_to_scalar, AffinePoint, Curve, CurveScalar}; -use crate::field::field_types::Field; #[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct ECDSASignature { @@ -57,11 +57,12 @@ pub fn verify_message( #[cfg(test)] mod tests { + use plonky2_field::field_types::Field; + use plonky2_field::secp256k1_scalar::Secp256K1Scalar; + use crate::curve::curve_types::{Curve, CurveScalar}; use crate::curve::ecdsa::{sign_message, verify_message, ECDSAPublicKey, ECDSASecretKey}; use crate::curve::secp256k1::Secp256K1; - use crate::field::field_types::Field; - use crate::field::secp256k1_scalar::Secp256K1Scalar; #[test] fn test_ecdsa_native() { diff --git a/plonky2/src/curve/glv.rs b/ecdsa/src/curve/glv.rs similarity index 100% rename from plonky2/src/curve/glv.rs rename to ecdsa/src/curve/glv.rs diff --git a/plonky2/src/curve/mod.rs b/ecdsa/src/curve/mod.rs similarity index 100% rename from plonky2/src/curve/mod.rs rename to ecdsa/src/curve/mod.rs diff --git a/plonky2/src/curve/secp256k1.rs b/ecdsa/src/curve/secp256k1.rs similarity index 100% rename from plonky2/src/curve/secp256k1.rs rename to ecdsa/src/curve/secp256k1.rs diff --git a/plonky2/src/gadgets/biguint.rs b/ecdsa/src/gadgets/biguint.rs similarity index 69% rename from plonky2/src/gadgets/biguint.rs rename to ecdsa/src/gadgets/biguint.rs index c9ad7280..0c08814c 100644 --- a/plonky2/src/gadgets/biguint.rs +++ b/ecdsa/src/gadgets/biguint.rs @@ -1,14 +1,14 @@ use std::marker::PhantomData; use num::{BigUint, Integer, Zero}; +use plonky2::gadgets::arithmetic_u32::U32Target; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; +use plonky2::iop::target::{BoolTarget, Target}; +use plonky2::iop::witness::{PartitionWitness, Witness}; +use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::extension_field::Extendable; - -use crate::gadgets::arithmetic_u32::U32Target; -use crate::hash::hash_types::RichField; -use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::{BoolTarget, Target}; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; +use plonky2_field::field_types::PrimeField; #[derive(Clone, Debug)] pub struct BigUintTarget { @@ -25,19 +25,67 @@ impl BigUintTarget { } } -impl, const D: usize> CircuitBuilder { - pub fn constant_biguint(&mut self, value: &BigUint) -> BigUintTarget { +pub trait CircuitBuilderBiguint, const D: usize> { + fn constant_biguint(&mut self, value: &BigUint) -> BigUintTarget; + + fn zero_biguint(&mut self) -> BigUintTarget; + + fn connect_biguint(&mut self, lhs: &BigUintTarget, rhs: &BigUintTarget); + + fn pad_biguints( + &mut self, + a: &BigUintTarget, + b: &BigUintTarget, + ) -> (BigUintTarget, BigUintTarget); + + fn cmp_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BoolTarget; + + fn add_virtual_biguint_target(&mut self, num_limbs: usize) -> BigUintTarget; + + /// Add two `BigUintTarget`s. + fn add_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget; + + /// Subtract two `BigUintTarget`s. We assume that the first is larger than the second. + fn sub_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget; + + fn mul_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget; + + fn mul_biguint_by_bool(&mut self, a: &BigUintTarget, b: BoolTarget) -> BigUintTarget; + + /// Returns x * y + z. This is no more efficient than mul-then-add; it's purely for convenience (only need to call one CircuitBuilder function). + fn mul_add_biguint( + &mut self, + x: &BigUintTarget, + y: &BigUintTarget, + z: &BigUintTarget, + ) -> BigUintTarget; + + fn div_rem_biguint( + &mut self, + a: &BigUintTarget, + b: &BigUintTarget, + ) -> (BigUintTarget, BigUintTarget); + + fn div_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget; + + fn rem_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget; +} + +impl, const D: usize> CircuitBuilderBiguint + for CircuitBuilder +{ + fn constant_biguint(&mut self, value: &BigUint) -> BigUintTarget { let limb_values = value.to_u32_digits(); let limbs = limb_values.iter().map(|&l| self.constant_u32(l)).collect(); BigUintTarget { limbs } } - pub fn zero_biguint(&mut self) -> BigUintTarget { + fn zero_biguint(&mut self) -> BigUintTarget { self.constant_biguint(&BigUint::zero()) } - pub fn connect_biguint(&mut self, lhs: &BigUintTarget, rhs: &BigUintTarget) { + fn connect_biguint(&mut self, lhs: &BigUintTarget, rhs: &BigUintTarget) { let min_limbs = lhs.num_limbs().min(rhs.num_limbs()); for i in 0..min_limbs { self.connect_u32(lhs.get_limb(i), rhs.get_limb(i)); @@ -51,7 +99,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn pad_biguints( + fn pad_biguints( &mut self, a: &BigUintTarget, b: &BigUintTarget, @@ -73,20 +121,19 @@ impl, const D: usize> CircuitBuilder { } } - pub fn cmp_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BoolTarget { + fn cmp_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BoolTarget { let (a, b) = self.pad_biguints(a, b); self.list_le_u32(a.limbs, b.limbs) } - pub fn add_virtual_biguint_target(&mut self, num_limbs: usize) -> BigUintTarget { + fn add_virtual_biguint_target(&mut self, num_limbs: usize) -> BigUintTarget { let limbs = self.add_virtual_u32_targets(num_limbs); BigUintTarget { limbs } } - // Add two `BigUintTarget`s. - pub fn add_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { + fn add_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { let num_limbs = a.num_limbs().max(b.num_limbs()); let mut combined_limbs = vec![]; @@ -110,8 +157,7 @@ impl, const D: usize> CircuitBuilder { } } - // Subtract two `BigUintTarget`s. We assume that the first is larger than the second. - pub fn sub_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { + fn sub_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { let (a, b) = self.pad_biguints(a, b); let num_limbs = a.limbs.len(); @@ -130,7 +176,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn mul_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { + fn mul_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { let total_limbs = a.limbs.len() + b.limbs.len(); let mut to_add = vec![vec![]; total_limbs]; @@ -156,7 +202,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn mul_biguint_by_bool(&mut self, a: &BigUintTarget, b: BoolTarget) -> BigUintTarget { + fn mul_biguint_by_bool(&mut self, a: &BigUintTarget, b: BoolTarget) -> BigUintTarget { let t = b.target; BigUintTarget { @@ -168,8 +214,7 @@ impl, const D: usize> CircuitBuilder { } } - // Returns x * y + z. This is no more efficient than mul-then-add; it's purely for convenience (only need to call one CircuitBuilder function). - pub fn mul_add_biguint( + fn mul_add_biguint( &mut self, x: &BigUintTarget, y: &BigUintTarget, @@ -179,7 +224,7 @@ impl, const D: usize> CircuitBuilder { self.add_biguint(&prod, z) } - pub fn div_rem_biguint( + fn div_rem_biguint( &mut self, a: &BigUintTarget, b: &BigUintTarget, @@ -212,17 +257,56 @@ impl, const D: usize> CircuitBuilder { (div, rem) } - pub fn div_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { + fn div_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { let (div, _rem) = self.div_rem_biguint(a, b); div } - pub fn rem_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { + fn rem_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { let (_div, rem) = self.div_rem_biguint(a, b); rem } } +pub fn witness_get_biguint_target, F: PrimeField>( + witness: &W, + bt: BigUintTarget, +) -> BigUint { + let base = BigUint::from(1usize << 32); + bt.limbs + .into_iter() + .rev() + .fold(BigUint::zero(), |acc, limb| { + acc * &base + witness.get_target(limb.0).to_canonical_biguint() + }) +} + +pub fn witness_set_biguint_target, F: PrimeField>( + witness: &mut W, + target: &BigUintTarget, + value: &BigUint, +) { + let mut limbs = value.to_u32_digits(); + assert!(target.num_limbs() >= limbs.len()); + limbs.resize(target.num_limbs(), 0); + for i in 0..target.num_limbs() { + witness.set_u32_target(target.limbs[i], limbs[i]); + } +} + +pub fn buffer_set_biguint_target( + buffer: &mut GeneratedValues, + target: &BigUintTarget, + value: &BigUint, +) { + let mut limbs = value.to_u32_digits(); + assert!(target.num_limbs() >= limbs.len()); + limbs.resize(target.num_limbs(), 0); + for i in 0..target.num_limbs() { + buffer.set_u32_target(target.get_limb(i), limbs[i]); + } +} + #[derive(Debug)] struct BigUintDivRemGenerator, const D: usize> { a: BigUintTarget, @@ -245,12 +329,12 @@ impl, const D: usize> SimpleGenerator } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_biguint_target(self.a.clone()); - let b = witness.get_biguint_target(self.b.clone()); + let a = witness_get_biguint_target(witness, self.a.clone()); + let b = witness_get_biguint_target(witness, self.b.clone()); let (div, rem) = a.div_rem(&b); - out_buffer.set_biguint_target(self.div.clone(), div); - out_buffer.set_biguint_target(self.rem.clone(), rem); + buffer_set_biguint_target(out_buffer, &self.div, &div); + buffer_set_biguint_target(out_buffer, &self.rem, &rem); } } @@ -258,14 +342,14 @@ impl, const D: usize> SimpleGenerator mod tests { use anyhow::Result; use num::{BigUint, FromPrimitive, Integer}; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::{ + iop::witness::PartialWitness, + plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig}, + }; use rand::Rng; - use crate::iop::witness::Witness; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::{ - iop::witness::PartialWitness, - plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, verifier::verify}, - }; + use crate::gadgets::biguint::{witness_set_biguint_target, CircuitBuilderBiguint}; #[test] fn test_biguint_add() -> Result<()> { @@ -288,13 +372,13 @@ mod tests { let expected_z = builder.add_virtual_biguint_target(expected_z_value.to_u32_digits().len()); builder.connect_biguint(&z, &expected_z); - pw.set_biguint_target(&x, &x_value); - pw.set_biguint_target(&y, &y_value); - pw.set_biguint_target(&expected_z, &expected_z_value); + witness_set_biguint_target(&mut pw, &x, &x_value); + witness_set_biguint_target(&mut pw, &y, &y_value); + witness_set_biguint_target(&mut pw, &expected_z, &expected_z_value); let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -324,7 +408,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -348,13 +432,13 @@ mod tests { let expected_z = builder.add_virtual_biguint_target(expected_z_value.to_u32_digits().len()); builder.connect_biguint(&z, &expected_z); - pw.set_biguint_target(&x, &x_value); - pw.set_biguint_target(&y, &y_value); - pw.set_biguint_target(&expected_z, &expected_z_value); + witness_set_biguint_target(&mut pw, &x, &x_value); + witness_set_biguint_target(&mut pw, &y, &y_value); + witness_set_biguint_target(&mut pw, &expected_z, &expected_z_value); let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -380,7 +464,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -413,6 +497,6 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } } diff --git a/plonky2/src/gadgets/curve.rs b/ecdsa/src/gadgets/curve.rs similarity index 82% rename from plonky2/src/gadgets/curve.rs rename to ecdsa/src/gadgets/curve.rs index e4e66a4e..e511973b 100644 --- a/plonky2/src/gadgets/curve.rs +++ b/ecdsa/src/gadgets/curve.rs @@ -1,11 +1,11 @@ +use plonky2::hash::hash_types::RichField; +use plonky2::iop::target::BoolTarget; +use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::extension_field::Extendable; 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; +use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget}; /// A Target representing an affine point on the curve `C`. We use incomplete arithmetic for efficiency, /// so we assume these points are not zero. @@ -21,11 +21,60 @@ impl AffinePointTarget { } } -impl, const D: usize> CircuitBuilder { - pub fn constant_affine_point( +pub trait CircuitBuilderCurve, const D: usize> { + fn constant_affine_point(&mut self, point: AffinePoint) -> AffinePointTarget; + + fn connect_affine_point( &mut self, - point: AffinePoint, - ) -> AffinePointTarget { + lhs: &AffinePointTarget, + rhs: &AffinePointTarget, + ); + + fn add_virtual_affine_point_target(&mut self) -> AffinePointTarget; + + fn curve_assert_valid(&mut self, p: &AffinePointTarget); + + fn curve_neg(&mut self, p: &AffinePointTarget) -> AffinePointTarget; + + fn curve_conditional_neg( + &mut self, + p: &AffinePointTarget, + b: BoolTarget, + ) -> AffinePointTarget; + + fn curve_double(&mut self, p: &AffinePointTarget) -> AffinePointTarget; + + fn curve_repeated_double( + &mut self, + p: &AffinePointTarget, + n: usize, + ) -> AffinePointTarget; + + /// Add two points, which are assumed to be non-equal. + fn curve_add( + &mut self, + p1: &AffinePointTarget, + p2: &AffinePointTarget, + ) -> AffinePointTarget; + + fn curve_conditional_add( + &mut self, + p1: &AffinePointTarget, + p2: &AffinePointTarget, + b: BoolTarget, + ) -> AffinePointTarget; + + fn curve_scalar_mul( + &mut self, + p: &AffinePointTarget, + n: &NonNativeTarget, + ) -> AffinePointTarget; +} + +impl, const D: usize> CircuitBuilderCurve + for CircuitBuilder +{ + fn constant_affine_point(&mut self, point: AffinePoint) -> AffinePointTarget { debug_assert!(!point.zero); AffinePointTarget { x: self.constant_nonnative(point.x), @@ -33,7 +82,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn connect_affine_point( + fn connect_affine_point( &mut self, lhs: &AffinePointTarget, rhs: &AffinePointTarget, @@ -42,14 +91,14 @@ impl, const D: usize> CircuitBuilder { self.connect_nonnative(&lhs.y, &rhs.y); } - pub fn add_virtual_affine_point_target(&mut self) -> AffinePointTarget { + fn add_virtual_affine_point_target(&mut self) -> AffinePointTarget { let x = self.add_virtual_nonnative_target(); let y = self.add_virtual_nonnative_target(); AffinePointTarget { x, y } } - pub fn curve_assert_valid(&mut self, p: &AffinePointTarget) { + fn curve_assert_valid(&mut self, p: &AffinePointTarget) { let a = self.constant_nonnative(C::A); let b = self.constant_nonnative(C::B); @@ -63,7 +112,7 @@ impl, const D: usize> CircuitBuilder { self.connect_nonnative(&y_squared, &rhs); } - pub fn curve_neg(&mut self, p: &AffinePointTarget) -> AffinePointTarget { + fn curve_neg(&mut self, p: &AffinePointTarget) -> AffinePointTarget { let neg_y = self.neg_nonnative(&p.y); AffinePointTarget { x: p.x.clone(), @@ -71,7 +120,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn curve_conditional_neg( + fn curve_conditional_neg( &mut self, p: &AffinePointTarget, b: BoolTarget, @@ -82,7 +131,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn curve_double(&mut self, p: &AffinePointTarget) -> AffinePointTarget { + fn curve_double(&mut self, p: &AffinePointTarget) -> AffinePointTarget { let AffinePointTarget { x, y } = p; let double_y = self.add_nonnative(y, y); let inv_double_y = self.inv_nonnative(&double_y); @@ -106,7 +155,7 @@ impl, const D: usize> CircuitBuilder { AffinePointTarget { x: x3, y: y3 } } - pub fn curve_repeated_double( + fn curve_repeated_double( &mut self, p: &AffinePointTarget, n: usize, @@ -120,8 +169,7 @@ impl, const D: usize> CircuitBuilder { result } - // Add two points, which are assumed to be non-equal. - pub fn curve_add( + fn curve_add( &mut self, p1: &AffinePointTarget, p2: &AffinePointTarget, @@ -143,7 +191,7 @@ impl, const D: usize> CircuitBuilder { AffinePointTarget { x: x3, y: y3 } } - pub fn curve_conditional_add( + fn curve_conditional_add( &mut self, p1: &AffinePointTarget, p2: &AffinePointTarget, @@ -162,7 +210,7 @@ impl, const D: usize> CircuitBuilder { AffinePointTarget { x, y } } - pub fn curve_scalar_mul( + fn curve_scalar_mul( &mut self, p: &AffinePointTarget, n: &NonNativeTarget, @@ -209,17 +257,18 @@ mod tests { use std::ops::Neg; use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2_field::field_types::Field; use plonky2_field::secp256k1_base::Secp256K1Base; use plonky2_field::secp256k1_scalar::Secp256K1Scalar; use crate::curve::curve_types::{AffinePoint, 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; + use crate::gadgets::curve::CircuitBuilderCurve; + use crate::gadgets::nonnative::CircuitBuilderNonNative; #[test] fn test_curve_point_is_valid() -> Result<()> { @@ -242,7 +291,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -270,7 +319,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common).unwrap(); + data.verify(proof).unwrap() } #[test] @@ -307,7 +356,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -337,7 +386,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -369,7 +418,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -402,7 +451,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -429,6 +478,6 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } } diff --git a/ecdsa/src/gadgets/curve_fixed_base.rs b/ecdsa/src/gadgets/curve_fixed_base.rs new file mode 100644 index 00000000..e64ec134 --- /dev/null +++ b/ecdsa/src/gadgets/curve_fixed_base.rs @@ -0,0 +1,113 @@ +use num::BigUint; +use plonky2::hash::hash_types::RichField; +use plonky2::hash::keccak::KeccakHash; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::config::{GenericHashOut, Hasher}; +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; + +use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; +use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve}; +use crate::gadgets::curve_windowed_mul::CircuitBuilderWindowedMul; +use crate::gadgets::nonnative::NonNativeTarget; +use crate::gadgets::split_nonnative::CircuitBuilderSplit; + +/// Compute windowed fixed-base scalar multiplication, using a 4-bit window. +pub fn fixed_base_curve_mul_circuit, const D: usize>( + builder: &mut CircuitBuilder, + base: AffinePoint, + scalar: &NonNativeTarget, +) -> AffinePointTarget { + // Holds `(16^i) * base` for `i=0..scalar.value.limbs.len() * 8`. + let scaled_base = (0..scalar.value.limbs.len() * 8).scan(base, |acc, _| { + let tmp = *acc; + for _ in 0..4 { + *acc = acc.double(); + } + Some(tmp) + }); + + let limbs = builder.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 = builder.zero(); + let mut result = builder.constant_affine_point(rando); + // `s * P = sum s_i * P_i` with `P_i = (16^i) * P` and `s = sum s_i * (16^i)`. + for (limb, point) in limbs.into_iter().zip(scaled_base) { + // `muls_point[t] = t * P_i` for `t=0..16`. + let muls_point = (0..16) + .scan(AffinePoint::ZERO, |acc, _| { + let tmp = *acc; + *acc = (point + *acc).to_affine(); + Some(tmp) + }) + .map(|p| builder.constant_affine_point(p)) + .collect::>(); + let is_zero = builder.is_equal(limb, zero); + let should_add = builder.not(is_zero); + // `r = s_i * P_i` + let r = builder.random_access_curve_points(limb, muls_point); + result = builder.curve_conditional_add(&result, &r, should_add); + } + + let to_add = builder.constant_affine_point(-rando); + builder.curve_add(&result, &to_add) +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2_field::field_types::Field; + 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::gadgets::biguint::witness_set_biguint_target; + use crate::gadgets::curve::CircuitBuilderCurve; + use crate::gadgets::curve_fixed_base::fixed_base_curve_mul_circuit; + use crate::gadgets::nonnative::CircuitBuilderNonNative; + + #[test] + #[ignore] + 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::(); + witness_set_biguint_target(&mut pw, &n_target.value, &n.to_canonical_biguint()); + + let res_target = fixed_base_curve_mul_circuit(&mut builder, 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(); + + data.verify(proof) + } +} diff --git a/ecdsa/src/gadgets/curve_msm.rs b/ecdsa/src/gadgets/curve_msm.rs new file mode 100644 index 00000000..c57cecd2 --- /dev/null +++ b/ecdsa/src/gadgets/curve_msm.rs @@ -0,0 +1,136 @@ +use num::BigUint; +use plonky2::hash::hash_types::RichField; +use plonky2::hash::keccak::KeccakHash; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::config::{GenericHashOut, Hasher}; +use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::Field; + +use crate::curve::curve_types::{Curve, CurveScalar}; +use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve}; +use crate::gadgets::curve_windowed_mul::CircuitBuilderWindowedMul; +use crate::gadgets::nonnative::NonNativeTarget; +use crate::gadgets::split_nonnative::CircuitBuilderSplit; + +/// Computes `n*p + m*q` using windowed MSM, with a 2-bit window. +/// See Algorithm 9.23 in Handbook of Elliptic and Hyperelliptic Curve Cryptography for a +/// description. +/// Note: Doesn't work if `p == q`. +pub fn curve_msm_circuit, const D: usize>( + builder: &mut CircuitBuilder, + p: &AffinePointTarget, + q: &AffinePointTarget, + n: &NonNativeTarget, + m: &NonNativeTarget, +) -> AffinePointTarget { + let limbs_n = builder.split_nonnative_to_2_bit_limbs(n); + let limbs_m = builder.split_nonnative_to_2_bit_limbs(m); + assert_eq!(limbs_n.len(), limbs_m.len()); + let num_limbs = limbs_n.len(); + + 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 = builder.constant_affine_point(rando); + let neg_rando = builder.constant_affine_point(-rando); + + // Precomputes `precomputation[i + 4*j] = i*p + j*q` for `i,j=0..4`. + let mut precomputation = vec![p.clone(); 16]; + 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 = builder.curve_add(&cur_p, p); + cur_q = builder.curve_add(&cur_q, q); + } + for i in 1..4 { + precomputation[i] = builder.curve_add(&precomputation[i], &neg_rando); + precomputation[4 * i] = builder.curve_add(&precomputation[4 * i], &neg_rando); + } + for i in 1..4 { + for j in 1..4 { + precomputation[i + 4 * j] = + builder.curve_add(&precomputation[i], &precomputation[4 * j]); + } + } + + let four = builder.constant(F::from_canonical_usize(4)); + + let zero = builder.zero(); + let mut result = rando_t; + for (limb_n, limb_m) in limbs_n.into_iter().zip(limbs_m).rev() { + result = builder.curve_repeated_double(&result, 2); + let index = builder.mul_add(four, limb_m, limb_n); + let r = builder.random_access_curve_points(index, precomputation.clone()); + let is_zero = builder.is_equal(index, zero); + let should_add = builder.not(is_zero); + result = builder.curve_conditional_add(&result, &r, should_add); + } + let starting_point_multiplied = (0..2 * num_limbs).fold(rando, |acc, _| acc.double()); + let to_add = builder.constant_affine_point(-starting_point_multiplied); + result = builder.curve_add(&result, &to_add); + + result +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2_field::field_types::Field; + use plonky2_field::secp256k1_scalar::Secp256K1Scalar; + + use crate::curve::curve_types::{Curve, CurveScalar}; + use crate::curve::secp256k1::Secp256K1; + use crate::gadgets::curve::CircuitBuilderCurve; + use crate::gadgets::curve_msm::curve_msm_circuit; + use crate::gadgets::nonnative::CircuitBuilderNonNative; + + #[test] + #[ignore] + fn test_curve_msm() -> 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 p = + (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); + let q = + (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); + let n = Secp256K1Scalar::rand(); + let m = Secp256K1Scalar::rand(); + + let res = + (CurveScalar(n) * p.to_projective() + CurveScalar(m) * q.to_projective()).to_affine(); + let res_expected = builder.constant_affine_point(res); + builder.curve_assert_valid(&res_expected); + + let p_target = builder.constant_affine_point(p); + let q_target = builder.constant_affine_point(q); + let n_target = builder.constant_nonnative(n); + let m_target = builder.constant_nonnative(m); + + let res_target = + curve_msm_circuit(&mut builder, &p_target, &q_target, &n_target, &m_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(); + + data.verify(proof) + } +} diff --git a/plonky2/src/gadgets/curve_windowed_mul.rs b/ecdsa/src/gadgets/curve_windowed_mul.rs similarity index 78% rename from plonky2/src/gadgets/curve_windowed_mul.rs rename to ecdsa/src/gadgets/curve_windowed_mul.rs index 46c663a0..05c2c58a 100644 --- a/plonky2/src/gadgets/curve_windowed_mul.rs +++ b/ecdsa/src/gadgets/curve_windowed_mul.rs @@ -1,24 +1,53 @@ use std::marker::PhantomData; use num::BigUint; +use plonky2::gadgets::arithmetic_u32::U32Target; +use plonky2::hash::hash_types::RichField; +use plonky2::hash::keccak::KeccakHash; +use plonky2::iop::target::{BoolTarget, Target}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::config::{GenericHashOut, Hasher}; use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::Field; use crate::curve::curve_types::{Curve, CurveScalar}; -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::hash::keccak::KeccakHash; -use crate::iop::target::{BoolTarget, Target}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::config::{GenericHashOut, Hasher}; +use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve}; +use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget}; +use crate::gadgets::split_nonnative::CircuitBuilderSplit; const WINDOW_SIZE: usize = 4; -impl, const D: usize> CircuitBuilder { - pub fn precompute_window( +pub trait CircuitBuilderWindowedMul, const D: usize> { + fn precompute_window( + &mut self, + p: &AffinePointTarget, + ) -> Vec>; + + fn random_access_curve_points( + &mut self, + access_index: Target, + v: Vec>, + ) -> AffinePointTarget; + + fn if_affine_point( + &mut self, + b: BoolTarget, + p1: &AffinePointTarget, + p2: &AffinePointTarget, + ) -> AffinePointTarget; + + fn curve_scalar_mul_windowed( + &mut self, + p: &AffinePointTarget, + n: &NonNativeTarget, + ) -> AffinePointTarget; +} + +impl, const D: usize> CircuitBuilderWindowedMul + for CircuitBuilder +{ + fn precompute_window( &mut self, p: &AffinePointTarget, ) -> Vec> { @@ -39,7 +68,7 @@ impl, const D: usize> CircuitBuilder { multiples } - pub fn random_access_curve_points( + fn random_access_curve_points( &mut self, access_index: Target, v: Vec>, @@ -85,7 +114,7 @@ impl, const D: usize> CircuitBuilder { AffinePointTarget { x, y } } - pub fn if_affine_point( + fn if_affine_point( &mut self, b: BoolTarget, p1: &AffinePointTarget, @@ -96,7 +125,7 @@ impl, const D: usize> CircuitBuilder { AffinePointTarget { x: new_x, y: new_y } } - pub fn curve_scalar_mul_windowed( + fn curve_scalar_mul_windowed( &mut self, p: &AffinePointTarget, n: &NonNativeTarget, @@ -143,17 +172,19 @@ mod tests { use std::ops::Neg; use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; 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; + use crate::gadgets::curve::CircuitBuilderCurve; + use crate::gadgets::curve_windowed_mul::CircuitBuilderWindowedMul; + use crate::gadgets::nonnative::CircuitBuilderNonNative; #[test] fn test_random_access_curve_points() -> Result<()> { @@ -186,10 +217,11 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] + #[ignore] fn test_curve_windowed_mul() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; @@ -219,6 +251,6 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } } diff --git a/plonky2/src/gadgets/ecdsa.rs b/ecdsa/src/gadgets/ecdsa.rs similarity index 53% rename from plonky2/src/gadgets/ecdsa.rs rename to ecdsa/src/gadgets/ecdsa.rs index a376e56a..afd79c61 100644 --- a/plonky2/src/gadgets/ecdsa.rs +++ b/ecdsa/src/gadgets/ecdsa.rs @@ -1,14 +1,16 @@ use std::marker::PhantomData; +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2_field::extension_field::Extendable; use plonky2_field::secp256k1_scalar::Secp256K1Scalar; use crate::curve::curve_types::Curve; use crate::curve::secp256k1::Secp256K1; -use crate::field::extension_field::Extendable; -use crate::gadgets::curve::AffinePointTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::plonk::circuit_builder::CircuitBuilder; +use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve}; +use crate::gadgets::curve_fixed_base::fixed_base_curve_mul_circuit; +use crate::gadgets::glv::CircuitBuilderGlv; +use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget}; #[derive(Clone, Debug)] pub struct ECDSASecretKeyTarget(NonNativeTarget); @@ -22,48 +24,48 @@ pub struct ECDSASignatureTarget { pub s: NonNativeTarget, } -impl, const D: usize> CircuitBuilder { - pub fn verify_message( - &mut self, - msg: NonNativeTarget, - sig: ECDSASignatureTarget, - pk: ECDSAPublicKeyTarget, - ) { - let ECDSASignatureTarget { r, s } = sig; +pub fn verify_message_circuit, const D: usize>( + builder: &mut CircuitBuilder, + msg: NonNativeTarget, + sig: ECDSASignatureTarget, + pk: ECDSAPublicKeyTarget, +) { + let ECDSASignatureTarget { r, s } = sig; - self.curve_assert_valid(&pk.0); + builder.curve_assert_valid(&pk.0); - let c = self.inv_nonnative(&s); - let u1 = self.mul_nonnative(&msg, &c); - let u2 = self.mul_nonnative(&r, &c); + let c = builder.inv_nonnative(&s); + let u1 = builder.mul_nonnative(&msg, &c); + let u2 = builder.mul_nonnative(&r, &c); - let point1 = self.fixed_base_curve_mul(Secp256K1::GENERATOR_AFFINE, &u1); - let point2 = self.glv_mul(&pk.0, &u2); - let point = self.curve_add(&point1, &point2); + let point1 = fixed_base_curve_mul_circuit(builder, Secp256K1::GENERATOR_AFFINE, &u1); + let point2 = builder.glv_mul(&pk.0, &u2); + let point = builder.curve_add(&point1, &point2); - let x = NonNativeTarget:: { - value: point.x.value, - _phantom: PhantomData, - }; - self.connect_nonnative(&r, &x); - } + let x = NonNativeTarget:: { + value: point.x.value, + _phantom: PhantomData, + }; + builder.connect_nonnative(&r, &x); } #[cfg(test)] mod tests { use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2_field::field_types::Field; + use plonky2_field::secp256k1_scalar::Secp256K1Scalar; + use super::{ECDSAPublicKeyTarget, ECDSASignatureTarget}; use crate::curve::curve_types::{Curve, CurveScalar}; use crate::curve::ecdsa::{sign_message, ECDSAPublicKey, ECDSASecretKey, ECDSASignature}; use crate::curve::secp256k1::Secp256K1; - use crate::field::field_types::Field; - use crate::field::secp256k1_scalar::Secp256K1Scalar; - use crate::gadgets::ecdsa::{ECDSAPublicKeyTarget, ECDSASignatureTarget}; - 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; + use crate::gadgets::curve::CircuitBuilderCurve; + use crate::gadgets::ecdsa::verify_message_circuit; + use crate::gadgets::nonnative::CircuitBuilderNonNative; fn test_ecdsa_circuit_with_config(config: CircuitConfig) -> Result<()> { const D: usize = 2; @@ -93,12 +95,12 @@ mod tests { s: s_target, }; - builder.verify_message(msg_target, sig_target, pk_target); + verify_message_circuit(&mut builder, msg_target, sig_target, pk_target); dbg!(builder.num_gates()); let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] diff --git a/plonky2/src/gadgets/glv.rs b/ecdsa/src/gadgets/glv.rs similarity index 66% rename from plonky2/src/gadgets/glv.rs rename to ecdsa/src/gadgets/glv.rs index 8a0179ec..c567e5ab 100644 --- a/plonky2/src/gadgets/glv.rs +++ b/ecdsa/src/gadgets/glv.rs @@ -1,25 +1,50 @@ use std::marker::PhantomData; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; +use plonky2::iop::target::{BoolTarget, Target}; +use plonky2::iop::witness::PartitionWitness; +use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::extension_field::Extendable; +use plonky2_field::field_types::{Field, PrimeField}; use plonky2_field::secp256k1_base::Secp256K1Base; use plonky2_field::secp256k1_scalar::Secp256K1Scalar; use crate::curve::glv::{decompose_secp256k1_scalar, GLV_BETA, GLV_S}; use crate::curve::secp256k1::Secp256K1; -use crate::gadgets::curve::AffinePointTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::{BoolTarget, Target}; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; +use crate::gadgets::biguint::{buffer_set_biguint_target, witness_get_biguint_target}; +use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve}; +use crate::gadgets::curve_msm::curve_msm_circuit; +use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget}; -impl, const D: usize> CircuitBuilder { - pub fn secp256k1_glv_beta(&mut self) -> NonNativeTarget { +pub trait CircuitBuilderGlv, const D: usize> { + fn secp256k1_glv_beta(&mut self) -> NonNativeTarget; + + fn decompose_secp256k1_scalar( + &mut self, + k: &NonNativeTarget, + ) -> ( + NonNativeTarget, + NonNativeTarget, + BoolTarget, + BoolTarget, + ); + + fn glv_mul( + &mut self, + p: &AffinePointTarget, + k: &NonNativeTarget, + ) -> AffinePointTarget; +} + +impl, const D: usize> CircuitBuilderGlv + for CircuitBuilder +{ + fn secp256k1_glv_beta(&mut self) -> NonNativeTarget { self.constant_nonnative(GLV_BETA) } - pub fn decompose_secp256k1_scalar( + fn decompose_secp256k1_scalar( &mut self, k: &NonNativeTarget, ) -> ( @@ -53,7 +78,7 @@ impl, const D: usize> CircuitBuilder { (k1, k2, k1_neg, k2_neg) } - pub fn glv_mul( + fn glv_mul( &mut self, p: &AffinePointTarget, k: &NonNativeTarget, @@ -69,7 +94,7 @@ impl, const D: usize> CircuitBuilder { let p_neg = self.curve_conditional_neg(p, k1_neg); let sp_neg = self.curve_conditional_neg(&sp, k2_neg); - self.curve_msm(&p_neg, &sp_neg, &k1, &k2) + curve_msm_circuit(self, &p_neg, &sp_neg, &k1, &k2) } } @@ -91,11 +116,15 @@ impl, const D: usize> SimpleGenerator } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let k = witness.get_nonnative_target(self.k.clone()); + let k = Secp256K1Scalar::from_biguint(witness_get_biguint_target( + witness, + self.k.value.clone(), + )); + let (k1, k2, k1_neg, k2_neg) = decompose_secp256k1_scalar(k); - out_buffer.set_nonnative_target(self.k1.clone(), k1); - out_buffer.set_nonnative_target(self.k2.clone(), k2); + buffer_set_biguint_target(out_buffer, &self.k1.value, &k1.to_canonical_biguint()); + buffer_set_biguint_target(out_buffer, &self.k2.value, &k2.to_canonical_biguint()); out_buffer.set_bool_target(self.k1_neg, k1_neg); out_buffer.set_bool_target(self.k2_neg, k2_neg); } @@ -104,19 +133,22 @@ impl, const D: usize> SimpleGenerator #[cfg(test)] mod tests { use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2_field::field_types::Field; use plonky2_field::secp256k1_scalar::Secp256K1Scalar; 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::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; + use crate::gadgets::curve::CircuitBuilderCurve; + use crate::gadgets::glv::CircuitBuilderGlv; + use crate::gadgets::nonnative::CircuitBuilderNonNative; #[test] + #[ignore] fn test_glv_gadget() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; @@ -143,6 +175,6 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } } diff --git a/ecdsa/src/gadgets/mod.rs b/ecdsa/src/gadgets/mod.rs new file mode 100644 index 00000000..35b10100 --- /dev/null +++ b/ecdsa/src/gadgets/mod.rs @@ -0,0 +1,9 @@ +pub mod biguint; +pub mod curve; +pub mod curve_fixed_base; +pub mod curve_msm; +pub mod curve_windowed_mul; +pub mod ecdsa; +pub mod glv; +pub mod nonnative; +pub mod split_nonnative; diff --git a/plonky2/src/gadgets/nonnative.rs b/ecdsa/src/gadgets/nonnative.rs similarity index 76% rename from plonky2/src/gadgets/nonnative.rs rename to ecdsa/src/gadgets/nonnative.rs index 6c483a86..76f23f3f 100644 --- a/plonky2/src/gadgets/nonnative.rs +++ b/ecdsa/src/gadgets/nonnative.rs @@ -1,17 +1,19 @@ use std::marker::PhantomData; use num::{BigUint, Integer, One, Zero}; +use plonky2::gadgets::arithmetic_u32::U32Target; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; +use plonky2::iop::target::{BoolTarget, Target}; +use plonky2::iop::witness::PartitionWitness; +use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::field_types::PrimeField; use plonky2_field::{extension_field::Extendable, field_types::Field}; use plonky2_util::ceil_div_usize; -use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::hash::hash_types::RichField; -use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::{BoolTarget, Target}; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; +use crate::gadgets::biguint::{ + buffer_set_biguint_target, witness_get_biguint_target, BigUintTarget, CircuitBuilderBiguint, +}; #[derive(Clone, Debug)] pub struct NonNativeTarget { @@ -19,36 +21,131 @@ pub struct NonNativeTarget { pub(crate) _phantom: PhantomData, } -impl, const D: usize> CircuitBuilder { +pub trait CircuitBuilderNonNative, const D: usize> { fn num_nonnative_limbs() -> usize { ceil_div_usize(FF::BITS, 32) } - pub fn biguint_to_nonnative(&mut self, x: &BigUintTarget) -> NonNativeTarget { + fn biguint_to_nonnative(&mut self, x: &BigUintTarget) -> NonNativeTarget; + + fn nonnative_to_canonical_biguint( + &mut self, + x: &NonNativeTarget, + ) -> BigUintTarget; + + fn constant_nonnative(&mut self, x: FF) -> NonNativeTarget; + + fn zero_nonnative(&mut self) -> NonNativeTarget; + + // Assert that two NonNativeTarget's, both assumed to be in reduced form, are equal. + fn connect_nonnative( + &mut self, + lhs: &NonNativeTarget, + rhs: &NonNativeTarget, + ); + + fn add_virtual_nonnative_target(&mut self) -> NonNativeTarget; + + fn add_virtual_nonnative_target_sized( + &mut self, + num_limbs: usize, + ) -> NonNativeTarget; + + fn add_nonnative( + &mut self, + a: &NonNativeTarget, + b: &NonNativeTarget, + ) -> NonNativeTarget; + + fn mul_nonnative_by_bool( + &mut self, + a: &NonNativeTarget, + b: BoolTarget, + ) -> NonNativeTarget; + + fn if_nonnative( + &mut self, + b: BoolTarget, + x: &NonNativeTarget, + y: &NonNativeTarget, + ) -> NonNativeTarget; + + fn add_many_nonnative( + &mut self, + to_add: &[NonNativeTarget], + ) -> NonNativeTarget; + + // Subtract two `NonNativeTarget`s. + fn sub_nonnative( + &mut self, + a: &NonNativeTarget, + b: &NonNativeTarget, + ) -> NonNativeTarget; + + fn mul_nonnative( + &mut self, + a: &NonNativeTarget, + b: &NonNativeTarget, + ) -> NonNativeTarget; + + fn mul_many_nonnative( + &mut self, + to_mul: &[NonNativeTarget], + ) -> NonNativeTarget; + + fn neg_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget; + + fn inv_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget; + + /// Returns `x % |FF|` as a `NonNativeTarget`. + fn reduce(&mut self, x: &BigUintTarget) -> NonNativeTarget; + + fn reduce_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget; + + fn bool_to_nonnative(&mut self, b: &BoolTarget) -> NonNativeTarget; + + // Split a nonnative field element to bits. + fn split_nonnative_to_bits(&mut self, x: &NonNativeTarget) -> Vec; + + fn nonnative_conditional_neg( + &mut self, + x: &NonNativeTarget, + b: BoolTarget, + ) -> NonNativeTarget; +} + +impl, const D: usize> CircuitBuilderNonNative + for CircuitBuilder +{ + fn num_nonnative_limbs() -> usize { + ceil_div_usize(FF::BITS, 32) + } + + fn biguint_to_nonnative(&mut self, x: &BigUintTarget) -> NonNativeTarget { NonNativeTarget { value: x.clone(), _phantom: PhantomData, } } - pub fn nonnative_to_canonical_biguint( + fn nonnative_to_canonical_biguint( &mut self, x: &NonNativeTarget, ) -> BigUintTarget { x.value.clone() } - pub fn constant_nonnative(&mut self, x: FF) -> NonNativeTarget { + fn constant_nonnative(&mut self, x: FF) -> NonNativeTarget { let x_biguint = self.constant_biguint(&x.to_canonical_biguint()); self.biguint_to_nonnative(&x_biguint) } - pub fn zero_nonnative(&mut self) -> NonNativeTarget { + fn zero_nonnative(&mut self) -> NonNativeTarget { self.constant_nonnative(FF::ZERO) } // Assert that two NonNativeTarget's, both assumed to be in reduced form, are equal. - pub fn connect_nonnative( + fn connect_nonnative( &mut self, lhs: &NonNativeTarget, rhs: &NonNativeTarget, @@ -56,7 +153,7 @@ impl, const D: usize> CircuitBuilder { self.connect_biguint(&lhs.value, &rhs.value); } - pub fn add_virtual_nonnative_target(&mut self) -> NonNativeTarget { + fn add_virtual_nonnative_target(&mut self) -> NonNativeTarget { let num_limbs = Self::num_nonnative_limbs::(); let value = self.add_virtual_biguint_target(num_limbs); @@ -66,7 +163,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn add_virtual_nonnative_target_sized( + fn add_virtual_nonnative_target_sized( &mut self, num_limbs: usize, ) -> NonNativeTarget { @@ -78,7 +175,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn add_nonnative( + fn add_nonnative( &mut self, a: &NonNativeTarget, b: &NonNativeTarget, @@ -110,7 +207,7 @@ impl, const D: usize> CircuitBuilder { sum } - pub fn mul_nonnative_by_bool( + fn mul_nonnative_by_bool( &mut self, a: &NonNativeTarget, b: BoolTarget, @@ -121,7 +218,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn if_nonnative( + fn if_nonnative( &mut self, b: BoolTarget, x: &NonNativeTarget, @@ -133,7 +230,7 @@ impl, const D: usize> CircuitBuilder { self.add_nonnative(&maybe_x, &maybe_y) } - pub fn add_many_nonnative( + fn add_many_nonnative( &mut self, to_add: &[NonNativeTarget], ) -> NonNativeTarget { @@ -177,7 +274,7 @@ impl, const D: usize> CircuitBuilder { } // Subtract two `NonNativeTarget`s. - pub fn sub_nonnative( + fn sub_nonnative( &mut self, a: &NonNativeTarget, b: &NonNativeTarget, @@ -205,7 +302,7 @@ impl, const D: usize> CircuitBuilder { diff } - pub fn mul_nonnative( + fn mul_nonnative( &mut self, a: &NonNativeTarget, b: &NonNativeTarget, @@ -236,7 +333,7 @@ impl, const D: usize> CircuitBuilder { prod } - pub fn mul_many_nonnative( + fn mul_many_nonnative( &mut self, to_mul: &[NonNativeTarget], ) -> NonNativeTarget { @@ -245,26 +342,20 @@ impl, const D: usize> CircuitBuilder { } let mut accumulator = self.mul_nonnative(&to_mul[0], &to_mul[1]); - for i in 2..to_mul.len() { - accumulator = self.mul_nonnative(&accumulator, &to_mul[i]); + for t in to_mul.iter().skip(2) { + accumulator = self.mul_nonnative(&accumulator, t); } accumulator } - pub fn neg_nonnative( - &mut self, - x: &NonNativeTarget, - ) -> NonNativeTarget { + fn neg_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget { let zero_target = self.constant_biguint(&BigUint::zero()); let zero_ff = self.biguint_to_nonnative(&zero_target); self.sub_nonnative(&zero_ff, x) } - pub fn inv_nonnative( - &mut self, - x: &NonNativeTarget, - ) -> NonNativeTarget { + fn inv_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget { let num_limbs = x.value.num_limbs(); let inv_biguint = self.add_virtual_biguint_target(num_limbs); let div = self.add_virtual_biguint_target(num_limbs); @@ -302,12 +393,12 @@ impl, const D: usize> CircuitBuilder { } } - pub fn reduce_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget { + fn reduce_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget { let x_biguint = self.nonnative_to_canonical_biguint(x); self.reduce(&x_biguint) } - pub fn bool_to_nonnative(&mut self, b: &BoolTarget) -> NonNativeTarget { + fn bool_to_nonnative(&mut self, b: &BoolTarget) -> NonNativeTarget { let limbs = vec![U32Target(b.target)]; let value = BigUintTarget { limbs }; @@ -318,10 +409,7 @@ impl, const D: usize> CircuitBuilder { } // Split a nonnative field element to bits. - pub fn split_nonnative_to_bits( - &mut self, - x: &NonNativeTarget, - ) -> Vec { + fn split_nonnative_to_bits(&mut self, x: &NonNativeTarget) -> Vec { let num_limbs = x.value.num_limbs(); let mut result = Vec::with_capacity(num_limbs * 32); @@ -339,7 +427,7 @@ impl, const D: usize> CircuitBuilder { result } - pub fn nonnative_conditional_neg( + fn nonnative_conditional_neg( &mut self, x: &NonNativeTarget, b: BoolTarget, @@ -377,8 +465,8 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_nonnative_target(self.a.clone()); - let b = witness.get_nonnative_target(self.b.clone()); + let a = FF::from_biguint(witness_get_biguint_target(witness, self.a.value.clone())); + let b = FF::from_biguint(witness_get_biguint_target(witness, self.b.value.clone())); let a_biguint = a.to_canonical_biguint(); let b_biguint = b.to_canonical_biguint(); let sum_biguint = a_biguint + b_biguint; @@ -389,7 +477,7 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat (false, sum_biguint) }; - out_buffer.set_biguint_target(self.sum.value.clone(), sum_reduced); + buffer_set_biguint_target(out_buffer, &self.sum.value, &sum_reduced); out_buffer.set_bool_target(self.overflow, overflow); } } @@ -417,7 +505,9 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat let summands: Vec<_> = self .summands .iter() - .map(|summand| witness.get_nonnative_target(summand.clone())) + .map(|summand| { + FF::from_biguint(witness_get_biguint_target(witness, summand.value.clone())) + }) .collect(); let summand_biguints: Vec<_> = summands .iter() @@ -432,7 +522,7 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat let (overflow_biguint, sum_reduced) = sum_biguint.div_rem(&modulus); let overflow = overflow_biguint.to_u64_digits()[0] as u32; - out_buffer.set_biguint_target(self.sum.value.clone(), sum_reduced); + buffer_set_biguint_target(out_buffer, &self.sum.value, &sum_reduced); out_buffer.set_u32_target(self.overflow, overflow); } } @@ -461,8 +551,8 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_nonnative_target(self.a.clone()); - let b = witness.get_nonnative_target(self.b.clone()); + let a = FF::from_biguint(witness_get_biguint_target(witness, self.a.value.clone())); + let b = FF::from_biguint(witness_get_biguint_target(witness, self.b.value.clone())); let a_biguint = a.to_canonical_biguint(); let b_biguint = b.to_canonical_biguint(); @@ -473,7 +563,7 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat (modulus + a_biguint - b_biguint, true) }; - out_buffer.set_biguint_target(self.diff.value.clone(), diff_biguint); + buffer_set_biguint_target(out_buffer, &self.diff.value, &diff_biguint); out_buffer.set_bool_target(self.overflow, overflow); } } @@ -502,8 +592,8 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_nonnative_target(self.a.clone()); - let b = witness.get_nonnative_target(self.b.clone()); + let a = FF::from_biguint(witness_get_biguint_target(witness, self.a.value.clone())); + let b = FF::from_biguint(witness_get_biguint_target(witness, self.b.value.clone())); let a_biguint = a.to_canonical_biguint(); let b_biguint = b.to_canonical_biguint(); @@ -512,8 +602,8 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat let modulus = FF::order(); let (overflow_biguint, prod_reduced) = prod_biguint.div_rem(&modulus); - out_buffer.set_biguint_target(self.prod.value.clone(), prod_reduced); - out_buffer.set_biguint_target(self.overflow.clone(), overflow_biguint); + buffer_set_biguint_target(out_buffer, &self.prod.value, &prod_reduced); + buffer_set_biguint_target(out_buffer, &self.overflow, &overflow_biguint); } } @@ -533,7 +623,7 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let x = witness.get_nonnative_target(self.x.clone()); + let x = FF::from_biguint(witness_get_biguint_target(witness, self.x.value.clone())); let inv = x.inverse(); let x_biguint = x.to_canonical_biguint(); @@ -542,22 +632,22 @@ impl, const D: usize, FF: PrimeField> SimpleGenerat let modulus = FF::order(); let (div, _rem) = prod.div_rem(&modulus); - out_buffer.set_biguint_target(self.div.clone(), div); - out_buffer.set_biguint_target(self.inv.clone(), inv_biguint); + buffer_set_biguint_target(out_buffer, &self.div, &div); + buffer_set_biguint_target(out_buffer, &self.inv, &inv_biguint); } } #[cfg(test)] mod tests { use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2_field::field_types::{Field, PrimeField}; use plonky2_field::secp256k1_base::Secp256K1Base; - 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; + use crate::gadgets::nonnative::CircuitBuilderNonNative; #[test] fn test_nonnative_add() -> Result<()> { @@ -583,7 +673,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -623,7 +713,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -653,7 +743,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -679,7 +769,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -703,7 +793,7 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } #[test] @@ -727,6 +817,6 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } } diff --git a/plonky2/src/gadgets/split_nonnative.rs b/ecdsa/src/gadgets/split_nonnative.rs similarity index 65% rename from plonky2/src/gadgets/split_nonnative.rs rename to ecdsa/src/gadgets/split_nonnative.rs index 18fc0264..e79438f8 100644 --- a/plonky2/src/gadgets/split_nonnative.rs +++ b/ecdsa/src/gadgets/split_nonnative.rs @@ -1,18 +1,40 @@ use std::marker::PhantomData; use itertools::Itertools; +use plonky2::gadgets::arithmetic_u32::U32Target; +use plonky2::hash::hash_types::RichField; +use plonky2::iop::target::Target; +use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2_field::extension_field::Extendable; use plonky2_field::field_types::Field; -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; -impl, const D: usize> CircuitBuilder { - pub fn split_u32_to_4_bit_limbs(&mut self, val: U32Target) -> Vec { +pub trait CircuitBuilderSplit, const D: usize> { + fn split_u32_to_4_bit_limbs(&mut self, val: U32Target) -> Vec; + + fn split_nonnative_to_4_bit_limbs( + &mut self, + val: &NonNativeTarget, + ) -> Vec; + + fn split_nonnative_to_2_bit_limbs( + &mut self, + val: &NonNativeTarget, + ) -> Vec; + + // Note: assumes its inputs are 4-bit limbs, and does not range-check. + fn recombine_nonnative_4_bit_limbs( + &mut self, + limbs: Vec, + ) -> NonNativeTarget; +} + +impl, const D: usize> CircuitBuilderSplit + for CircuitBuilder +{ + fn split_u32_to_4_bit_limbs(&mut self, val: U32Target) -> Vec { let two_bit_limbs = self.split_le_base::<4>(val.0, 16); let four = self.constant(F::from_canonical_usize(4)); let combined_limbs = two_bit_limbs @@ -24,7 +46,7 @@ impl, const D: usize> CircuitBuilder { combined_limbs } - pub fn split_nonnative_to_4_bit_limbs( + fn split_nonnative_to_4_bit_limbs( &mut self, val: &NonNativeTarget, ) -> Vec { @@ -35,7 +57,7 @@ impl, const D: usize> CircuitBuilder { .collect() } - pub fn split_nonnative_to_2_bit_limbs( + fn split_nonnative_to_2_bit_limbs( &mut self, val: &NonNativeTarget, ) -> Vec { @@ -47,7 +69,7 @@ impl, const D: usize> CircuitBuilder { } // Note: assumes its inputs are 4-bit limbs, and does not range-check. - pub fn recombine_nonnative_4_bit_limbs( + fn recombine_nonnative_4_bit_limbs( &mut self, limbs: Vec, ) -> NonNativeTarget { @@ -74,15 +96,15 @@ impl, const D: usize> CircuitBuilder { #[cfg(test)] mod tests { use anyhow::Result; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2_field::field_types::Field; use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - use crate::gadgets::nonnative::NonNativeTarget; - 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; + use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget}; + use crate::gadgets::split_nonnative::CircuitBuilderSplit; #[test] fn test_split_nonnative() -> Result<()> { @@ -104,6 +126,6 @@ mod tests { let data = builder.build::(); let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) + data.verify(proof) } } diff --git a/ecdsa/src/lib.rs b/ecdsa/src/lib.rs new file mode 100644 index 00000000..1de32647 --- /dev/null +++ b/ecdsa/src/lib.rs @@ -0,0 +1,4 @@ +#![allow(clippy::needless_range_loop)] + +pub mod curve; +pub mod gadgets; diff --git a/plonky2/src/gadgets/curve_fixed_base.rs b/plonky2/src/gadgets/curve_fixed_base.rs deleted file mode 100644 index f28e45d1..00000000 --- a/plonky2/src/gadgets/curve_fixed_base.rs +++ /dev/null @@ -1,110 +0,0 @@ -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 { - /// Compute windowed fixed-base scalar multiplication, using a 4-bit window. - pub fn fixed_base_curve_mul( - &mut self, - base: AffinePoint, - scalar: &NonNativeTarget, - ) -> AffinePointTarget { - // Holds `(16^i) * base` for `i=0..scalar.value.limbs.len() * 8`. - let scaled_base = (0..scalar.value.limbs.len() * 8).scan(base, |acc, _| { - let tmp = *acc; - for _ in 0..4 { - *acc = acc.double(); - } - Some(tmp) - }); - - let limbs = 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); - // `s * P = sum s_i * P_i` with `P_i = (16^i) * P` and `s = sum s_i * (16^i)`. - for (limb, point) in limbs.into_iter().zip(scaled_base) { - // `muls_point[t] = t * P_i` for `t=0..16`. - let muls_point = (0..16) - .scan(AffinePoint::ZERO, |acc, _| { - let tmp = *acc; - *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); - // `r = s_i * P_i` - let r = self.random_access_curve_points(limb, muls_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] - #[ignore] - 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 deleted file mode 100644 index fba7c229..00000000 --- a/plonky2/src/gadgets/curve_msm.rs +++ /dev/null @@ -1,133 +0,0 @@ -use num::BigUint; -use plonky2_field::extension_field::Extendable; - -use crate::curve::curve_types::{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 { - /// Computes `n*p + m*q` using windowed MSM, with a 2-bit window. - /// See Algorithm 9.23 in Handbook of Elliptic and Hyperelliptic Curve Cryptography for a - /// description. - /// Note: Doesn't work if `p == q`. - pub fn curve_msm( - &mut self, - p: &AffinePointTarget, - q: &AffinePointTarget, - n: &NonNativeTarget, - m: &NonNativeTarget, - ) -> AffinePointTarget { - let limbs_n = self.split_nonnative_to_2_bit_limbs(n); - let limbs_m = self.split_nonnative_to_2_bit_limbs(m); - assert_eq!(limbs_n.len(), limbs_m.len()); - let num_limbs = limbs_n.len(); - - 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); - - // Precomputes `precomputation[i + 4*j] = i*p + j*q` for `i,j=0..4`. - let mut precomputation = vec![p.clone(); 16]; - 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..2 * num_limbs).fold(rando, |acc, _| acc.double()); - let to_add = self.constant_affine_point(-starting_point_multiplied); - result = self.curve_add(&result, &to_add); - - result - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - 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; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - #[ignore] - fn test_curve_msm() -> 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 p = - (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let q = - (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let n = Secp256K1Scalar::rand(); - let m = Secp256K1Scalar::rand(); - - let res = - (CurveScalar(n) * p.to_projective() + CurveScalar(m) * q.to_projective()).to_affine(); - let res_expected = builder.constant_affine_point(res); - builder.curve_assert_valid(&res_expected); - - let p_target = builder.constant_affine_point(p); - let q_target = builder.constant_affine_point(q); - let n_target = builder.constant_nonnative(n); - let m_target = builder.constant_nonnative(m); - - let res_target = builder.curve_msm(&p_target, &q_target, &n_target, &m_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 50fc0437..d8613337 100644 --- a/plonky2/src/gadgets/mod.rs +++ b/plonky2/src/gadgets/mod.rs @@ -1,21 +1,12 @@ pub mod arithmetic; pub mod arithmetic_extension; pub mod arithmetic_u32; -pub mod biguint; -pub mod curve; -pub mod curve_fixed_base; -pub mod curve_msm; -pub mod curve_windowed_mul; -pub mod ecdsa; -pub mod glv; pub mod hash; pub mod interpolation; pub mod multiple_comparison; -pub mod nonnative; pub mod polynomial; pub mod random_access; pub mod range_check; pub mod select; pub mod split_base; pub(crate) mod split_join; -pub mod split_nonnative; diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index 1569e889..f36ba3aa 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -1,13 +1,10 @@ use std::fmt::Debug; use std::marker::PhantomData; -use num::BigUint; use plonky2_field::extension_field::{Extendable, FieldExtension}; -use plonky2_field::field_types::{Field, PrimeField}; +use plonky2_field::field_types::Field; use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::gadgets::nonnative::NonNativeTarget; use crate::hash::hash_types::{HashOut, HashOutTarget, RichField}; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::{BoolTarget, Target}; @@ -169,21 +166,6 @@ impl GeneratedValues { self.set_target(target.0, F::from_canonical_u32(value)) } - pub fn set_biguint_target(&mut self, target: BigUintTarget, value: BigUint) { - let mut limbs = value.to_u32_digits(); - - assert!(target.num_limbs() >= limbs.len()); - - limbs.resize(target.num_limbs(), 0); - for i in 0..target.num_limbs() { - self.set_u32_target(target.get_limb(i), limbs[i]); - } - } - - pub fn set_nonnative_target(&mut self, target: NonNativeTarget, value: FF) { - self.set_biguint_target(target.value, value.to_canonical_biguint()) - } - pub fn set_hash_target(&mut self, ht: HashOutTarget, value: HashOut) { ht.elements .iter() diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index a013f811..4a565d02 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -1,16 +1,12 @@ use std::collections::HashMap; -use std::iter::repeat; use itertools::Itertools; -use num::{BigUint, FromPrimitive, Zero}; use plonky2_field::extension_field::{Extendable, FieldExtension}; -use plonky2_field::field_types::{Field, PrimeField}; +use plonky2_field::field_types::Field; use crate::fri::structure::{FriOpenings, FriOpeningsTarget}; use crate::fri::witness_util::set_fri_proof_target; use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::gadgets::nonnative::NonNativeTarget; use crate::hash::hash_types::HashOutTarget; use crate::hash::hash_types::RichField; use crate::hash::hash_types::{HashOut, MerkleCapTarget}; @@ -64,30 +60,6 @@ pub trait Witness { panic!("not a bool") } - fn get_biguint_target(&self, target: BigUintTarget) -> BigUint - where - F: PrimeField, - { - let mut result = BigUint::zero(); - - let limb_base = BigUint::from_u64(1 << 32u64).unwrap(); - for i in (0..target.num_limbs()).rev() { - let limb = target.get_limb(i); - result *= &limb_base; - result += self.get_target(limb.0).to_canonical_biguint(); - } - - result - } - - fn get_nonnative_target(&self, target: NonNativeTarget) -> FF - where - F: PrimeField, - { - let val = self.get_biguint_target(target.value); - FF::from_biguint(val) - } - fn get_hash_target(&self, ht: HashOutTarget) -> HashOut { HashOut { elements: self.get_targets(&ht.elements).try_into().unwrap(), @@ -160,16 +132,6 @@ pub trait Witness { self.set_target(target.0, F::from_canonical_u32(value)) } - fn set_biguint_target(&mut self, target: &BigUintTarget, value: &BigUint) { - for (<, l) in target - .limbs - .iter() - .zip(value.to_u32_digits().into_iter().chain(repeat(0))) - { - self.set_u32_target(lt, l); - } - } - /// Set the targets in a `ProofWithPublicInputsTarget` to their corresponding values in a /// `ProofWithPublicInputs`. fn set_proof_with_pis_target, const D: usize>( diff --git a/plonky2/src/lib.rs b/plonky2/src/lib.rs index e5e77bb9..1502cea9 100644 --- a/plonky2/src/lib.rs +++ b/plonky2/src/lib.rs @@ -12,7 +12,6 @@ pub use plonky2_field as field; -pub mod curve; pub mod fri; pub mod gadgets; pub mod gates;