Add solidity groth16, kzg10 and final decider verifiers in a dedicated workspace (#70)

* change: Refactor structure into workspace

* chore: Add empty readme

* change: Transform repo into workspace

* add: Create folding-verifier-solidity crate

* add: Include askama.toml for `sol` extension escaper

* add: Jordi's old Groth16 verifier .sol template and adapt it

* tmp: create simple template struct to test

* Update FoldingSchemes trait, fit Nova+CycleFold

- update lib.rs's `FoldingScheme` trait interface
- fit Nova+CycleFold into the `FoldingScheme` trait
- refactor `src/nova/*`

* chore: add serialization assets for testing

Now we include an `assets` folder with a serialized proof & vk for tests

* Add `examples` dir, with Nova's `FoldingScheme` example

* polishing

* expose poseidon_test_config outside tests

* change: Refactor structure into workspace

* chore: Add empty readme

* change: Transform repo into workspace

* add: Create folding-verifier-solidity crate

* add: Include askama.toml for `sol` extension escaper

* add: Jordi's old Groth16 verifier .sol template and adapt it

* tmp: create simple template struct to test

* feat: templating kzg working

* chore: add emv and revm

* feat: start evm file

* chore: add ark-poly-commit

* chore: move `commitment` to `folding-schemes`

* chore: update `.gitignore` to ignore generated contracts

* chore: update template with bn254 lib on it (avoids import), update for loop to account for whitespaces

* refactor: update template with no lib

* feat: add evm deploy code, compile and create kzg verifier

* chore: update `Cargo.toml` to have `folding-schemes` available with verifiers

* feat: start kzg prove and verify with sol

* chore: compute crs from kzg prover

* feat: evm kzg verification passing

* tmp

* change: Swap order of G2 coordinates within the template

* Update way to serialize proof with correct order

* chore: update `Cargo.toml`

* chore: add revm

* chore: add `save_solidity`

* refactor: verifiers in dedicated mod

* refactor: have dedicated `utils` module

* chore: expose modules

* chore: update verifier for kzg

* chore: rename templates

* fix: look for binary using also name of contract

* refactor: generate groth16 proof for sha256 pre-image, generate groth16 template with verifying key

* chore: template renaming

* fix: switch circuit for circuit that simply adds

* feat: generates test data on the fly

* feat: update to latest groth16 verifier

* refactor: rename folder, update `.gitignore`

* chore: update `Cargo.toml`

* chore: update templates extension to indicate that they are templates

* chore: rename templates, both files and structs

* fix: template inheritance working

* feat: template spdx and pragma statements

* feat: decider verifier compiles, update test for kzg10 and groth16 templates

* feat: parameterize which size of the crs should be stored on the contract

* chore: add comment on how the groth16 and kzg10 proofs will be linked together

* chore: cargo clippy run

* chore: cargo clippy tests

* chore: cargo fmt

* refactor: remove unused lifetime parameter

* chore: end merge

* chore: move examples to `folding-schemes` workspace

* get latest main changes

* fix: temp fix clippy warnings, will remove lints once not used in tests only

* fix: cargo clippy lint added on `code_size`

* fix: update path to test circuit and add step for installing solc

* chore: remove `save_solidity` steps

* fix: the borrowed expression implements the required traits

* chore: update `Cargo.toml`

* chore: remove extra `[patch.crates-io]`

* fix: update to patch at the workspace level and add comment explaining this

* refactor: correct `staticcall` with valid input/output sizes and change return syntax for pairing

* refactor: expose modules and remove `dead_code` calls

* chore: update `README.md`, add additional comments on `kzg10` template and update `groth16` template comments

* chore: be clearer on attributions on `kzg10`

---------

Co-authored-by: CPerezz <c.perezbaro@gmail.com>
Co-authored-by: arnaucube <root@arnaucube.com>
This commit is contained in:
Pierre
2024-02-09 08:19:25 +01:00
committed by GitHub
parent 97e973a685
commit 63dbbfe1bc
67 changed files with 1208 additions and 53 deletions

View File

@@ -0,0 +1,229 @@
use ark_ec::CurveGroup;
use ark_ff::Field;
use ark_r1cs_std::{boolean::Boolean, groups::GroupOpsBounds, prelude::CurveVar};
use ark_relations::r1cs::SynthesisError;
use ark_std::{rand::Rng, UniformRand};
use core::marker::PhantomData;
use super::CommitmentProver;
use crate::transcript::Transcript;
use crate::utils::vec::{vec_add, vec_scalar_mul};
use crate::Error;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Proof<C: CurveGroup> {
pub R: C,
pub u: Vec<C::ScalarField>,
pub r_u: C::ScalarField,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Params<C: CurveGroup> {
pub h: C,
pub generators: Vec<C::Affine>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Pedersen<C: CurveGroup> {
_c: PhantomData<C>,
}
impl<C: CurveGroup> Pedersen<C> {
pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> {
let generators: Vec<C::Affine> = std::iter::repeat_with(|| C::Affine::rand(rng))
.take(max.next_power_of_two())
.collect();
let params: Params<C> = Params::<C> {
h: C::rand(rng),
generators,
};
params
}
}
// implement the CommitmentProver trait for Pedersen
impl<C: CurveGroup> CommitmentProver<C> for Pedersen<C> {
type Params = Params<C>;
type Proof = Proof<C>;
fn commit(
params: &Self::Params,
v: &[C::ScalarField],
r: &C::ScalarField, // blinding factor
) -> Result<C, Error> {
if params.generators.len() < v.len() {
return Err(Error::PedersenParamsLen(params.generators.len(), v.len()));
}
// h⋅r + <g, v>
// use msm_unchecked because we already ensured at the if that lengths match
Ok(params.h.mul(r) + C::msm_unchecked(&params.generators[..v.len()], v))
}
fn prove(
params: &Params<C>,
transcript: &mut impl Transcript<C>,
cm: &C,
v: &[C::ScalarField],
r: &C::ScalarField, // blinding factor
) -> Result<Self::Proof, Error> {
if params.generators.len() < v.len() {
return Err(Error::PedersenParamsLen(params.generators.len(), v.len()));
}
transcript.absorb_point(cm)?;
let r1 = transcript.get_challenge();
let d = transcript.get_challenges(v.len());
// R = h⋅r_1 + <g, d>
// use msm_unchecked because we already ensured at the if that lengths match
let R: C = params.h.mul(r1) + C::msm_unchecked(&params.generators[..d.len()], &d);
transcript.absorb_point(&R)?;
let e = transcript.get_challenge();
// u = d + v⋅e
let u = vec_add(&vec_scalar_mul(v, &e), &d)?;
// r_u = e⋅r + r_1
let r_u = e * r + r1;
Ok(Self::Proof { R, u, r_u })
}
}
impl<C: CurveGroup> Pedersen<C> {
pub fn verify(
params: &Params<C>,
transcript: &mut impl Transcript<C>,
cm: C,
proof: Proof<C>,
) -> Result<(), Error> {
if params.generators.len() < proof.u.len() {
return Err(Error::PedersenParamsLen(
params.generators.len(),
proof.u.len(),
));
}
transcript.absorb_point(&cm)?;
transcript.get_challenge(); // r_1
transcript.get_challenges(proof.u.len()); // d
transcript.absorb_point(&proof.R)?;
let e = transcript.get_challenge();
// check that: R + cm⋅e == h⋅r_u + <g, u>
let lhs = proof.R + cm.mul(e);
// use msm_unchecked because we already ensured at the if that lengths match
let rhs = params.h.mul(proof.r_u)
+ C::msm_unchecked(&params.generators[..proof.u.len()], &proof.u);
if lhs != rhs {
return Err(Error::CommitmentVerificationFail);
}
Ok(())
}
}
pub type CF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
pub struct PedersenGadget<C, GC>
where
C: CurveGroup,
GC: CurveVar<C, CF<C>>,
{
_cf: PhantomData<CF<C>>,
_c: PhantomData<C>,
_gc: PhantomData<GC>,
}
impl<C, GC> PedersenGadget<C, GC>
where
C: CurveGroup,
GC: CurveVar<C, CF<C>>,
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
pub fn commit(
h: GC,
g: Vec<GC>,
v: Vec<Vec<Boolean<CF<C>>>>,
r: Vec<Boolean<CF<C>>>,
) -> Result<GC, SynthesisError> {
let mut res = GC::zero();
res += h.scalar_mul_le(r.iter())?;
for (i, v_i) in v.iter().enumerate() {
res += g[i].scalar_mul_le(v_i.iter())?;
}
Ok(res)
}
}
#[cfg(test)]
mod tests {
use ark_ff::{BigInteger, PrimeField};
use ark_pallas::{constraints::GVar, Fq, Fr, Projective};
use ark_r1cs_std::{alloc::AllocVar, bits::boolean::Boolean, eq::EqGadget};
use ark_relations::r1cs::ConstraintSystem;
use ark_std::UniformRand;
use super::*;
use crate::transcript::poseidon::{poseidon_test_config, PoseidonTranscript};
#[test]
fn test_pedersen_vector() {
let mut rng = ark_std::test_rng();
let n: usize = 10;
// setup params
let params = Pedersen::<Projective>::new_params(&mut rng, n);
let poseidon_config = poseidon_test_config::<Fr>();
// init Prover's transcript
let mut transcript_p = PoseidonTranscript::<Projective>::new(&poseidon_config);
// init Verifier's transcript
let mut transcript_v = PoseidonTranscript::<Projective>::new(&poseidon_config);
let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
.take(n)
.collect();
let r: Fr = Fr::rand(&mut rng);
let cm = Pedersen::<Projective>::commit(&params, &v, &r).unwrap();
let proof = Pedersen::<Projective>::prove(&params, &mut transcript_p, &cm, &v, &r).unwrap();
Pedersen::<Projective>::verify(&params, &mut transcript_v, cm, proof).unwrap();
}
#[test]
fn test_pedersen_circuit() {
let mut rng = ark_std::test_rng();
let n: usize = 10;
// setup params
let params = Pedersen::<Projective>::new_params(&mut rng, n);
let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
.take(n)
.collect();
let r: Fr = Fr::rand(&mut rng);
let cm = Pedersen::<Projective>::commit(&params, &v, &r).unwrap();
// circuit
let cs = ConstraintSystem::<Fq>::new_ref();
let v_bits: Vec<Vec<bool>> = v.iter().map(|val| val.into_bigint().to_bits_le()).collect();
let r_bits: Vec<bool> = r.into_bigint().to_bits_le();
// prepare inputs
let vVar: Vec<Vec<Boolean<Fq>>> = v_bits
.iter()
.map(|val_bits| {
Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(val_bits.clone())).unwrap()
})
.collect();
let rVar = Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(r_bits)).unwrap();
let gVar = Vec::<GVar>::new_witness(cs.clone(), || Ok(params.generators)).unwrap();
let hVar = GVar::new_witness(cs.clone(), || Ok(params.h)).unwrap();
let expected_cmVar = GVar::new_witness(cs.clone(), || Ok(cm)).unwrap();
// use the gadget
let cmVar = PedersenGadget::<Projective, GVar>::commit(hVar, gVar, vVar, rVar).unwrap();
cmVar.enforce_equal(&expected_cmVar).unwrap();
}
}