diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8e8e3f..7dcbdff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,8 +55,12 @@ jobs: curl -sSfL https://github.com/iden3/circom/releases/download/v2.1.6/circom-linux-amd64 -o $HOME/bin/circom chmod +x $HOME/bin/circom echo "$HOME/bin" >> $GITHUB_PATH + - name: Download solc + run: | + curl -sSfL https://github.com/ethereum/solidity/releases/download/v0.8.4/solc-static-linux -o /usr/local/bin/solc + chmod +x /usr/local/bin/solc - name: Execute compile.sh to generate .r1cs and .wasm from .circom - run: bash ./src/frontend/circom/test_folder/compile.sh + run: bash ./folding-schemes/src/frontend/circom/test_folder/compile.sh - name: Build # This build will be reused by nextest, # and also checks (--all-targets) that benches don't bit-rot diff --git a/.gitignore b/.gitignore index e8d5982..ec388aa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ Cargo.lock # Circom generated files /src/frontend/circom/test_folder/test_circuit.r1cs -/src/frontend/circom/test_folder/test_circuit_js/ \ No newline at end of file +/src/frontend/circom/test_folder/test_circuit_js/ + +# generated contracts at test time +folding-schemes-solidity/generated \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5913108..87b06ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,50 +1,9 @@ -[package] -name = "folding-schemes" -version = "0.1.0" -edition = "2021" - -[dependencies] -ark-ec = "^0.4.0" -ark-ff = "^0.4.0" -ark-poly = "^0.4.0" -ark-std = "^0.4.0" -ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["r1cs", "sponge", "crh"] } -ark-poly-commit = "^0.4.0" -ark-relations = { version = "^0.4.0", default-features = false } -ark-r1cs-std = { default-features = false } # use latest version from the patch -ark-snark = { version = "^0.4.0"} -ark-serialize = "^0.4.0" -ark-circom = { git = "https://github.com/gakonst/ark-circom.git" } -thiserror = "1.0" -rayon = "1.7.0" -num-bigint = "0.4" -color-eyre = "=0.6.2" - -# tmp imports for espresso's sumcheck -espresso_subroutines = {git="https://github.com/EspressoSystems/hyperplonk", package="subroutines"} - -[dev-dependencies] -ark-pallas = {version="0.4.0", features=["r1cs"]} -ark-vesta = {version="0.4.0", features=["r1cs"]} -ark-bn254 = "0.4.0" -ark-mnt4-298 = {version="0.4.0", features=["r1cs"]} -ark-mnt6-298 = {version="0.4.0", features=["r1cs"]} -ark-groth16 = { version = "^0.4.0" } -rand = "0.8.5" -tracing = { version = "0.1", default-features = false, features = [ "attributes" ] } -tracing-subscriber = { version = "0.2" } - -[features] -default = ["parallel"] - -parallel = [ - "ark-std/parallel", - "ark-ff/parallel", - "ark-ec/parallel", - "ark-poly/parallel", - "ark-crypto-primitives/parallel", - "ark-r1cs-std/parallel", - ] +[workspace] +resolver = "1" +members = [ + "folding-schemes", + "folding-schemes-solidity" +] # The following patch is to use a version of ark-r1cs-std compatible with # v0.4.0 but that includes a cherry-picked commit from after v0.4.0 which fixes @@ -52,5 +11,4 @@ parallel = [ # https://github.com/arkworks-rs/r1cs-std/pull/124, without including other # changes done between v0.4.0 and this fix which would break compatibility. [patch.crates-io] -ark-r1cs-std = { git = "https://github.com/arnaucube/ark-r1cs-std-cherry-picked/" } - +ark-r1cs-std = { git = "https://github.com/arnaucube/ark-r1cs-std-cherry-picked/" } \ No newline at end of file diff --git a/folding-schemes-solidity/Cargo.toml b/folding-schemes-solidity/Cargo.toml new file mode 100644 index 0000000..f92154d --- /dev/null +++ b/folding-schemes-solidity/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "folding-schemes-solidity" +version = "0.1.0" +edition = "2021" + +[dependencies] +ark-ec = "0.4" +ark-ff = "0.4" +ark-poly = "0.4" +ark-std = "0.4" +ark-groth16 = "0.4" +askama = { version = "0.12.0", features = ["config"], default-features = false } +ark-bn254 = "0.4.0" +ark-poly-commit = "0.4.0" +folding-schemes = { path = "../folding-schemes/" } +itertools = "0.12.1" +ark-serialize = "0.4.1" +revm = "3.5.0" + +[dev-dependencies] +ark-crypto-primitives = "0.4.0" +ark-groth16 = "0.4" +ark-r1cs-std = "0.4.0" +ark-relations = "0.4.0" +revm = "3.5.0" +tracing = { version = "0.1", default-features = false, features = [ "attributes" ] } +tracing-subscriber = { version = "0.2" } + +[features] +default = ["parallel"] + +parallel = [ + "ark-std/parallel", + "ark-ff/parallel", + "ark-poly/parallel", + ] + + + diff --git a/folding-schemes-solidity/README.md b/folding-schemes-solidity/README.md new file mode 100644 index 0000000..e72cc83 --- /dev/null +++ b/folding-schemes-solidity/README.md @@ -0,0 +1,3 @@ +# `folding-schemes-solidity` + +This crate implements templating logic to output verifier contracts for `folding-schemes`-generated decider proofs. \ No newline at end of file diff --git a/folding-schemes-solidity/askama.toml b/folding-schemes-solidity/askama.toml new file mode 100644 index 0000000..c596edf --- /dev/null +++ b/folding-schemes-solidity/askama.toml @@ -0,0 +1,3 @@ +[[escaper]] +path = "askama::Text" +extensions = ["sol"] \ No newline at end of file diff --git a/folding-schemes-solidity/src/evm.rs b/folding-schemes-solidity/src/evm.rs new file mode 100644 index 0000000..8afc9f6 --- /dev/null +++ b/folding-schemes-solidity/src/evm.rs @@ -0,0 +1,181 @@ +pub use revm; +use revm::{ + primitives::{hex, Address, CreateScheme, ExecutionResult, Output, TransactTo, TxEnv}, + InMemoryDB, EVM, +}; +use std::{ + fmt::{self, Debug, Formatter}, + fs::{create_dir_all, File}, + io::{self, Write}, + process::{Command, Stdio}, + str, +}; + +// from: https://github.com/privacy-scaling-explorations/halo2-solidity-verifier/blob/85cb77b171ce3ee493628007c7a1cfae2ea878e6/examples/separately.rs#L56 +pub fn save_solidity(name: impl AsRef, solidity: &str) { + const DIR_GENERATED: &str = "./generated"; + create_dir_all(DIR_GENERATED).unwrap(); + File::create(format!("{DIR_GENERATED}/{}", name.as_ref())) + .unwrap() + .write_all(solidity.as_bytes()) + .unwrap(); +} + +/// Compile solidity with `--via-ir` flag, then return creation bytecode. +/// +/// # Panics +/// Panics if executable `solc` can not be found, or compilation fails. +pub fn compile_solidity(solidity: impl AsRef<[u8]>, contract_name: &str) -> Vec { + let mut process = match Command::new("solc") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .arg("--bin") + .arg("--optimize") + .arg("-") + .spawn() + { + Ok(process) => process, + Err(err) if err.kind() == io::ErrorKind::NotFound => { + panic!("Command 'solc' not found"); + } + Err(err) => { + panic!("Failed to spawn process with command 'solc':\n{err}"); + } + }; + process + .stdin + .take() + .unwrap() + .write_all(solidity.as_ref()) + .unwrap(); + let output = process.wait_with_output().unwrap(); + let stdout = str::from_utf8(&output.stdout).unwrap(); + if let Some(binary) = find_binary(stdout, contract_name) { + binary + } else { + panic!( + "Compilation fails:\n{}", + str::from_utf8(&output.stderr).unwrap() + ) + } +} + +/// Find binary from `stdout` with given `contract_name`. +/// `contract_name` is provided since `solc` may compile multiple contracts or libraries. +/// hence, we need to find the correct binary. +fn find_binary(stdout: &str, contract_name: &str) -> Option> { + let start_contract = stdout.find(contract_name)?; + let stdout_contract = &stdout[start_contract..]; + let start = stdout_contract.find("Binary:")? + 8; + Some(hex::decode(&stdout_contract[start..stdout_contract.len() - 1]).unwrap()) +} + +/// Evm runner. +pub struct Evm { + evm: EVM, +} + +impl Debug for Evm { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut debug_struct = f.debug_struct("Evm"); + debug_struct + .field("env", &self.evm.env) + .field("db", &self.evm.db.as_ref().unwrap()) + .finish() + } +} + +impl Default for Evm { + fn default() -> Self { + Self { + evm: EVM { + env: Default::default(), + db: Some(Default::default()), + }, + } + } +} + +impl Evm { + /// Return code_size of given address. + /// + /// # Panics + /// Panics if given address doesn't have bytecode. + pub fn code_size(&mut self, address: Address) -> usize { + self.evm.db.as_ref().unwrap().accounts[&address] + .info + .code + .as_ref() + .unwrap() + .len() + } + + /// Apply create transaction with given `bytecode` as creation bytecode. + /// Return created `address`. + /// + /// # Panics + /// Panics if execution reverts or halts unexpectedly. + pub fn create(&mut self, bytecode: Vec) -> Address { + let (_, output) = self.transact_success_or_panic(TxEnv { + gas_limit: u64::MAX, + transact_to: TransactTo::Create(CreateScheme::Create), + data: bytecode.into(), + ..Default::default() + }); + match output { + Output::Create(_, Some(address)) => address, + _ => unreachable!(), + } + } + + /// Apply call transaction to given `address` with `calldata`. + /// Returns `gas_used` and `return_data`. + /// + /// # Panics + /// Panics if execution reverts or halts unexpectedly. + pub fn call(&mut self, address: Address, calldata: Vec) -> (u64, Vec) { + let (gas_used, output) = self.transact_success_or_panic(TxEnv { + gas_limit: u64::MAX, + transact_to: TransactTo::Call(address), + data: calldata.into(), + ..Default::default() + }); + match output { + Output::Call(output) => (gas_used, output.into()), + _ => unreachable!(), + } + } + + fn transact_success_or_panic(&mut self, tx: TxEnv) -> (u64, Output) { + self.evm.env.tx = tx; + let result = self.evm.transact_commit().unwrap(); + self.evm.env.tx = Default::default(); + match result { + ExecutionResult::Success { + gas_used, + output, + logs, + .. + } => { + if !logs.is_empty() { + println!("--- logs from {} ---", logs[0].address); + for (log_idx, log) in logs.iter().enumerate() { + println!("log#{log_idx}"); + for (topic_idx, topic) in log.topics.iter().enumerate() { + println!(" topic{topic_idx}: {topic:?}"); + } + } + println!("--- end ---"); + } + (gas_used, output) + } + ExecutionResult::Revert { gas_used, output } => { + panic!("Transaction reverts with gas_used {gas_used} and output {output:#x}") + } + ExecutionResult::Halt { reason, gas_used } => panic!( + "Transaction halts unexpectedly with gas_used {gas_used} and reason {reason:?}" + ), + } + } +} diff --git a/folding-schemes-solidity/src/lib.rs b/folding-schemes-solidity/src/lib.rs new file mode 100644 index 0000000..7bbeeb4 --- /dev/null +++ b/folding-schemes-solidity/src/lib.rs @@ -0,0 +1,5 @@ +pub use evm::*; +pub use verifiers::templates::*; +mod evm; +mod utils; +mod verifiers; diff --git a/folding-schemes-solidity/src/utils/encoding.rs b/folding-schemes-solidity/src/utils/encoding.rs new file mode 100644 index 0000000..c9f7b48 --- /dev/null +++ b/folding-schemes-solidity/src/utils/encoding.rs @@ -0,0 +1,43 @@ +/// Defines encodings of G1 and G2 elements for use in Solidity templates. +use ark_bn254::{Fq, G1Affine, G2Affine}; +use std::fmt::{self, Display}; + +#[derive(Debug, Default)] +pub struct FqWrapper(pub Fq); + +impl Display for FqWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[derive(Debug, Default)] +pub struct G1Repr(pub [FqWrapper; 2]); + +impl Display for G1Repr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:#?}", self.0) + } +} + +/// Converts a G1 element to a representation that can be used in Solidity templates. +pub fn g1_to_fq_repr(g1: G1Affine) -> G1Repr { + G1Repr([FqWrapper(g1.x), FqWrapper(g1.y)]) +} + +#[derive(Debug, Default)] +pub struct G2Repr(pub [[FqWrapper; 2]; 2]); + +impl Display for G2Repr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:#?}", self.0) + } +} + +/// Converts a G2 element to a representation that can be used in Solidity templates. +pub fn g2_to_fq_repr(g2: G2Affine) -> G2Repr { + G2Repr([ + [FqWrapper(g2.x.c0), FqWrapper(g2.x.c1)], + [FqWrapper(g2.y.c0), FqWrapper(g2.y.c1)], + ]) +} diff --git a/folding-schemes-solidity/src/utils/mod.rs b/folding-schemes-solidity/src/utils/mod.rs new file mode 100644 index 0000000..2956942 --- /dev/null +++ b/folding-schemes-solidity/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod encoding; diff --git a/folding-schemes-solidity/src/verifiers/mod.rs b/folding-schemes-solidity/src/verifiers/mod.rs new file mode 100644 index 0000000..4d59f0b --- /dev/null +++ b/folding-schemes-solidity/src/verifiers/mod.rs @@ -0,0 +1,287 @@ +pub mod templates; + +#[cfg(test)] +mod tests { + use crate::evm::{compile_solidity, save_solidity, Evm}; + use crate::verifiers::templates::{Groth16Verifier, KZG10Verifier}; + use ark_bn254::{Bn254, Fr, G1Projective as G1}; + use ark_crypto_primitives::snark::{CircuitSpecificSetupSNARK, SNARK}; + use ark_ec::{AffineRepr, CurveGroup}; + use ark_ff::{BigInt, BigInteger, PrimeField}; + use ark_groth16::Groth16; + use ark_poly_commit::kzg10::VerifierKey; + use ark_r1cs_std::alloc::AllocVar; + use ark_r1cs_std::eq::EqGadget; + use ark_r1cs_std::fields::fp::FpVar; + use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; + use ark_std::rand::{RngCore, SeedableRng}; + use ark_std::Zero; + use ark_std::{test_rng, UniformRand}; + use askama::Template; + use folding_schemes::{ + commitment::{ + kzg::{KZGProver, KZGSetup, ProverKey}, + CommitmentProver, + }, + transcript::{ + poseidon::{poseidon_test_config, PoseidonTranscript}, + Transcript, + }, + }; + use itertools::chain; + use std::marker::PhantomData; + + // Function signatures for proof verification on kzg10 and groth16 contracts + pub const FUNCTION_SIGNATURE_KZG10_CHECK: [u8; 4] = [0x9e, 0x78, 0xcc, 0xf7]; + pub const FUNCTION_SIGNATURE_GROTH16_VERIFY_PROOF: [u8; 4] = [0x43, 0x75, 0x3b, 0x4d]; + + // Pragma statements for verifiers + pub const PRAGMA_GROTH16_VERIFIER: &str = "pragma solidity >=0.7.0 <0.9.0;"; // from snarkjs, avoid changing + pub const PRAGMA_KZG10_VERIFIER: &str = "pragma solidity >=0.8.1 <=0.8.4;"; + + struct TestAddCircuit { + _f: PhantomData, + pub x: u8, + pub y: u8, + pub z: u8, + } + + impl ConstraintSynthesizer for TestAddCircuit { + fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { + let x = FpVar::::new_witness(cs.clone(), || Ok(F::from(self.x)))?; + let y = FpVar::::new_witness(cs.clone(), || Ok(F::from(self.y)))?; + let z = FpVar::::new_input(cs.clone(), || Ok(F::from(self.z)))?; + let comp_z = x.clone() + y.clone(); + comp_z.enforce_equal(&z)?; + Ok(()) + } + } + + #[test] + fn test_groth16_kzg10_decider_template_renders() { + let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64()); + let (x, y, z) = (21, 21, 42); + let (_, vk) = { + let c = TestAddCircuit:: { + _f: PhantomData, + x, + y, + z, + }; + Groth16::::setup(c, &mut rng).unwrap() + }; + let groth16_template = Groth16Verifier::from(vk, None); + let (pk, vk): (ProverKey, VerifierKey) = KZGSetup::::setup(&mut rng, 5); + let kzg10_template = KZG10Verifier::from(&vk, &pk.powers_of_g[..5], None, None); + let decider_template = super::templates::Groth16KZG10DeciderVerifier { + groth16_verifier: groth16_template, + kzg10_verifier: kzg10_template, + }; + save_solidity("decider.sol", &decider_template.render().unwrap()); + } + + #[test] + fn test_groth16_kzg10_decider_template_compiles() { + let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64()); + let (x, y, z) = (21, 21, 42); + let (_, vk) = { + let c = TestAddCircuit:: { + _f: PhantomData, + x, + y, + z, + }; + Groth16::::setup(c, &mut rng).unwrap() + }; + // we dont specify any pragma values for both verifiers, the pragma from the decider takes over + let groth16_template = Groth16Verifier::from(vk, None); + let (pk, vk): (ProverKey, VerifierKey) = KZGSetup::::setup(&mut rng, 5); + let kzg10_template = KZG10Verifier::from(&vk, &pk.powers_of_g[..5], None, None); + let decider_template = super::templates::Groth16KZG10DeciderVerifier { + groth16_verifier: groth16_template, + kzg10_verifier: kzg10_template, + }; + let decider_verifier_bytecode = + compile_solidity(decider_template.render().unwrap(), "NovaDecider"); + let mut evm = Evm::default(); + _ = evm.create(decider_verifier_bytecode); + } + + #[test] + fn test_groth16_verifier_template_renders() { + let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64()); + let (x, y, z) = (21, 21, 42); + let (_, vk) = { + let c = TestAddCircuit:: { + _f: PhantomData, + x, + y, + z, + }; + Groth16::::setup(c, &mut rng).unwrap() + }; + let template = Groth16Verifier::from(vk, Some(PRAGMA_GROTH16_VERIFIER.to_string())); + save_solidity("groth16_verifier.sol", &template.render().unwrap()); + _ = template.render().unwrap(); + } + + #[test] + fn test_groth16_verifier_template_compiles() { + let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64()); + let (x, y, z) = (21, 21, 42); + let (_, vk) = { + let c = TestAddCircuit:: { + _f: PhantomData, + x, + y, + z, + }; + Groth16::::setup(c, &mut rng).unwrap() + }; + let res = Groth16Verifier::from(vk, Some(PRAGMA_GROTH16_VERIFIER.to_string())) + .render() + .unwrap(); + let groth16_verifier_bytecode = compile_solidity(res, "Verifier"); + let mut evm = Evm::default(); + _ = evm.create(groth16_verifier_bytecode); + } + + #[test] + fn test_groth16_verifier_accepts_and_rejects_proofs() { + let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64()); + let (x, y, z) = (21, 21, 42); + let (pk, vk) = { + let c = TestAddCircuit:: { + _f: PhantomData, + x, + y, + z, + }; + Groth16::::setup(c, &mut rng).unwrap() + }; + let c = TestAddCircuit:: { + _f: PhantomData, + x, + y, + z, + }; + let proof = Groth16::::prove(&pk, c, &mut rng).unwrap(); + let res = Groth16Verifier::from(vk, Some(PRAGMA_GROTH16_VERIFIER.to_string())) + .render() + .unwrap(); + save_solidity("groth16_verifier.sol", &res); + let groth16_verifier_bytecode = compile_solidity(&res, "Verifier"); + let mut evm = Evm::default(); + let verifier_address = evm.create(groth16_verifier_bytecode); + let (a_x, a_y) = proof.a.xy().unwrap(); + let (b_x, b_y) = proof.b.xy().unwrap(); + let (c_x, c_y) = proof.c.xy().unwrap(); + let mut calldata: Vec = chain![ + FUNCTION_SIGNATURE_GROTH16_VERIFY_PROOF, + a_x.into_bigint().to_bytes_be(), + a_y.into_bigint().to_bytes_be(), + b_x.c1.into_bigint().to_bytes_be(), + b_x.c0.into_bigint().to_bytes_be(), + b_y.c1.into_bigint().to_bytes_be(), + b_y.c0.into_bigint().to_bytes_be(), + c_x.into_bigint().to_bytes_be(), + c_y.into_bigint().to_bytes_be(), + BigInt::from(Fr::from(z)).to_bytes_be(), + ] + .collect(); + let (_, output) = evm.call(verifier_address, calldata.clone()); + assert_eq!(*output.last().unwrap(), 1); + + // change calldata to make it invalid + let last_calldata_element = calldata.last_mut().unwrap(); + *last_calldata_element = 0; + let (_, output) = evm.call(verifier_address, calldata); + assert_eq!(*output.last().unwrap(), 0); + } + + #[test] + fn test_kzg_verifier_template_renders() { + let rng = &mut test_rng(); + let n = 10; + let (pk, vk): (ProverKey, VerifierKey) = KZGSetup::::setup(rng, n); + let template = KZG10Verifier::from( + &vk, + &pk.powers_of_g[..5], + Some(PRAGMA_KZG10_VERIFIER.to_string()), + None, + ); + let res = template.render().unwrap(); + assert!(res.contains(&vk.g.x.to_string())); + } + + #[test] + fn test_kzg_verifier_compiles() { + let rng = &mut test_rng(); + let n = 10; + let (pk, vk): (ProverKey, VerifierKey) = KZGSetup::::setup(rng, n); + let template = KZG10Verifier::from( + &vk, + &pk.powers_of_g[..5], + Some(PRAGMA_KZG10_VERIFIER.to_string()), + None, + ); + let res = template.render().unwrap(); + let kzg_verifier_bytecode = compile_solidity(res, "KZG10"); + let mut evm = Evm::default(); + _ = evm.create(kzg_verifier_bytecode); + } + + #[test] + fn test_kzg_verifier_accepts_and_rejects_proofs() { + let rng = &mut test_rng(); + let poseidon_config = poseidon_test_config::(); + let transcript_p = &mut PoseidonTranscript::::new(&poseidon_config); + let transcript_v = &mut PoseidonTranscript::::new(&poseidon_config); + + let n = 10; + let (pk, vk): (ProverKey, VerifierKey) = KZGSetup::::setup(rng, n); + let v: Vec = std::iter::repeat_with(|| Fr::rand(rng)).take(n).collect(); + let cm = KZGProver::::commit(&pk, &v, &Fr::zero()).unwrap(); + let (eval, proof) = + KZGProver::::prove(&pk, transcript_p, &cm, &v, &Fr::zero()).unwrap(); + let template = KZG10Verifier::from( + &vk, + &pk.powers_of_g[..5], + Some(PRAGMA_KZG10_VERIFIER.to_string()), + None, + ); + let res = template.render().unwrap(); + let kzg_verifier_bytecode = compile_solidity(res, "KZG10"); + let mut evm = Evm::default(); + let verifier_address = evm.create(kzg_verifier_bytecode); + + let (cm_affine, proof_affine) = (cm.into_affine(), proof.into_affine()); + let (x_comm, y_comm) = cm_affine.xy().unwrap(); + let (x_proof, y_proof) = proof_affine.xy().unwrap(); + let y = eval.into_bigint().to_bytes_be(); + + transcript_v.absorb_point(&cm).unwrap(); + let x = transcript_v.get_challenge(); + + let x = x.into_bigint().to_bytes_be(); + let mut calldata: Vec = chain![ + FUNCTION_SIGNATURE_KZG10_CHECK, + x_comm.into_bigint().to_bytes_be(), + y_comm.into_bigint().to_bytes_be(), + x_proof.into_bigint().to_bytes_be(), + y_proof.into_bigint().to_bytes_be(), + x.clone(), + y, + ] + .collect(); + + let (_, output) = evm.call(verifier_address, calldata.clone()); + assert_eq!(*output.last().unwrap(), 1); + + // change calldata to make it invalid + let last_calldata_element = calldata.last_mut().unwrap(); + *last_calldata_element = 0; + let (_, output) = evm.call(verifier_address, calldata); + assert_eq!(*output.last().unwrap(), 0); + } +} diff --git a/folding-schemes-solidity/src/verifiers/templates.rs b/folding-schemes-solidity/src/verifiers/templates.rs new file mode 100644 index 0000000..8431d58 --- /dev/null +++ b/folding-schemes-solidity/src/verifiers/templates.rs @@ -0,0 +1,113 @@ +use std::ops::Deref; + +use crate::utils::encoding::{g1_to_fq_repr, g2_to_fq_repr}; +/// Solidity templates for the verifier contracts. +/// We use askama for templating and define which variables are required for each template. +use crate::utils::encoding::{G1Repr, G2Repr}; +use ark_bn254::{Bn254, G1Affine}; +use ark_groth16::VerifyingKey; +use ark_poly_commit::kzg10::VerifierKey; +use askama::Template; + +#[derive(Template, Default)] +#[template(path = "groth16_verifier.askama.sol", ext = "sol")] +pub struct Groth16Verifier { + /// SPDX-License-Identifier + pub sdpx: String, + /// The `pragma` statement. + pub pragma_version: String, + /// The `alpha * G`, where `G` is the generator of `G1`. + pub vkey_alpha_g1: G1Repr, + /// The `alpha * H`, where `H` is the generator of `G2`. + pub vkey_beta_g2: G2Repr, + /// The `gamma * H`, where `H` is the generator of `G2`. + pub vkey_gamma_g2: G2Repr, + /// The `delta * H`, where `H` is the generator of `G2`. + pub vkey_delta_g2: G2Repr, + /// Length of the `gamma_abc_g1` vector. + pub gamma_abc_len: usize, + /// The `gamma^{-1} * (beta * a_i + alpha * b_i + c_i) * H`, where `H` is the generator of `E::G1`. + pub gamma_abc_g1: Vec, +} + +impl Groth16Verifier { + pub fn from(value: VerifyingKey, pragma: Option) -> Self { + let pragma_version = pragma.unwrap_or_default(); + let sdpx = "// SPDX-License-Identifier: GPL-3.0".to_string(); + Self { + pragma_version, + sdpx, + vkey_alpha_g1: g1_to_fq_repr(value.alpha_g1), + vkey_beta_g2: g2_to_fq_repr(value.beta_g2), + vkey_gamma_g2: g2_to_fq_repr(value.gamma_g2), + vkey_delta_g2: g2_to_fq_repr(value.delta_g2), + gamma_abc_len: value.gamma_abc_g1.len(), + gamma_abc_g1: value + .gamma_abc_g1 + .iter() + .copied() + .map(g1_to_fq_repr) + .collect(), + } + } +} + +#[derive(Template, Default)] +#[template(path = "kzg10_verifier.askama.sol", ext = "sol")] +pub struct KZG10Verifier { + /// SPDX-License-Identifier + pub sdpx: String, + /// The `pragma` statement. + pub pragma_version: String, + /// The generator of `G1`. + pub g1: G1Repr, + /// The generator of `G2`. + pub g2: G2Repr, + /// The verification key + pub vk: G2Repr, + /// Length of the trusted setup vector. + pub g1_crs_len: usize, + /// The trusted setup vector. + pub g1_crs: Vec, +} + +impl KZG10Verifier { + pub fn from( + vk: &VerifierKey, + crs: &[G1Affine], + pragma: Option, + sdpx: Option, + ) -> KZG10Verifier { + let g1_string_repr = g1_to_fq_repr(vk.g); + let g2_string_repr = g2_to_fq_repr(vk.h); + let vk_string_repr = g2_to_fq_repr(vk.beta_h); + let g1_crs_len = crs.len(); + let g1_crs = crs.iter().map(|g1| g1_to_fq_repr(*g1)).collect(); + let sdpx = sdpx.unwrap_or_default(); + let pragma_version = pragma.unwrap_or_default(); + KZG10Verifier { + sdpx, + pragma_version, + g1: g1_string_repr, + g2: g2_string_repr, + vk: vk_string_repr, + g1_crs, + g1_crs_len, + } + } +} + +#[derive(Template)] +#[template(path = "kzg10_groth16_decider_verifier.askama.sol", ext = "sol")] +pub struct Groth16KZG10DeciderVerifier { + pub groth16_verifier: Groth16Verifier, + pub kzg10_verifier: KZG10Verifier, +} + +impl Deref for Groth16KZG10DeciderVerifier { + type Target = Groth16Verifier; + + fn deref(&self) -> &Self::Target { + &self.groth16_verifier + } +} diff --git a/folding-schemes-solidity/templates/groth16_verifier.askama.sol b/folding-schemes-solidity/templates/groth16_verifier.askama.sol new file mode 100644 index 0000000..86cf648 --- /dev/null +++ b/folding-schemes-solidity/templates/groth16_verifier.askama.sol @@ -0,0 +1,172 @@ +{{ sdpx }} +/* + Copyright 2021 0KIMS association. + + * `folding-schemes-solidity` added comment + This file is a template built out of [snarkJS](https://github.com/iden3/snarkjs) groth16 verifier. + See the original ejs template [here](https://github.com/iden3/snarkjs/blob/master/templates/verifier_groth16.sol.ejs) + * + + snarkJS is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + snarkJS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with snarkJS. If not, see . +*/ + +{{ pragma_version }} + +contract Groth16Verifier { + // Scalar field size + uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + // Verification Key data + uint256 constant alphax = {{ vkey_alpha_g1.0[0] }}; + uint256 constant alphay = {{ vkey_alpha_g1.0[1] }}; + uint256 constant betax1 = {{ vkey_beta_g2.0[0][1] }}; + uint256 constant betax2 = {{ vkey_beta_g2.0[0][0] }}; + uint256 constant betay1 = {{ vkey_beta_g2.0[1][1] }}; + uint256 constant betay2 = {{ vkey_beta_g2.0[1][0] }}; + uint256 constant gammax1 = {{ vkey_gamma_g2.0[0][1] }}; + uint256 constant gammax2 = {{ vkey_gamma_g2.0[0][0] }}; + uint256 constant gammay1 = {{ vkey_gamma_g2.0[1][1] }}; + uint256 constant gammay2 = {{ vkey_gamma_g2.0[1][0] }}; + uint256 constant deltax1 = {{ vkey_delta_g2.0[0][1] }}; + uint256 constant deltax2 = {{ vkey_delta_g2.0[0][0] }}; + uint256 constant deltay1 = {{ vkey_delta_g2.0[1][1] }}; + uint256 constant deltay2 = {{ vkey_delta_g2.0[1][0] }}; + + {% for (i, point) in gamma_abc_g1.iter().enumerate() %} + uint256 constant IC{{i}}x = {{ point.0[0] }}; + uint256 constant IC{{i}}y = {{ point.0[1] }}; + {% endfor %} + + // Memory data + uint16 constant pVk = 0; + uint16 constant pPairing = 128; + + uint16 constant pLastMem = 896; + + function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[{{ gamma_abc_len - 1 }}] calldata _pubSignals) public view returns (bool) { + assembly { + function checkField(v) { + if iszero(lt(v, q)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + function g1_mulAccC(pR, x, y, s) { + let success + let mIn := mload(0x40) + mstore(mIn, x) + mstore(add(mIn, 32), y) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk { + let _pPairing := add(pMem, pPairing) + let _pVk := add(pMem, pVk) + + mstore(_pVk, IC0x) + mstore(add(_pVk, 32), IC0y) + + // Compute the linear combination vk_x + {% for (i, _) in gamma_abc_g1.iter().enumerate() %} + {% if loop.first -%} + {%- else -%} + g1_mulAccC(_pVk, IC{{i}}x, IC{{i}}y, calldataload(add(pubSignals, {{(i-1)*32}}))) + {%- endif -%} + {% endfor %} + + // -A + mstore(_pPairing, calldataload(pA)) + mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q)) + + // B + mstore(add(_pPairing, 64), calldataload(pB)) + mstore(add(_pPairing, 96), calldataload(add(pB, 32))) + mstore(add(_pPairing, 128), calldataload(add(pB, 64))) + mstore(add(_pPairing, 160), calldataload(add(pB, 96))) + + // alpha1 + mstore(add(_pPairing, 192), alphax) + mstore(add(_pPairing, 224), alphay) + + // beta2 + mstore(add(_pPairing, 256), betax1) + mstore(add(_pPairing, 288), betax2) + mstore(add(_pPairing, 320), betay1) + mstore(add(_pPairing, 352), betay2) + + // vk_x + mstore(add(_pPairing, 384), mload(add(pMem, pVk))) + mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32)))) + + + // gamma2 + mstore(add(_pPairing, 448), gammax1) + mstore(add(_pPairing, 480), gammax2) + mstore(add(_pPairing, 512), gammay1) + mstore(add(_pPairing, 544), gammay2) + + // C + mstore(add(_pPairing, 576), calldataload(pC)) + mstore(add(_pPairing, 608), calldataload(add(pC, 32))) + + // delta2 + mstore(add(_pPairing, 640), deltax1) + mstore(add(_pPairing, 672), deltax2) + mstore(add(_pPairing, 704), deltay1) + mstore(add(_pPairing, 736), deltay2) + + + let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20) + + isOk := and(success, mload(_pPairing)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, pLastMem)) + + // Validate that all evaluations ∈ F + {% for (i, _) in gamma_abc_g1.iter().enumerate() %} + checkField(calldataload(add(_pubSignals, {{i*32}}))) + {% endfor %} + + // Validate all evaluations + let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem) + + mstore(0, isValid) + + return(0, 0x20) + } + } +} \ No newline at end of file diff --git a/folding-schemes-solidity/templates/kzg10_groth16_decider_verifier.askama.sol b/folding-schemes-solidity/templates/kzg10_groth16_decider_verifier.askama.sol new file mode 100644 index 0000000..a46461e --- /dev/null +++ b/folding-schemes-solidity/templates/kzg10_groth16_decider_verifier.askama.sol @@ -0,0 +1,20 @@ +pragma solidity ^0.8.4; + +{{ groth16_verifier }} + +{{ kzg10_verifier }} + +/** + * @author PSE & 0xPARC + * @title NovaDecider contract, for verifying zk-snarks Nova IVC proofs. + * @dev This is an askama template. It will feature a snarkjs groth16 and a kzg10 verifier, from which this contract inherits. + */ +contract NovaDecider is Groth16Verifier, KZG10Verifier { + function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[{{ gamma_abc_len - 1 }}] calldata _pubSignals, uint256[2] calldata c, uint256[2] calldata pi, uint256 x, uint256 y) public view returns (bool) { + require(super.verifyProof(_pA, _pB, _pC, _pubSignals) == true, "Groth16 verification failed"); + // for now, we do not relate the Groth16 and KZG10 proofs + // this will done in the future, by computing challenge points from the groth16 proof's data + require(super.check(c, pi, x, y) == true, "KZG10 verification failed"); + return true; + } +} \ No newline at end of file diff --git a/folding-schemes-solidity/templates/kzg10_verifier.askama.sol b/folding-schemes-solidity/templates/kzg10_verifier.askama.sol new file mode 100644 index 0000000..89b11e7 --- /dev/null +++ b/folding-schemes-solidity/templates/kzg10_verifier.askama.sol @@ -0,0 +1,275 @@ +{{ sdpx }} + +{{ pragma_version }} + +/** + * @author Privacy and Scaling Explorations team - pse.dev + * @dev Contains utility functions for ops in BN254; in G_1 mostly. + * @notice Forked from https://github.com/weijiekoh/libkzg/tree/master. + * Among others, a few of the changes we did on this fork were: + * - Templating the pragma version + * - Removing type wrappers and use uints instead + * - Performing changes on arg types + * - Update some of the `require` statements + * - Use the bn254 scalar field instead of checking for overflow on the babyjub prime + * - In batch checking, we compute auxiliary polynomials and their commitments at the same time. + */ +contract KZG10Verifier { + + // prime of field F_p over which y^2 = x^3 + 3 is defined + uint256 public constant BN254_PRIME_FIELD = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; + uint256 public constant BN254_SCALAR_FIELD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + + /** + * @notice Performs scalar multiplication in G_1. + * @param p G_1 point to multiply + * @param s Scalar to multiply by + * @return r G_1 point p multiplied by scalar s + */ + function mulScalar(uint256[2] memory p, uint256 s) internal view returns (uint256[2] memory r) { + uint256[3] memory input; + input[0] = p[0]; + input[1] = p[1]; + input[2] = s; + bool success; + assembly { + success := staticcall(sub(gas(), 2000), 7, input, 0x60, r, 0x40) + switch success + case 0 { invalid() } + } + require(success, "bn254: scalar mul failed"); + } + + /** + * @notice Negates a point in G_1. + * @param p G_1 point to negate + * @return uint256[2] G_1 point -p + */ + function negate(uint256[2] memory p) internal pure returns (uint256[2] memory) { + if (p[0] == 0 && p[1] == 0) { + return p; + } + return [p[0], BN254_PRIME_FIELD - (p[1] % BN254_PRIME_FIELD)]; + } + + /** + * @notice Adds two points in G_1. + * @param p1 G_1 point 1 + * @param p2 G_1 point 2 + * @return r G_1 point p1 + p2 + */ + function add(uint256[2] memory p1, uint256[2] memory p2) internal view returns (uint256[2] memory r) { + bool success; + uint256[4] memory input = [p1[0], p1[1], p2[0], p2[1]]; + assembly { + success := staticcall(sub(gas(), 2000), 6, input, 0x80, r, 0x40) + switch success + case 0 { invalid() } + } + + require(success, "bn254: point add failed"); + } + + /** + * @notice Computes the pairing check e(p1, p2) * e(p3, p4) == 1 + * @dev Note that G_2 points a*i + b are encoded as two elements of F_p, (a, b) + * @param a_1 G_1 point 1 + * @param a_2 G_2 point 1 + * @param b_1 G_1 point 2 + * @param b_2 G_2 point 2 + * @return result true if pairing check is successful + */ + function pairing(uint256[2] memory a_1, uint256[2][2] memory a_2, uint256[2] memory b_1, uint256[2][2] memory b_2) + internal + view + returns (bool result) + { + uint256[12] memory input = [ + a_1[0], + a_1[1], + a_2[0][1], // imaginary part first + a_2[0][0], + a_2[1][1], // imaginary part first + a_2[1][0], + b_1[0], + b_1[1], + b_2[0][1], // imaginary part first + b_2[0][0], + b_2[1][1], // imaginary part first + b_2[1][0] + ]; + + uint256[1] memory out; + bool success; + + assembly { + success := staticcall(sub(gas(), 2000), 8, input, 0x180, out, 0x20) + switch success + case 0 { invalid() } + } + + require(success, "bn254: pairing failed"); + + return out[0] == 1; + } + + uint256[2] G_1 = [ + {{ g1.0[0] }}, + {{ g1.0[1] }} + ]; + uint256[2][2] G_2 = [ + [ + {{ g2.0[0][0] }}, + {{ g2.0[0][1] }} + ], + [ + {{ g2.0[1][0] }}, + {{ g2.0[1][1] }} + ] + ]; + uint256[2][2] VK = [ + [ + {{ vk.0[0][0] }}, + {{ vk.0[0][1] }} + ], + [ + {{ vk.0[1][0] }}, + {{ vk.0[1][1] }} + ] + ]; + + uint256[2][{{ g1_crs_len }}] G1_CRS = [ + {%- for (i, point) in g1_crs.iter().enumerate() %} + [ + {{ point.0[0] }}, + {{ point.0[1] }} + {% if loop.last -%} + ] + {%- else -%} + ], + {%- endif -%} + {% endfor -%} + ]; + + /** + * @notice Verifies a single point evaluation proof. Function name follows `ark-poly`. + * @dev To avoid ops in G_2, we slightly tweak how the verification is done. + * @param c G_1 point commitment to polynomial. + * @param pi G_1 point proof. + * @param x Value to prove evaluation of polynomial at. + * @param y Evaluation poly(x). + * @return result Indicates if KZG proof is correct. + */ + function check(uint256[2] calldata c, uint256[2] calldata pi, uint256 x, uint256 y) + public + view + returns (bool result) + { + // + // we want to: + // 1. avoid gas intensive ops in G2 + // 2. format the pairing check in line with what the evm opcode expects. + // + // we can do this by tweaking the KZG check to be: + // + // e(pi, vk - x * g2) = e(c - y * g1, g2) [initial check] + // e(pi, vk - x * g2) * e(c - y * g1, g2)^{-1} = 1 + // e(pi, vk - x * g2) * e(-c + y * g1, g2) = 1 [bilinearity of pairing for all subsequent steps] + // e(pi, vk) * e(pi, -x * g2) * e(-c + y * g1, g2) = 1 + // e(pi, vk) * e(-x * pi, g2) * e(-c + y * g1, g2) = 1 + // e(pi, vk) * e(x * -pi - c + y * g1, g2) = 1 [done] + // |_ rhs_pairing _| + // + uint256[2] memory rhs_pairing = + add(mulScalar(negate(pi), x), add(negate(c), mulScalar(G_1, y))); + return pairing(pi, VK, rhs_pairing, G_2); + } + + function evalPolyAt(uint256[] memory _coefficients, uint256 _index) public pure returns (uint256) { + uint256 m = BN254_SCALAR_FIELD; + uint256 result = 0; + uint256 powerOfX = 1; + + for (uint256 i = 0; i < _coefficients.length; i++) { + uint256 coeff = _coefficients[i]; + assembly { + result := addmod(result, mulmod(powerOfX, coeff, m), m) + powerOfX := mulmod(powerOfX, _index, m) + } + } + return result; + } + + /** + * @notice Ensures that z(x) == 0 and l(x) == y for all x in x_vals and y in y_vals. It returns the commitment to z(x) and l(x). + * @param z_coeffs coefficients of the zero polynomial z(x) = (x - x_1)(x - x_2)...(x - x_n). + * @param l_coeffs coefficients of the lagrange polynomial l(x). + * @param x_vals x values to evaluate the polynomials at. + * @param y_vals y values to which l(x) should evaluate to. + * @return uint256[2] commitment to z(x). + * @return uint256[2] commitment to l(x). + */ + function checkAndCommitAuxPolys( + uint256[] memory z_coeffs, + uint256[] memory l_coeffs, + uint256[] memory x_vals, + uint256[] memory y_vals + ) public view returns (uint256[2] memory, uint256[2] memory) { + // z(x) is of degree len(x_vals), it is a product of linear polynomials (x - x_i) + // l(x) is of degree len(x_vals) - 1 + uint256[2] memory z_commit; + uint256[2] memory l_commit; + for (uint256 i = 0; i < x_vals.length; i++) { + z_commit = add(z_commit, mulScalar(G1_CRS[i], z_coeffs[i])); // update commitment to z(x) + l_commit = add(l_commit, mulScalar(G1_CRS[i], l_coeffs[i])); // update commitment to l(x) + + uint256 eval_z = evalPolyAt(z_coeffs, x_vals[i]); + uint256 eval_l = evalPolyAt(l_coeffs, x_vals[i]); + + require(eval_z == 0, "checkAndCommitAuxPolys: wrong zero poly"); + require(eval_l == y_vals[i], "checkAndCommitAuxPolys: wrong lagrange poly"); + } + // z(x) has len(x_vals) + 1 coeffs, we add to the commmitment the last coeff of z(x) + z_commit = add(z_commit, mulScalar(G1_CRS[z_coeffs.length - 1], z_coeffs[z_coeffs.length - 1])); + + return (z_commit, l_commit); + } + + /** + * @notice Verifies a batch of point evaluation proofs. Function name follows `ark-poly`. + * @dev To avoid ops in G_2, we slightly tweak how the verification is done. + * @param c G1 point commitment to polynomial. + * @param pi G2 point proof. + * @param x_vals Values to prove evaluation of polynomial at. + * @param y_vals Evaluation poly(x). + * @param l_coeffs Coefficients of the lagrange polynomial. + * @param z_coeffs Coefficients of the zero polynomial z(x) = (x - x_1)(x - x_2)...(x - x_n). + * @return result Indicates if KZG proof is correct. + */ + function batchCheck( + uint256[2] calldata c, + uint256[2][2] calldata pi, + uint256[] calldata x_vals, + uint256[] calldata y_vals, + uint256[] calldata l_coeffs, + uint256[] calldata z_coeffs + ) public view returns (bool result) { + // + // we want to: + // 1. avoid gas intensive ops in G2 + // 2. format the pairing check in line with what the evm opcode expects. + // + // we can do this by tweaking the KZG check to be: + // + // e(z(r) * g1, pi) * e(g1, l(r) * g2) = e(c, g2) [initial check] + // e(z(r) * g1, pi) * e(l(r) * g1, g2) * e(c, g2)^{-1} = 1 [bilinearity of pairing] + // e(z(r) * g1, pi) * e(l(r) * g1 - c, g2) = 1 [done] + // + (uint256[2] memory z_commit, uint256[2] memory l_commit) = + checkAndCommitAuxPolys(z_coeffs, l_coeffs, x_vals, y_vals); + uint256[2] memory neg_commit = negate(c); + return pairing(z_commit, pi, add(l_commit, neg_commit), G_2); + } +} diff --git a/folding-schemes/Cargo.toml b/folding-schemes/Cargo.toml new file mode 100644 index 0000000..c1bd195 --- /dev/null +++ b/folding-schemes/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "folding-schemes" +version = "0.1.0" +edition = "2021" + +[dependencies] +ark-ec = "^0.4.0" +ark-ff = "^0.4.0" +ark-poly = "^0.4.0" +ark-std = "^0.4.0" +ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["r1cs", "sponge", "crh"] } +ark-poly-commit = "^0.4.0" +ark-relations = { version = "^0.4.0", default-features = false } +ark-r1cs-std = { version = "0.4.0", default-features = false } # this is patched at the workspace level +ark-snark = { version = "^0.4.0"} +ark-serialize = "^0.4.0" +ark-circom = { git = "https://github.com/gakonst/ark-circom.git" } +thiserror = "1.0" +rayon = "1.7.0" +num-bigint = "0.4" +color-eyre = "=0.6.2" + +# tmp imports for espresso's sumcheck +espresso_subroutines = {git="https://github.com/EspressoSystems/hyperplonk", package="subroutines"} + +[dev-dependencies] +ark-pallas = {version="0.4.0", features=["r1cs"]} +ark-vesta = {version="0.4.0", features=["r1cs"]} +ark-bn254 = "0.4.0" +ark-mnt4-298 = {version="0.4.0", features=["r1cs"]} +ark-mnt6-298 = {version="0.4.0", features=["r1cs"]} +ark-groth16 = { version = "^0.4.0" } +rand = "0.8.5" +tracing = { version = "0.1", default-features = false, features = [ "attributes" ] } +tracing-subscriber = { version = "0.2" } + +[features] +default = ["parallel"] + +parallel = [ + "ark-std/parallel", + "ark-ff/parallel", + "ark-ec/parallel", + "ark-poly/parallel", + "ark-crypto-primitives/parallel", + "ark-r1cs-std/parallel", + ] + diff --git a/examples/fold_sha256.rs b/folding-schemes/examples/fold_sha256.rs similarity index 100% rename from examples/fold_sha256.rs rename to folding-schemes/examples/fold_sha256.rs diff --git a/src/ccs/mod.rs b/folding-schemes/src/ccs/mod.rs similarity index 100% rename from src/ccs/mod.rs rename to folding-schemes/src/ccs/mod.rs diff --git a/src/ccs/r1cs.rs b/folding-schemes/src/ccs/r1cs.rs similarity index 100% rename from src/ccs/r1cs.rs rename to folding-schemes/src/ccs/r1cs.rs diff --git a/src/commitment/kzg.rs b/folding-schemes/src/commitment/kzg.rs similarity index 100% rename from src/commitment/kzg.rs rename to folding-schemes/src/commitment/kzg.rs diff --git a/src/commitment/mod.rs b/folding-schemes/src/commitment/mod.rs similarity index 100% rename from src/commitment/mod.rs rename to folding-schemes/src/commitment/mod.rs diff --git a/src/commitment/pedersen.rs b/folding-schemes/src/commitment/pedersen.rs similarity index 100% rename from src/commitment/pedersen.rs rename to folding-schemes/src/commitment/pedersen.rs diff --git a/src/constants.rs b/folding-schemes/src/constants.rs similarity index 100% rename from src/constants.rs rename to folding-schemes/src/constants.rs diff --git a/src/folding/circuits/mod.rs b/folding-schemes/src/folding/circuits/mod.rs similarity index 100% rename from src/folding/circuits/mod.rs rename to folding-schemes/src/folding/circuits/mod.rs diff --git a/src/folding/circuits/nonnative.rs b/folding-schemes/src/folding/circuits/nonnative.rs similarity index 100% rename from src/folding/circuits/nonnative.rs rename to folding-schemes/src/folding/circuits/nonnative.rs diff --git a/src/folding/circuits/sum_check.rs b/folding-schemes/src/folding/circuits/sum_check.rs similarity index 100% rename from src/folding/circuits/sum_check.rs rename to folding-schemes/src/folding/circuits/sum_check.rs diff --git a/src/folding/circuits/utils.rs b/folding-schemes/src/folding/circuits/utils.rs similarity index 100% rename from src/folding/circuits/utils.rs rename to folding-schemes/src/folding/circuits/utils.rs diff --git a/src/folding/hypernova/cccs.rs b/folding-schemes/src/folding/hypernova/cccs.rs similarity index 100% rename from src/folding/hypernova/cccs.rs rename to folding-schemes/src/folding/hypernova/cccs.rs diff --git a/src/folding/hypernova/circuit.rs b/folding-schemes/src/folding/hypernova/circuit.rs similarity index 100% rename from src/folding/hypernova/circuit.rs rename to folding-schemes/src/folding/hypernova/circuit.rs diff --git a/src/folding/hypernova/lcccs.rs b/folding-schemes/src/folding/hypernova/lcccs.rs similarity index 100% rename from src/folding/hypernova/lcccs.rs rename to folding-schemes/src/folding/hypernova/lcccs.rs diff --git a/src/folding/hypernova/mod.rs b/folding-schemes/src/folding/hypernova/mod.rs similarity index 100% rename from src/folding/hypernova/mod.rs rename to folding-schemes/src/folding/hypernova/mod.rs diff --git a/src/folding/hypernova/nimfs.rs b/folding-schemes/src/folding/hypernova/nimfs.rs similarity index 100% rename from src/folding/hypernova/nimfs.rs rename to folding-schemes/src/folding/hypernova/nimfs.rs diff --git a/src/folding/hypernova/utils.rs b/folding-schemes/src/folding/hypernova/utils.rs similarity index 100% rename from src/folding/hypernova/utils.rs rename to folding-schemes/src/folding/hypernova/utils.rs diff --git a/src/folding/mod.rs b/folding-schemes/src/folding/mod.rs similarity index 100% rename from src/folding/mod.rs rename to folding-schemes/src/folding/mod.rs diff --git a/src/folding/nova/circuits.rs b/folding-schemes/src/folding/nova/circuits.rs similarity index 100% rename from src/folding/nova/circuits.rs rename to folding-schemes/src/folding/nova/circuits.rs diff --git a/src/folding/nova/cyclefold.rs b/folding-schemes/src/folding/nova/cyclefold.rs similarity index 100% rename from src/folding/nova/cyclefold.rs rename to folding-schemes/src/folding/nova/cyclefold.rs diff --git a/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs similarity index 100% rename from src/folding/nova/decider_eth.rs rename to folding-schemes/src/folding/nova/decider_eth.rs diff --git a/src/folding/nova/decider_eth_circuit.rs b/folding-schemes/src/folding/nova/decider_eth_circuit.rs similarity index 100% rename from src/folding/nova/decider_eth_circuit.rs rename to folding-schemes/src/folding/nova/decider_eth_circuit.rs diff --git a/src/folding/nova/mod.rs b/folding-schemes/src/folding/nova/mod.rs similarity index 100% rename from src/folding/nova/mod.rs rename to folding-schemes/src/folding/nova/mod.rs diff --git a/src/folding/nova/nifs.rs b/folding-schemes/src/folding/nova/nifs.rs similarity index 100% rename from src/folding/nova/nifs.rs rename to folding-schemes/src/folding/nova/nifs.rs diff --git a/src/folding/nova/traits.rs b/folding-schemes/src/folding/nova/traits.rs similarity index 100% rename from src/folding/nova/traits.rs rename to folding-schemes/src/folding/nova/traits.rs diff --git a/src/folding/protogalaxy/folding.rs b/folding-schemes/src/folding/protogalaxy/folding.rs similarity index 100% rename from src/folding/protogalaxy/folding.rs rename to folding-schemes/src/folding/protogalaxy/folding.rs diff --git a/src/folding/protogalaxy/mod.rs b/folding-schemes/src/folding/protogalaxy/mod.rs similarity index 100% rename from src/folding/protogalaxy/mod.rs rename to folding-schemes/src/folding/protogalaxy/mod.rs diff --git a/src/folding/protogalaxy/traits.rs b/folding-schemes/src/folding/protogalaxy/traits.rs similarity index 100% rename from src/folding/protogalaxy/traits.rs rename to folding-schemes/src/folding/protogalaxy/traits.rs diff --git a/src/folding/protogalaxy/utils.rs b/folding-schemes/src/folding/protogalaxy/utils.rs similarity index 100% rename from src/folding/protogalaxy/utils.rs rename to folding-schemes/src/folding/protogalaxy/utils.rs diff --git a/src/frontend/circom/mod.rs b/folding-schemes/src/frontend/circom/mod.rs similarity index 100% rename from src/frontend/circom/mod.rs rename to folding-schemes/src/frontend/circom/mod.rs diff --git a/folding-schemes/src/frontend/circom/test_folder/compile.sh b/folding-schemes/src/frontend/circom/test_folder/compile.sh new file mode 100644 index 0000000..2db5715 --- /dev/null +++ b/folding-schemes/src/frontend/circom/test_folder/compile.sh @@ -0,0 +1,2 @@ +#!/bin/bash +circom ./folding-schemes/src/frontend/circom/test_folder/test_circuit.circom --r1cs --wasm --prime bn128 --output ./folding-schemes/src/frontend/circom/test_folder/ \ No newline at end of file diff --git a/src/frontend/circom/test_folder/test_circuit.circom b/folding-schemes/src/frontend/circom/test_folder/test_circuit.circom similarity index 100% rename from src/frontend/circom/test_folder/test_circuit.circom rename to folding-schemes/src/frontend/circom/test_folder/test_circuit.circom diff --git a/src/frontend/mod.rs b/folding-schemes/src/frontend/mod.rs similarity index 100% rename from src/frontend/mod.rs rename to folding-schemes/src/frontend/mod.rs diff --git a/src/lib.rs b/folding-schemes/src/lib.rs similarity index 100% rename from src/lib.rs rename to folding-schemes/src/lib.rs diff --git a/src/transcript/mod.rs b/folding-schemes/src/transcript/mod.rs similarity index 100% rename from src/transcript/mod.rs rename to folding-schemes/src/transcript/mod.rs diff --git a/src/transcript/poseidon.rs b/folding-schemes/src/transcript/poseidon.rs similarity index 100% rename from src/transcript/poseidon.rs rename to folding-schemes/src/transcript/poseidon.rs diff --git a/src/utils/bit.rs b/folding-schemes/src/utils/bit.rs similarity index 100% rename from src/utils/bit.rs rename to folding-schemes/src/utils/bit.rs diff --git a/src/utils/espresso/mod.rs b/folding-schemes/src/utils/espresso/mod.rs similarity index 100% rename from src/utils/espresso/mod.rs rename to folding-schemes/src/utils/espresso/mod.rs diff --git a/src/utils/espresso/multilinear_polynomial.rs b/folding-schemes/src/utils/espresso/multilinear_polynomial.rs similarity index 100% rename from src/utils/espresso/multilinear_polynomial.rs rename to folding-schemes/src/utils/espresso/multilinear_polynomial.rs diff --git a/src/utils/espresso/sum_check/mod.rs b/folding-schemes/src/utils/espresso/sum_check/mod.rs similarity index 100% rename from src/utils/espresso/sum_check/mod.rs rename to folding-schemes/src/utils/espresso/sum_check/mod.rs diff --git a/src/utils/espresso/sum_check/prover.rs b/folding-schemes/src/utils/espresso/sum_check/prover.rs similarity index 100% rename from src/utils/espresso/sum_check/prover.rs rename to folding-schemes/src/utils/espresso/sum_check/prover.rs diff --git a/src/utils/espresso/sum_check/structs.rs b/folding-schemes/src/utils/espresso/sum_check/structs.rs similarity index 100% rename from src/utils/espresso/sum_check/structs.rs rename to folding-schemes/src/utils/espresso/sum_check/structs.rs diff --git a/src/utils/espresso/sum_check/verifier.rs b/folding-schemes/src/utils/espresso/sum_check/verifier.rs similarity index 100% rename from src/utils/espresso/sum_check/verifier.rs rename to folding-schemes/src/utils/espresso/sum_check/verifier.rs diff --git a/src/utils/espresso/virtual_polynomial.rs b/folding-schemes/src/utils/espresso/virtual_polynomial.rs similarity index 100% rename from src/utils/espresso/virtual_polynomial.rs rename to folding-schemes/src/utils/espresso/virtual_polynomial.rs diff --git a/src/utils/gadgets.rs b/folding-schemes/src/utils/gadgets.rs similarity index 100% rename from src/utils/gadgets.rs rename to folding-schemes/src/utils/gadgets.rs diff --git a/src/utils/hypercube.rs b/folding-schemes/src/utils/hypercube.rs similarity index 100% rename from src/utils/hypercube.rs rename to folding-schemes/src/utils/hypercube.rs diff --git a/src/utils/lagrange_poly.rs b/folding-schemes/src/utils/lagrange_poly.rs similarity index 100% rename from src/utils/lagrange_poly.rs rename to folding-schemes/src/utils/lagrange_poly.rs diff --git a/src/utils/mle.rs b/folding-schemes/src/utils/mle.rs similarity index 100% rename from src/utils/mle.rs rename to folding-schemes/src/utils/mle.rs diff --git a/src/utils/mod.rs b/folding-schemes/src/utils/mod.rs similarity index 100% rename from src/utils/mod.rs rename to folding-schemes/src/utils/mod.rs diff --git a/src/utils/vec.rs b/folding-schemes/src/utils/vec.rs similarity index 100% rename from src/utils/vec.rs rename to folding-schemes/src/utils/vec.rs diff --git a/src/frontend/circom/test_folder/compile.sh b/src/frontend/circom/test_folder/compile.sh deleted file mode 100644 index 49c4412..0000000 --- a/src/frontend/circom/test_folder/compile.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -circom ./src/frontend/circom/test_folder/test_circuit.circom --r1cs --wasm --prime bn128 --output ./src/frontend/circom/test_folder/ \ No newline at end of file