mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-20 12:51:36 +01:00
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:
228
folding-schemes/src/utils/espresso/sum_check/prover.rs
Normal file
228
folding-schemes/src/utils/espresso/sum_check/prover.rs
Normal file
@@ -0,0 +1,228 @@
|
||||
// code forked from:
|
||||
// https://github.com/EspressoSystems/hyperplonk/tree/main/subroutines/src/poly_iop/sum_check
|
||||
//
|
||||
// Copyright (c) 2023 Espresso Systems (espressosys.com)
|
||||
// This file is part of the HyperPlonk library.
|
||||
|
||||
// You should have received a copy of the MIT License
|
||||
// along with the HyperPlonk library. If not, see <https://mit-license.org/>.
|
||||
|
||||
//! Prover subroutines for a SumCheck protocol.
|
||||
|
||||
use super::SumCheckProver;
|
||||
use crate::utils::{
|
||||
lagrange_poly::compute_lagrange_interpolated_poly, multilinear_polynomial::fix_variables,
|
||||
virtual_polynomial::VirtualPolynomial,
|
||||
};
|
||||
use ark_ec::CurveGroup;
|
||||
use ark_ff::Field;
|
||||
use ark_ff::{batch_inversion, PrimeField};
|
||||
use ark_poly::DenseMultilinearExtension;
|
||||
use ark_std::{cfg_into_iter, end_timer, start_timer, vec::Vec};
|
||||
use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator};
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::structs::{IOPProverMessage, IOPProverState};
|
||||
use espresso_subroutines::poly_iop::prelude::PolyIOPErrors;
|
||||
|
||||
// #[cfg(feature = "parallel")]
|
||||
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
||||
|
||||
impl<C: CurveGroup> SumCheckProver<C> for IOPProverState<C> {
|
||||
type VirtualPolynomial = VirtualPolynomial<C::ScalarField>;
|
||||
type ProverMessage = IOPProverMessage<C::ScalarField>;
|
||||
|
||||
/// Initialize the prover state to argue for the sum of the input polynomial
|
||||
/// over {0,1}^`num_vars`.
|
||||
fn prover_init(polynomial: &Self::VirtualPolynomial) -> Result<Self, PolyIOPErrors> {
|
||||
let start = start_timer!(|| "sum check prover init");
|
||||
if polynomial.aux_info.num_variables == 0 {
|
||||
return Err(PolyIOPErrors::InvalidParameters(
|
||||
"Attempt to prove a constant.".to_string(),
|
||||
));
|
||||
}
|
||||
end_timer!(start);
|
||||
|
||||
Ok(Self {
|
||||
challenges: Vec::with_capacity(polynomial.aux_info.num_variables),
|
||||
round: 0,
|
||||
poly: polynomial.clone(),
|
||||
extrapolation_aux: (1..polynomial.aux_info.max_degree)
|
||||
.map(|degree| {
|
||||
let points = (0..1 + degree as u64)
|
||||
.map(C::ScalarField::from)
|
||||
.collect::<Vec<_>>();
|
||||
let weights = barycentric_weights(&points);
|
||||
(points, weights)
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Receive message from verifier, generate prover message, and proceed to
|
||||
/// next round.
|
||||
///
|
||||
/// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2).
|
||||
fn prove_round_and_update_state(
|
||||
&mut self,
|
||||
challenge: &Option<C::ScalarField>,
|
||||
) -> Result<Self::ProverMessage, PolyIOPErrors> {
|
||||
// let start =
|
||||
// start_timer!(|| format!("sum check prove {}-th round and update state",
|
||||
// self.round));
|
||||
|
||||
if self.round >= self.poly.aux_info.num_variables {
|
||||
return Err(PolyIOPErrors::InvalidProver(
|
||||
"Prover is not active".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// let fix_argument = start_timer!(|| "fix argument");
|
||||
|
||||
// Step 1:
|
||||
// fix argument and evaluate f(x) over x_m = r; where r is the challenge
|
||||
// for the current round, and m is the round number, indexed from 1
|
||||
//
|
||||
// i.e.:
|
||||
// at round m <= n, for each mle g(x_1, ... x_n) within the flattened_mle
|
||||
// which has already been evaluated to
|
||||
//
|
||||
// g(r_1, ..., r_{m-1}, x_m ... x_n)
|
||||
//
|
||||
// eval g over r_m, and mutate g to g(r_1, ... r_m,, x_{m+1}... x_n)
|
||||
let mut flattened_ml_extensions: Vec<DenseMultilinearExtension<C::ScalarField>> = self
|
||||
.poly
|
||||
.flattened_ml_extensions
|
||||
.par_iter()
|
||||
.map(|x| x.as_ref().clone())
|
||||
.collect();
|
||||
|
||||
if let Some(chal) = challenge {
|
||||
if self.round == 0 {
|
||||
return Err(PolyIOPErrors::InvalidProver(
|
||||
"first round should be prover first.".to_string(),
|
||||
));
|
||||
}
|
||||
self.challenges.push(*chal);
|
||||
|
||||
let r = self.challenges[self.round - 1];
|
||||
// #[cfg(feature = "parallel")]
|
||||
flattened_ml_extensions
|
||||
.par_iter_mut()
|
||||
.for_each(|mle| *mle = fix_variables(mle, &[r]));
|
||||
// #[cfg(not(feature = "parallel"))]
|
||||
// flattened_ml_extensions
|
||||
// .iter_mut()
|
||||
// .for_each(|mle| *mle = fix_variables(mle, &[r]));
|
||||
} else if self.round > 0 {
|
||||
return Err(PolyIOPErrors::InvalidProver(
|
||||
"verifier message is empty".to_string(),
|
||||
));
|
||||
}
|
||||
// end_timer!(fix_argument);
|
||||
|
||||
self.round += 1;
|
||||
|
||||
let products_list = self.poly.products.clone();
|
||||
let mut products_sum = vec![C::ScalarField::ZERO; self.poly.aux_info.max_degree + 1];
|
||||
|
||||
// Step 2: generate sum for the partial evaluated polynomial:
|
||||
// f(r_1, ... r_m,, x_{m+1}... x_n)
|
||||
|
||||
products_list.iter().for_each(|(coefficient, products)| {
|
||||
let mut sum = cfg_into_iter!(0..1 << (self.poly.aux_info.num_variables - self.round))
|
||||
.fold(
|
||||
|| {
|
||||
(
|
||||
vec![(C::ScalarField::ZERO, C::ScalarField::ZERO); products.len()],
|
||||
vec![C::ScalarField::ZERO; products.len() + 1],
|
||||
)
|
||||
},
|
||||
|(mut buf, mut acc), b| {
|
||||
buf.iter_mut()
|
||||
.zip(products.iter())
|
||||
.for_each(|((eval, step), f)| {
|
||||
let table = &flattened_ml_extensions[*f];
|
||||
*eval = table[b << 1];
|
||||
*step = table[(b << 1) + 1] - table[b << 1];
|
||||
});
|
||||
acc[0] += buf.iter().map(|(eval, _)| eval).product::<C::ScalarField>();
|
||||
acc[1..].iter_mut().for_each(|acc| {
|
||||
buf.iter_mut().for_each(|(eval, step)| *eval += step as &_);
|
||||
*acc += buf.iter().map(|(eval, _)| eval).product::<C::ScalarField>();
|
||||
});
|
||||
(buf, acc)
|
||||
},
|
||||
)
|
||||
.map(|(_, partial)| partial)
|
||||
.reduce(
|
||||
|| vec![C::ScalarField::ZERO; products.len() + 1],
|
||||
|mut sum, partial| {
|
||||
sum.iter_mut()
|
||||
.zip(partial.iter())
|
||||
.for_each(|(sum, partial)| *sum += partial);
|
||||
sum
|
||||
},
|
||||
);
|
||||
sum.iter_mut().for_each(|sum| *sum *= coefficient);
|
||||
let extraploation = cfg_into_iter!(0..self.poly.aux_info.max_degree - products.len())
|
||||
.map(|i| {
|
||||
let (points, weights) = &self.extrapolation_aux[products.len() - 1];
|
||||
let at = C::ScalarField::from((products.len() + 1 + i) as u64);
|
||||
extrapolate(points, weights, &sum, &at)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
products_sum
|
||||
.iter_mut()
|
||||
.zip(sum.iter().chain(extraploation.iter()))
|
||||
.for_each(|(products_sum, sum)| *products_sum += sum);
|
||||
});
|
||||
|
||||
// update prover's state to the partial evaluated polynomial
|
||||
self.poly.flattened_ml_extensions = flattened_ml_extensions
|
||||
.par_iter()
|
||||
.map(|x| Arc::new(x.clone()))
|
||||
.collect();
|
||||
|
||||
let prover_poly = compute_lagrange_interpolated_poly::<C::ScalarField>(&products_sum);
|
||||
Ok(IOPProverMessage {
|
||||
coeffs: prover_poly.coeffs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::filter_map_bool_then)]
|
||||
fn barycentric_weights<F: PrimeField>(points: &[F]) -> Vec<F> {
|
||||
let mut weights = points
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(j, point_j)| {
|
||||
points
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, point_i)| (i != j).then(|| *point_j - point_i))
|
||||
.reduce(|acc, value| acc * value)
|
||||
.unwrap_or_else(F::one)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
batch_inversion(&mut weights);
|
||||
weights
|
||||
}
|
||||
|
||||
fn extrapolate<F: PrimeField>(points: &[F], weights: &[F], evals: &[F], at: &F) -> F {
|
||||
let (coeffs, sum_inv) = {
|
||||
let mut coeffs = points.iter().map(|point| *at - point).collect::<Vec<_>>();
|
||||
batch_inversion(&mut coeffs);
|
||||
coeffs.iter_mut().zip(weights).for_each(|(coeff, weight)| {
|
||||
*coeff *= weight;
|
||||
});
|
||||
let sum_inv = coeffs.iter().sum::<F>().inverse().unwrap_or_default();
|
||||
(coeffs, sum_inv)
|
||||
};
|
||||
coeffs
|
||||
.iter()
|
||||
.zip(evals)
|
||||
.map(|(coeff, eval)| *coeff * eval)
|
||||
.sum::<F>()
|
||||
* sum_inv
|
||||
}
|
||||
Reference in New Issue
Block a user