From a35228af97e388f7106d79a9f1418e7797e61693 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 20 Dec 2023 18:04:30 +0100 Subject: [PATCH] Add code for checking the number of constraints of the 'naive' approach using non-native operations to compute the scalar multiplication. Currently it does not compile due ProjectiveVar used by Pallas implementation being tied to the C::BaseField as the constraint field: https://github.com/arkworks-rs/r1cs-std/tree/b477880a3b9c097b65b1e006d8116f3998cf013c/src/groups/curves/short_weierstrass/mod.rs#L44 (where here we would like to use the C::ScalarField as constraint field). --- Cargo.toml | 1 + src/circuits.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f12ac9a..26b07af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ ark-r1cs-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false } ark-snark = { version = "^0.4.0", default-features = false } ark-groth16 = { version = "^0.4.0" } +ark-pallas = {version="0.4.0", features=["r1cs"]} thiserror = "1.0" [dev-dependencies] diff --git a/src/circuits.rs b/src/circuits.rs index 92202f0..97cec62 100644 --- a/src/circuits.rs +++ b/src/circuits.rs @@ -86,17 +86,32 @@ where } } +// Note: since at the v0.4.0 of ark_curves the bn254 curve does not have the constraints +// implemented, for the following tests we use the pallas curve. #[cfg(test)] pub mod tests { use super::*; - use ark_bn254::{Fr, G1Projective}; use ark_crypto_primitives::sponge::{poseidon::PoseidonSponge, CryptographicSponge}; use ark_ec::Group; - use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar}; + use ark_ff::{BigInteger, PrimeField}; + use ark_r1cs_std::{ + alloc::AllocVar, + boolean::Boolean, + fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar}, + groups::GroupOpsBounds, + prelude::CurveVar, + }; use ark_relations::r1cs::ConstraintSystem; use ark_std::UniformRand; use std::ops::Mul; + // import pallas curve + use ark_pallas::{Fq, Fr, Projective}; + // instead of ark_pallas::constraints::GVar we use a custom non-native version of it: + use ark_pallas::PallasConfig; + use ark_r1cs_std::groups::curves::short_weierstrass::ProjectiveVar; + pub type NonNativePallasGVar = ProjectiveVar>; + use crate::sigmabus::SigmaProof; use crate::transcript::{tests::poseidon_test_config, PoseidonTranscript}; @@ -105,7 +120,7 @@ pub mod tests { let mut rng = ark_std::test_rng(); let poseidon_config = poseidon_test_config::(); - let mut transcript = PoseidonTranscript::::new(&poseidon_config); + let mut transcript = PoseidonTranscript::::new(&poseidon_config); let x = Fr::rand(&mut rng); @@ -119,7 +134,7 @@ pub mod tests { let r = Fr::rand(&mut rng); let o_h = Fr::rand(&mut rng); - let R = G1Projective::generator().mul(r); + let R = Projective::generator().mul(r); let mut sponge = PoseidonSponge::::new(&poseidon_config); sponge.absorb(&vec![r, o_h]); @@ -150,7 +165,7 @@ pub mod tests { CRHParametersVar::::new_witness(cs.clone(), || Ok(poseidon_config)).unwrap(); // GenZK - GenZKCircuit::::check( + GenZKCircuit::::check( &crh_params, cmVar, sVar, @@ -162,6 +177,66 @@ pub mod tests { ) .unwrap(); assert!(cs.is_satisfied().unwrap()); - dbg!("num_constraints={:?}", cs.num_constraints()); + dbg!(cs.num_constraints()); + } + + // This circuit implements the x*G operation that Sigmabus proves, but here we do it in the + // 'naive' way, which is computing it non-natively. + struct NonNativeScalarMulCircuit< + C: CurveGroup, + GC: CurveVar, + FV: FieldVar, + > { + _gc: PhantomData, + _fv: PhantomData, + pub x: C::ScalarField, + pub X: C, + } + impl ConstraintSynthesizer> for NonNativeScalarMulCircuit + where + C: CurveGroup, + GC: CurveVar, + FV: FieldVar, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, + { + fn generate_constraints( + self, + cs: ConstraintSystemRef>, + ) -> Result<(), SynthesisError> { + let G = GC::new_constant(cs.clone(), C::generator())?; + let x_bits = Vec::>>::new_input(cs.clone(), || { + Ok(self.x.into_bigint().to_bits_le()) + })?; + let X = GC::new_input(cs.clone(), || Ok(self.X))?; + + let xG = G.scalar_mul_le(x_bits.iter())?; + xG.enforce_equal(&X)?; + + Ok(()) + } + } + + #[test] + fn test_nonnative_num_constraints() { + let mut rng = ark_std::test_rng(); + + // compute X = x * G + let x = Fr::rand(&mut rng); + let X = Projective::generator().mul(x); + + let cs = ConstraintSystem::::new_ref(); + let nonnative_scalarmul_circuit = NonNativeScalarMulCircuit::< + Projective, + NonNativePallasGVar, + NonNativeFieldVar, + > { + _gc: PhantomData, + _fv: PhantomData, + x, + X, + }; + + assert!(cs.is_satisfied().unwrap()); + dbg!(cs.num_constraints()); } }