diff --git a/Cargo.toml b/Cargo.toml index 11a37363..66f6352f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,11 +25,11 @@ ark-bls12-377 = { version = "0.4.0", features = ["r1cs","curve"] } ark-bls12-381 = { version = "0.4.0", features = ["curve"] } ark-blst = { git = "https://github.com/nikkolasg/ark-blst" } ark-serialize = { version = "0.4.0", features = ["derive"] } -ark-crypto-primitives = {version = "0.4.0", features = ["sponge","r1cs","snark"] } +ark-crypto-primitives = {version = "^0.4.0", features = ["sponge","r1cs","snark"] } ark-r1cs-std = { version = "0.4.0", default-features = false } ark-relations = { version = "0.4.0", default-features = false, optional = true } ark-snark = { version = "0.4.0", default-features = false } -ark-groth16 = { version = "0.3.0" } +ark-groth16 = { version = "0.4.0", features = ["r1cs"] } ark-bw6-761 = { version = "0.4.0" } ark-poly-commit = { version = "0.4.0" } ark-poly = {version = "0.4.0"} @@ -47,6 +47,7 @@ tracing-subscriber = { version = "0.2" } [dev-dependencies] +rand_chacha = { version = "0.3.0", default-features = false } serde = { version = "1.0", features = ["derive"] } csv = "1.1.5" criterion = "0.3.6" @@ -67,6 +68,10 @@ harness = false name = "pst" harness = false +[[bench]] +name = "testudo_comm" +harness = false + [features] multicore = ["rayon"] profile = [] diff --git a/benches/pst.rs b/benches/pst.rs index a9b821a0..ea9727b2 100644 --- a/benches/pst.rs +++ b/benches/pst.rs @@ -1,98 +1,99 @@ -use std::time::Instant; - -use ark_poly_commit::multilinear_pc::MultilinearPC; -use ark_serialize::CanonicalSerialize; -use libtestudo::{ - parameters::PoseidonConfiguration, poseidon_transcript::PoseidonTranscript, sqrt_pst::Polynomial, -}; -use serde::Serialize; -type F = ark_bls12_377::Fr; -type E = ark_bls12_377::Bls12_377; -use ark_std::UniformRand; - -#[derive(Default, Clone, Serialize)] -struct BenchmarkResults { - power: usize, - commit_time: u128, - opening_time: u128, - verification_time: u128, - proof_size: usize, - commiter_key_size: usize, -} -fn main() { - let params = ark_bls12_377::Fr::poseidon_params(); - - let mut writer = csv::Writer::from_path("sqrt_pst.csv").expect("unable to open csv writer"); - for &s in [4, 5, 20, 27].iter() { - println!("Running for {} inputs", s); - let mut rng = ark_std::test_rng(); - let mut br = BenchmarkResults::default(); - br.power = s; - let num_vars = s; - let len = 2_usize.pow(num_vars as u32); - let z: Vec = (0..len).into_iter().map(|_| F::rand(&mut rng)).collect(); - let r: Vec = (0..num_vars) - .into_iter() - .map(|_| F::rand(&mut rng)) - .collect(); - - let setup_vars = (num_vars as f32 / 2.0).ceil() as usize; - let gens = MultilinearPC::::setup((num_vars as f32 / 2.0).ceil() as usize, &mut rng); - let (ck, vk) = MultilinearPC::::trim(&gens, setup_vars); - - let mut cks = Vec::::new(); - ck.serialize_with_mode(&mut cks, ark_serialize::Compress::Yes) - .unwrap(); - br.commiter_key_size = cks.len(); - - let mut pl = Polynomial::from_evaluations(&z.clone()); - - let v = pl.eval(&r); - - let start = Instant::now(); - let (comm_list, t) = pl.commit(&ck); - let duration = start.elapsed().as_millis(); - br.commit_time = duration; - - let mut prover_transcript = PoseidonTranscript::new(¶ms); - - let start = Instant::now(); - let (u, pst_proof, mipp_proof) = pl.open(&mut prover_transcript, comm_list, &ck, &r, &t); - let duration = start.elapsed().as_millis(); - br.opening_time = duration; - - let mut p1 = Vec::::new(); - let mut p2 = Vec::::new(); - pst_proof - .serialize_with_mode(&mut p1, ark_serialize::Compress::Yes) - .unwrap(); - - mipp_proof - .serialize_with_mode(&mut p2, ark_serialize::Compress::Yes) - .unwrap(); - - br.proof_size = p1.len() + p2.len(); - - let mut verifier_transcript = PoseidonTranscript::new(¶ms); - - let start = Instant::now(); - let res = Polynomial::verify( - &mut verifier_transcript, - &vk, - &u, - &r, - v, - &pst_proof, - &mipp_proof, - &t, - ); - let duration = start.elapsed().as_millis(); - br.verification_time = duration; - assert!(res == true); - - writer - .serialize(br) - .expect("unable to write results to csv"); - writer.flush().expect("wasn't able to flush"); - } -} +// use std::time::Instant; + +// use ark_poly_commit::multilinear_pc::MultilinearPC; +// use ark_serialize::CanonicalSerialize; +// use libtestudo::{ +// parameters::PoseidonConfiguration, poseidon_transcript::PoseidonTranscript, sqrt_pst::Polynomial, +// }; +// use serde::Serialize; +// type F = ark_bls12_377::Fr; +// type E = ark_bls12_377::Bls12_377; +// use ark_std::UniformRand; + +// #[derive(Default, Clone, Serialize)] +// struct BenchmarkResults { +// power: usize, +// commit_time: u128, +// opening_time: u128, +// verification_time: u128, +// proof_size: usize, +// commiter_key_size: usize, +// } +// fn main() { +// let params = ark_bls12_377::Fr::poseidon_params(); + +// let mut writer = csv::Writer::from_path("sqrt_pst.csv").expect("unable to open csv writer"); +// for &s in [4, 5, 20, 27].iter() { +// println!("Running for {} inputs", s); +// let mut rng = ark_std::test_rng(); +// let mut br = BenchmarkResults::default(); +// br.power = s; +// let num_vars = s; +// let len = 2_usize.pow(num_vars as u32); +// let z: Vec = (0..len).into_iter().map(|_| F::rand(&mut rng)).collect(); +// let r: Vec = (0..num_vars) +// .into_iter() +// .map(|_| F::rand(&mut rng)) +// .collect(); + +// let setup_vars = (num_vars as f32 / 2.0).ceil() as usize; +// let gens = MultilinearPC::::setup((num_vars as f32 / 2.0).ceil() as usize, &mut rng); +// let (ck, vk) = MultilinearPC::::trim(&gens, setup_vars); + +// let mut cks = Vec::::new(); +// ck.serialize_with_mode(&mut cks, ark_serialize::Compress::Yes) +// .unwrap(); +// br.commiter_key_size = cks.len(); + +// let mut pl = Polynomial::from_evaluations(&z.clone()); + +// let v = pl.eval(&r); + +// let start = Instant::now(); +// let (comm_list, t) = pl.commit(&ck); +// let duration = start.elapsed().as_millis(); +// br.commit_time = duration; + +// let mut prover_transcript = PoseidonTranscript::new(¶ms); + +// let start = Instant::now(); +// let (u, pst_proof, mipp_proof) = pl.open(&mut prover_transcript, comm_list, &ck, &r, &t); +// let duration = start.elapsed().as_millis(); +// br.opening_time = duration; + +// let mut p1 = Vec::::new(); +// let mut p2 = Vec::::new(); +// pst_proof +// .serialize_with_mode(&mut p1, ark_serialize::Compress::Yes) +// .unwrap(); + +// mipp_proof +// .serialize_with_mode(&mut p2, ark_serialize::Compress::Yes) +// .unwrap(); + +// br.proof_size = p1.len() + p2.len(); + +// let mut verifier_transcript = PoseidonTranscript::new(¶ms); + +// let start = Instant::now(); +// let res = Polynomial::verify( +// &mut verifier_transcript, +// &vk, +// &u, +// &r, +// v, +// &pst_proof, +// &mipp_proof, +// &t, +// ); +// let duration = start.elapsed().as_millis(); +// br.verification_time = duration; +// assert!(res == true); + +// writer +// .serialize(br) +// .expect("unable to write results to csv"); +// writer.flush().expect("wasn't able to flush"); +// } +// } +fn main() {} diff --git a/benches/testudo.rs b/benches/testudo.rs index bd9cc75a..9873d9b7 100644 --- a/benches/testudo.rs +++ b/benches/testudo.rs @@ -1,127 +1,129 @@ -use std::time::Instant; - -use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::pairing::Pairing; -use ark_ff::PrimeField; -use ark_serialize::*; -use libtestudo::parameters::PoseidonConfiguration; -use libtestudo::{ - poseidon_transcript::PoseidonTranscript, - testudo_snark::{TestudoSnark, TestudoSnarkGens}, - Instance, -}; -use serde::Serialize; - -#[derive(Default, Clone, Serialize)] -struct BenchmarkResults { - power: usize, - input_constraints: usize, - testudo_proving_time: u128, - testudo_verification_time: u128, - sat_proof_size: usize, - eval_proof_size: usize, - total_proof_size: usize, -} - -fn main() { - bench_with_bls12_377(); - // bench_with_bls12_381(); - // bench_with_ark_blst(); -} - -fn bench_with_ark_blst() { - let params = ark_blst::Scalar::poseidon_params(); - testudo_snark_bench::(params, "testudo_blst"); -} - -fn bench_with_bls12_377() { - let params = ark_bls12_377::Fr::poseidon_params(); - testudo_snark_bench::(params, "testudo_bls12_377"); -} - -fn bench_with_bls12_381() { - let params = ark_bls12_381::Fr::poseidon_params(); - testudo_snark_bench::(params, "testudo_bls12_381"); -} - -fn testudo_snark_bench(params: PoseidonConfig, file_name: &str) -where - E: Pairing, - E::ScalarField: PrimeField, - E::ScalarField: Absorb, -{ - let mut writer = csv::Writer::from_path(file_name).expect("unable to open csv writer"); - for &s in [4, 5, 10, 12, 14, 16, 18, 20, 22, 24, 26].iter() { - println!("Running for {} inputs", s); - let mut br = BenchmarkResults::default(); - let num_vars = (2_usize).pow(s as u32); - let num_cons = num_vars; - br.power = s; - br.input_constraints = num_cons; - let num_inputs = 10; - - let (inst, vars, inputs) = - Instance::::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); - let mut prover_transcript = PoseidonTranscript::new(¶ms.clone()); - - let gens = - TestudoSnarkGens::::setup(num_cons, num_vars, num_inputs, num_cons, params.clone()); - - let (comm, decomm) = TestudoSnark::::encode(&inst, &gens); - - let start = Instant::now(); - let proof = TestudoSnark::prove( - &inst, - &comm, - &decomm, - vars, - &inputs, - &gens, - &mut prover_transcript, - params.clone(), - ) - .unwrap(); - let duration = start.elapsed().as_millis(); - br.testudo_proving_time = duration; - - let mut sat_proof = Vec::::new(); - proof - .r1cs_verifier_proof - .serialize_with_mode(&mut sat_proof, Compress::Yes) - .unwrap(); - br.sat_proof_size = sat_proof.len(); - - let mut eval_proof = Vec::::new(); - proof - .r1cs_eval_proof - .serialize_with_mode(&mut eval_proof, Compress::Yes) - .unwrap(); - br.eval_proof_size = eval_proof.len(); - - let mut total_proof = Vec::::new(); - proof - .serialize_with_mode(&mut total_proof, Compress::Yes) - .unwrap(); - br.total_proof_size = total_proof.len(); - - let mut verifier_transcript = PoseidonTranscript::new(¶ms.clone()); - let start = Instant::now(); - - let res = proof.verify( - &gens, - &comm, - &inputs, - &mut verifier_transcript, - params.clone(), - ); - assert!(res.is_ok()); - let duration = start.elapsed().as_millis(); - br.testudo_verification_time = duration; - - writer - .serialize(br) - .expect("unable to write results to csv"); - writer.flush().expect("wasn't able to flush"); - } -} +// use std::time::Instant; + +// use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; +// use ark_crypto_primitives::sponge::Absorb; +// use ark_ec::pairing::Pairing; +// use ark_ff::PrimeField; +// use ark_serialize::*; +// use libtestudo::parameters::PoseidonConfiguration; +// use libtestudo::{ +// poseidon_transcript::PoseidonTranscript, +// testudo_snark::{TestudoSnark, TestudoSnarkGens}, +// Instance, +// }; +// use serde::Serialize; + +// #[derive(Default, Clone, Serialize)] +// struct BenchmarkResults { +// power: usize, +// input_constraints: usize, +// testudo_proving_time: u128, +// testudo_verification_time: u128, +// sat_proof_size: usize, +// eval_proof_size: usize, +// total_proof_size: usize, +// } + +// fn main() { +// bench_with_bls12_377(); +// // bench_with_bls12_381(); +// // bench_with_ark_blst(); +// } + +// fn bench_with_ark_blst() { +// let params = ark_blst::Scalar::poseidon_params(); +// testudo_snark_bench::(params, "testudo_blst"); +// } + +// fn bench_with_bls12_377() { +// let params = ark_bls12_377::Fr::poseidon_params(); +// testudo_snark_bench::(params, "testudo_bls12_377"); +// } + +// fn bench_with_bls12_381() { +// let params = ark_bls12_381::Fr::poseidon_params(); +// testudo_snark_bench::(params, "testudo_bls12_381"); +// } + +// fn testudo_snark_bench(params: PoseidonConfig, file_name: &str) +// where +// E: Pairing, +// E::ScalarField: PrimeField, +// E::ScalarField: Absorb, +// { +// let mut writer = csv::Writer::from_path(file_name).expect("unable to open csv writer"); +// for &s in [4, 5, 10, 12, 14, 16, 18, 20, 22, 24, 26].iter() { +// println!("Running for {} inputs", s); +// let mut br = BenchmarkResults::default(); +// let num_vars = (2_usize).pow(s as u32); +// let num_cons = num_vars; +// br.power = s; +// br.input_constraints = num_cons; +// let num_inputs = 10; + +// let (inst, vars, inputs) = +// Instance::::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); +// let mut prover_transcript = PoseidonTranscript::new(¶ms.clone()); + +// let gens = +// TestudoSnarkGens::::setup(num_cons, num_vars, num_inputs, num_cons, params.clone()); + +// let (comm, decomm) = TestudoSnark::::encode(&inst, &gens); + +// let start = Instant::now(); +// let proof = TestudoSnark::prove( +// &inst, +// &comm, +// &decomm, +// vars, +// &inputs, +// &gens, +// &mut prover_transcript, +// params.clone(), +// ) +// .unwrap(); +// let duration = start.elapsed().as_millis(); +// br.testudo_proving_time = duration; + +// let mut sat_proof = Vec::::new(); +// proof +// .r1cs_verifier_proof +// .serialize_with_mode(&mut sat_proof, Compress::Yes) +// .unwrap(); +// br.sat_proof_size = sat_proof.len(); + +// let mut eval_proof = Vec::::new(); +// proof +// .r1cs_eval_proof +// .serialize_with_mode(&mut eval_proof, Compress::Yes) +// .unwrap(); +// br.eval_proof_size = eval_proof.len(); + +// let mut total_proof = Vec::::new(); +// proof +// .serialize_with_mode(&mut total_proof, Compress::Yes) +// .unwrap(); +// br.total_proof_size = total_proof.len(); + +// let mut verifier_transcript = PoseidonTranscript::new(¶ms.clone()); +// let start = Instant::now(); + +// let res = proof.verify( +// &gens, +// &comm, +// &inputs, +// &mut verifier_transcript, +// params.clone(), +// ); +// assert!(res.is_ok()); +// let duration = start.elapsed().as_millis(); +// br.testudo_verification_time = duration; + +// writer +// .serialize(br) +// .expect("unable to write results to csv"); +// writer.flush().expect("wasn't able to flush"); +// } +// } + +fn main() {} diff --git a/benches/testudo_comm.rs b/benches/testudo_comm.rs new file mode 100644 index 00000000..e011373d --- /dev/null +++ b/benches/testudo_comm.rs @@ -0,0 +1,96 @@ +use ark_poly_commit::multilinear_pc::MultilinearPC; +use libtestudo::circuit_verifier::TestudoCommVerifier; +use libtestudo::{ + parameters::get_bls12377_fq_params, poseidon_transcript::PoseidonTranscript, sqrt_pst::Polynomial, +}; +use ark_std::time::Instant; +use ark_std::marker::PhantomData; +use serde::Serialize; +type F = ark_bls12_377::Fr; +type E = ark_bls12_377::Bls12_377; +use ark_std::UniformRand; +use ark_relations::r1cs::ConstraintSystem; +use ark_ec::bls12::Bls12; +use ark_ec::pairing::Pairing; +use ark_relations::r1cs::ConstraintSynthesizer; +use ark_std::rand::SeedableRng; +use ark_groth16::Groth16; +use ark_snark::SNARK; +use rand::rngs::OsRng; +#[derive(Default, Clone, Serialize)] +struct BenchmarkResults { + power: usize, + num_constraints: usize, + proving_time: u128, +} +fn main() { + let params = get_bls12377_fq_params(); + + let mut writer = csv::Writer::from_path("testudo_comm.csv").expect("unable to open csv writer"); + for &s in [5, 10, 15, 20, 25].iter() { + println!("Running for {} inputs", s); + let mut rng = ark_std::test_rng(); + let mut br = BenchmarkResults::default(); + br.power = s; + let num_vars = s; + let len = 2_usize.pow(num_vars as u32); + let z: Vec = (0..len).into_iter().map(|_| F::rand(&mut rng)).collect(); + let r: Vec = (0..num_vars) + .into_iter() + .map(|_| F::rand(&mut rng)) + .collect(); + + let setup_vars = (num_vars as f32 / 2.0).ceil() as usize; + let gens = MultilinearPC::::setup((num_vars as f32 / 2.0).ceil() as usize, &mut rng); + let (ck, vk) = MultilinearPC::::trim(&gens, setup_vars); + + let mut pl = Polynomial::from_evaluations(&z.clone()); + + let v = pl.eval(&r); + + let (comm_list, t) = pl.commit(&ck); + + let mut prover_transcript = PoseidonTranscript::new(&get_bls12377_fq_params()); + + let (u, pst_proof, mipp_proof) = pl.open(&mut prover_transcript, comm_list, &ck, &r, &t); + + let circuit = + TestudoCommVerifier:: { + params: get_bls12377_fq_params(), + vk, + U: u, + point: r, + v, + pst_proof, + mipp_proof, + T: t, + _iv: PhantomData, + }; + let cs = ConstraintSystem::< as Pairing>::BaseField>::new_ref(); + circuit.clone().generate_constraints(cs.clone()).unwrap(); + // assert!(cs.is_satisfied().unwrap()); + br.num_constraints = cs.num_constraints(); + + + let mut rng2 = rand_chacha::ChaChaRng::seed_from_u64(1776); + let (pk, vk) = Groth16::::circuit_specific_setup(circuit.clone(), &mut rng2).unwrap(); + + + let start = Instant::now(); + + let proof = Groth16::::prove(&pk, circuit.clone(), &mut OsRng).unwrap(); + + let duration = start.elapsed().as_millis(); + + br.proving_time = duration; + + + let ok = Groth16::::verify(&pk.vk, &[], &proof).unwrap(); + assert!(ok); + + writer + .serialize(br) + .expect("unable to write results to csv"); + writer.flush().expect("wasn't able to flush"); + } +} diff --git a/examples/cubic.rs b/examples/cubic.rs index dcc69eb5..34f16acc 100644 --- a/examples/cubic.rs +++ b/examples/cubic.rs @@ -1,170 +1,172 @@ -//! Demonstrates how to produces a proof for canonical cubic equation: `x^3 + x + 5 = y`. -//! The example is described in detail [here]. -//! -//! The R1CS for this problem consists of the following 4 constraints: -//! `Z0 * Z0 - Z1 = 0` -//! `Z1 * Z0 - Z2 = 0` -//! `(Z2 + Z0) * 1 - Z3 = 0` -//! `(Z3 + 5) * 1 - I0 = 0` -//! -//! [here]: https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649 -use ark_ec::pairing::Pairing; -use ark_ff::{BigInteger, PrimeField}; -use ark_std::{One, UniformRand, Zero}; -use libtestudo::testudo_snark::{TestudoSnark, TestudoSnarkGens}; -use libtestudo::{ - parameters::poseidon_params, poseidon_transcript::PoseidonTranscript, InputsAssignment, Instance, - VarsAssignment, -}; - -#[allow(non_snake_case)] -fn produce_r1cs() -> ( - usize, - usize, - usize, - usize, - Instance, - VarsAssignment, - InputsAssignment, -) { - // parameters of the R1CS instance - let num_cons = 4; - let num_vars = 4; - let num_inputs = 1; - let num_non_zero_entries = 8; - - // We will encode the above constraints into three matrices, where - // the coefficients in the matrix are in the little-endian byte order - let mut A: Vec<(usize, usize, Vec)> = Vec::new(); - let mut B: Vec<(usize, usize, Vec)> = Vec::new(); - let mut C: Vec<(usize, usize, Vec)> = Vec::new(); - - let one = E::ScalarField::one().into_bigint().to_bytes_le(); - - // R1CS is a set of three sparse matrices A B C, where is a row for every - // constraint and a column for every entry in z = (vars, 1, inputs) - // An R1CS instance is satisfiable iff: - // Az \circ Bz = Cz, where z = (vars, 1, inputs) - - // constraint 0 entries in (A,B,C) - // constraint 0 is Z0 * Z0 - Z1 = 0. - A.push((0, 0, one.clone())); - B.push((0, 0, one.clone())); - C.push((0, 1, one.clone())); - - // constraint 1 entries in (A,B,C) - // constraint 1 is Z1 * Z0 - Z2 = 0. - A.push((1, 1, one.clone())); - B.push((1, 0, one.clone())); - C.push((1, 2, one.clone())); - - // constraint 2 entries in (A,B,C) - // constraint 2 is (Z2 + Z0) * 1 - Z3 = 0. - A.push((2, 2, one.clone())); - A.push((2, 0, one.clone())); - B.push((2, num_vars, one.clone())); - C.push((2, 3, one.clone())); - - // constraint 3 entries in (A,B,C) - // constraint 3 is (Z3 + 5) * 1 - I0 = 0. - A.push((3, 3, one.clone())); - A.push(( - 3, - num_vars, - E::ScalarField::from(5u32).into_bigint().to_bytes_le(), - )); - B.push((3, num_vars, one.clone())); - C.push((3, num_vars + 1, one)); - - let inst = Instance::::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap(); - - // compute a satisfying assignment - let mut rng = ark_std::rand::thread_rng(); - let z0 = E::ScalarField::rand(&mut rng); - let z1 = z0 * z0; // constraint 0 - let z2 = z1 * z0; // constraint 1 - let z3 = z2 + z0; // constraint 2 - let i0 = z3 + E::ScalarField::from(5u32); // constraint 3 - - // create a VarsAssignment - let mut vars = vec![E::ScalarField::zero().into_bigint().to_bytes_le(); num_vars]; - vars[0] = z0.into_bigint().to_bytes_le(); - vars[1] = z1.into_bigint().to_bytes_le(); - vars[2] = z2.into_bigint().to_bytes_le(); - vars[3] = z3.into_bigint().to_bytes_le(); - let assignment_vars = VarsAssignment::new(&vars).unwrap(); - - // create an InputsAssignment - let mut inputs = vec![E::ScalarField::zero().into_bigint().to_bytes_le(); num_inputs]; - inputs[0] = i0.into_bigint().to_bytes_le(); - let assignment_inputs = InputsAssignment::new(&inputs).unwrap(); - - // check if the instance we created is satisfiable - let res = inst.is_sat(&assignment_vars, &assignment_inputs); - assert!(res.unwrap(), "should be satisfied"); - - ( - num_cons, - num_vars, - num_inputs, - num_non_zero_entries, - inst, - assignment_vars, - assignment_inputs, - ) -} - -type E = ark_bls12_377::Bls12_377; -fn main() { - // produce an R1CS instance - let ( - num_cons, - num_vars, - num_inputs, - num_non_zero_entries, - inst, - assignment_vars, - assignment_inputs, - ) = produce_r1cs::(); - - let params = poseidon_params(); - - // produce public parameters - let gens = TestudoSnarkGens::::setup( - num_cons, - num_vars, - num_inputs, - num_non_zero_entries, - params.clone(), - ); - - // create a commitment to the R1CS instance - let (comm, decomm) = TestudoSnark::encode(&inst, &gens); - - // produce a proof of satisfiability - let mut prover_transcript = PoseidonTranscript::new(¶ms); - let proof = TestudoSnark::prove( - &inst, - &comm, - &decomm, - assignment_vars, - &assignment_inputs, - &gens, - &mut prover_transcript, - params.clone(), - ) - .unwrap(); - - // verify the proof of satisfiability - let mut verifier_transcript = PoseidonTranscript::new(¶ms); - assert!(proof - .verify( - &gens, - &comm, - &assignment_inputs, - &mut verifier_transcript, - params - ) - .is_ok()); - println!("proof verification successful!"); -} +// //! Demonstrates how to produces a proof for canonical cubic equation: `x^3 + x + 5 = y`. +// //! The example is described in detail [here]. +// //! +// //! The R1CS for this problem consists of the following 4 constraints: +// //! `Z0 * Z0 - Z1 = 0` +// //! `Z1 * Z0 - Z2 = 0` +// //! `(Z2 + Z0) * 1 - Z3 = 0` +// //! `(Z3 + 5) * 1 - I0 = 0` +// //! +// //! [here]: https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649 +// use ark_ec::pairing::Pairing; +// use ark_ff::{BigInteger, PrimeField}; +// use ark_std::{One, UniformRand, Zero}; +// use libtestudo::testudo_snark::{TestudoSnark, TestudoSnarkGens}; +// use libtestudo::{ +// parameters::poseidon_params, poseidon_transcript::PoseidonTranscript, InputsAssignment, Instance, +// VarsAssignment, +// }; + +// #[allow(non_snake_case)] +// fn produce_r1cs() -> ( +// usize, +// usize, +// usize, +// usize, +// Instance, +// VarsAssignment, +// InputsAssignment, +// ) { +// // parameters of the R1CS instance +// let num_cons = 4; +// let num_vars = 4; +// let num_inputs = 1; +// let num_non_zero_entries = 8; + +// // We will encode the above constraints into three matrices, where +// // the coefficients in the matrix are in the little-endian byte order +// let mut A: Vec<(usize, usize, Vec)> = Vec::new(); +// let mut B: Vec<(usize, usize, Vec)> = Vec::new(); +// let mut C: Vec<(usize, usize, Vec)> = Vec::new(); + +// let one = E::ScalarField::one().into_bigint().to_bytes_le(); + +// // R1CS is a set of three sparse matrices A B C, where is a row for every +// // constraint and a column for every entry in z = (vars, 1, inputs) +// // An R1CS instance is satisfiable iff: +// // Az \circ Bz = Cz, where z = (vars, 1, inputs) + +// // constraint 0 entries in (A,B,C) +// // constraint 0 is Z0 * Z0 - Z1 = 0. +// A.push((0, 0, one.clone())); +// B.push((0, 0, one.clone())); +// C.push((0, 1, one.clone())); + +// // constraint 1 entries in (A,B,C) +// // constraint 1 is Z1 * Z0 - Z2 = 0. +// A.push((1, 1, one.clone())); +// B.push((1, 0, one.clone())); +// C.push((1, 2, one.clone())); + +// // constraint 2 entries in (A,B,C) +// // constraint 2 is (Z2 + Z0) * 1 - Z3 = 0. +// A.push((2, 2, one.clone())); +// A.push((2, 0, one.clone())); +// B.push((2, num_vars, one.clone())); +// C.push((2, 3, one.clone())); + +// // constraint 3 entries in (A,B,C) +// // constraint 3 is (Z3 + 5) * 1 - I0 = 0. +// A.push((3, 3, one.clone())); +// A.push(( +// 3, +// num_vars, +// E::ScalarField::from(5u32).into_bigint().to_bytes_le(), +// )); +// B.push((3, num_vars, one.clone())); +// C.push((3, num_vars + 1, one)); + +// let inst = Instance::::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap(); + +// // compute a satisfying assignment +// let mut rng = ark_std::rand::thread_rng(); +// let z0 = E::ScalarField::rand(&mut rng); +// let z1 = z0 * z0; // constraint 0 +// let z2 = z1 * z0; // constraint 1 +// let z3 = z2 + z0; // constraint 2 +// let i0 = z3 + E::ScalarField::from(5u32); // constraint 3 + +// // create a VarsAssignment +// let mut vars = vec![E::ScalarField::zero().into_bigint().to_bytes_le(); num_vars]; +// vars[0] = z0.into_bigint().to_bytes_le(); +// vars[1] = z1.into_bigint().to_bytes_le(); +// vars[2] = z2.into_bigint().to_bytes_le(); +// vars[3] = z3.into_bigint().to_bytes_le(); +// let assignment_vars = VarsAssignment::new(&vars).unwrap(); + +// // create an InputsAssignment +// let mut inputs = vec![E::ScalarField::zero().into_bigint().to_bytes_le(); num_inputs]; +// inputs[0] = i0.into_bigint().to_bytes_le(); +// let assignment_inputs = InputsAssignment::new(&inputs).unwrap(); + +// // check if the instance we created is satisfiable +// let res = inst.is_sat(&assignment_vars, &assignment_inputs); +// assert!(res.unwrap(), "should be satisfied"); + +// ( +// num_cons, +// num_vars, +// num_inputs, +// num_non_zero_entries, +// inst, +// assignment_vars, +// assignment_inputs, +// ) +// } + +// type E = ark_bls12_377::Bls12_377; +// fn main() { +// // produce an R1CS instance +// let ( +// num_cons, +// num_vars, +// num_inputs, +// num_non_zero_entries, +// inst, +// assignment_vars, +// assignment_inputs, +// ) = produce_r1cs::(); + +// let params = poseidon_params(); + +// // produce public parameters +// let gens = TestudoSnarkGens::::setup( +// num_cons, +// num_vars, +// num_inputs, +// num_non_zero_entries, +// params.clone(), +// ); + +// // create a commitment to the R1CS instance +// let (comm, decomm) = TestudoSnark::encode(&inst, &gens); + +// // produce a proof of satisfiability +// let mut prover_transcript = PoseidonTranscript::new(¶ms); +// let proof = TestudoSnark::prove( +// &inst, +// &comm, +// &decomm, +// assignment_vars, +// &assignment_inputs, +// &gens, +// &mut prover_transcript, +// params.clone(), +// ) +// .unwrap(); + +// // verify the proof of satisfiability +// let mut verifier_transcript = PoseidonTranscript::new(¶ms); +// assert!(proof +// .verify( +// &gens, +// &comm, +// &assignment_inputs, +// &mut verifier_transcript, +// params +// ) +// .is_ok()); +// println!("proof verification successful!"); +// } + +fn main() {} diff --git a/profiler/testudo.rs b/profiler/testudo.rs index 92f7c267..f97fd93c 100644 --- a/profiler/testudo.rs +++ b/profiler/testudo.rs @@ -1,92 +1,94 @@ -#![allow(non_snake_case)] -#![allow(clippy::assertions_on_result_states)] +// #![allow(non_snake_case)] +// #![allow(clippy::assertions_on_result_states)] -extern crate libtestudo; -extern crate merlin; -use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::pairing::Pairing; -use ark_ff::PrimeField; -use ark_serialize::*; -use libtestudo::parameters::PoseidonConfiguration; -use libtestudo::poseidon_transcript::PoseidonTranscript; -use libtestudo::{ - testudo_snark::{TestudoSnark, TestudoSnarkGens}, - Instance, -}; +// extern crate libtestudo; +// extern crate merlin; +// use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; +// use ark_crypto_primitives::sponge::Absorb; +// use ark_ec::pairing::Pairing; +// use ark_ff::PrimeField; +// use ark_serialize::*; +// use libtestudo::parameters::PoseidonConfiguration; +// use libtestudo::poseidon_transcript::PoseidonTranscript; +// use libtestudo::{ +// testudo_snark::{TestudoSnark, TestudoSnarkGens}, +// Instance, +// }; -fn print(msg: &str) { - let star = "* "; - println!("{:indent$}{}{}", "", star, msg, indent = 2); -} +// fn print(msg: &str) { +// let star = "* "; +// println!("{:indent$}{}{}", "", star, msg, indent = 2); +// } -fn main() { - let params = ark_bls12_377::Fr::poseidon_params(); - profiler::(params); -} +// fn main() { +// let params = ark_bls12_377::Fr::poseidon_params(); +// profiler::(params); +// } -fn profiler(params: PoseidonConfig) -where - E: Pairing, - E::ScalarField: PrimeField, - E::ScalarField: Absorb, -{ - // the list of number of variables (and constraints) in an R1CS instance - let inst_sizes = vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; +// fn profiler(params: PoseidonConfig) +// where +// E: Pairing, +// E::ScalarField: PrimeField, +// E::ScalarField: Absorb, +// { +// // the list of number of variables (and constraints) in an R1CS instance +// let inst_sizes = vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; - println!("Profiler:: SNARK"); - for &s in inst_sizes.iter() { - let num_vars = (2_usize).pow(s as u32); - let num_cons = num_vars; - let num_inputs = 10; +// println!("Profiler:: SNARK"); +// for &s in inst_sizes.iter() { +// let num_vars = (2_usize).pow(s as u32); +// let num_cons = num_vars; +// let num_inputs = 10; - // produce a synthetic R1CSInstance - let (inst, vars, inputs) = - Instance::::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); +// // produce a synthetic R1CSInstance +// let (inst, vars, inputs) = +// Instance::::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); - // produce public generators - let gens = - TestudoSnarkGens::::setup(num_cons, num_vars, num_inputs, num_cons, params.clone()); +// // produce public generators +// let gens = +// TestudoSnarkGens::::setup(num_cons, num_vars, num_inputs, num_cons, params.clone()); - // create a commitment to R1CSInstance - let (comm, decomm) = TestudoSnark::encode(&inst, &gens); +// // create a commitment to R1CSInstance +// let (comm, decomm) = TestudoSnark::encode(&inst, &gens); - // produce a proof of satisfiability - let mut prover_transcript = PoseidonTranscript::new(¶ms.clone()); - let proof = TestudoSnark::prove( - &inst, - &comm, - &decomm, - vars, - &inputs, - &gens, - &mut prover_transcript, - params.clone(), - ) - .unwrap(); +// // produce a proof of satisfiability +// let mut prover_transcript = PoseidonTranscript::new(¶ms.clone()); +// let proof = TestudoSnark::prove( +// &inst, +// &comm, +// &decomm, +// vars, +// &inputs, +// &gens, +// &mut prover_transcript, +// params.clone(), +// ) +// .unwrap(); - let mut proof_encoded = Vec::new(); - proof - .serialize_with_mode(&mut proof_encoded, Compress::Yes) - .unwrap(); - let msg_proof_len = format!( - "TestudoSnark::proof_compressed_len {:?}", - proof_encoded.len() - ); - print(&msg_proof_len); +// let mut proof_encoded = Vec::new(); +// proof +// .serialize_with_mode(&mut proof_encoded, Compress::Yes) +// .unwrap(); +// let msg_proof_len = format!( +// "TestudoSnark::proof_compressed_len {:?}", +// proof_encoded.len() +// ); +// print(&msg_proof_len); - // verify the proof of satisfiability - let mut verifier_transcript = PoseidonTranscript::new(¶ms.clone()); - assert!(proof - .verify( - &gens, - &comm, - &inputs, - &mut verifier_transcript, - params.clone() - ) - .is_ok()); +// // verify the proof of satisfiability +// let mut verifier_transcript = PoseidonTranscript::new(¶ms.clone()); +// assert!(proof +// .verify( +// &gens, +// &comm, +// &inputs, +// &mut verifier_transcript, +// params.clone() +// ) +// .is_ok()); - println!(); - } -} +// println!(); +// } +// } + +fn main() {} diff --git a/src/circuit_verifier.rs b/src/circuit_verifier.rs new file mode 100644 index 00000000..60cde505 --- /dev/null +++ b/src/circuit_verifier.rs @@ -0,0 +1,597 @@ +use crate::ark_std::One; +use crate::mipp::MippProof; +use ark_crypto_primitives::sponge::{ + constraints::CryptographicSpongeVar, + poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig}, +}; +use ark_crypto_primitives::Error; +use ark_ec::pairing::Pairing; +use ark_ec::CurveGroup; +use ark_poly_commit::multilinear_pc::data_structures::CommitmentG2; +use ark_poly_commit::multilinear_pc::data_structures::ProofG1; +use ark_poly_commit::multilinear_pc::{ + data_structures::{Commitment, Proof, VerifierKey}, +}; +use ark_r1cs_std::fields::nonnative::NonNativeFieldVar; +use ark_r1cs_std::prelude::*; +use ark_r1cs_std::{ + alloc::AllocVar, + prelude::{EqGadget, FieldVar}, +}; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError}; +use ark_serialize::CanonicalSerialize; +use ark_serialize::Compress; +use std::ops::AddAssign; +use std::ops::Mul; +use std::ops::MulAssign; +use std::marker::PhantomData; + + +struct MippTUVar +where + E: Pairing, + IV: PairingVar, + IV::G1Var: CurveVar, + IV::GTVar: FieldVar, +{ + pub tc: IV::GTVar, + pub uc: IV::G1Var, +} + +impl Default for MippTUVar +where + E: Pairing, + IV: PairingVar, + IV::G1Var: CurveVar, + IV::GTVar: FieldVar, +{ + fn default() -> Self { + Self { + tc: IV::GTVar::one(), + uc: IV::G1Var::zero(), + } + } +} +impl MippTUVar +where + E: Pairing, + IV: PairingVar, + IV::G1Var: CurveVar, + IV::GTVar: FieldVar, +{ + fn merge(&mut self, other: &Self) { + self.tc.mul_assign(&other.tc); + self.uc.add_assign(&other.uc); + } +} + +pub struct TestudoCommVerifier +where + E: Pairing, + IV: PairingVar, +{ + pub params: PoseidonConfig, + pub vk: VerifierKey, + pub U: Commitment, + pub point: Vec, + pub v: E::ScalarField, + pub pst_proof: Proof, + pub mipp_proof: MippProof, + pub T: E::TargetField, + pub _iv: PhantomData, +} +impl Clone for TestudoCommVerifier +where + E: Pairing, + IV: PairingVar, +{ + fn clone(&self) -> Self { + Self { + params: self.params.clone(), + vk: self.vk.clone(), + U: self.U.clone(), + point: self.point.clone(), + v: self.v.clone(), + pst_proof: self.pst_proof.clone(), + mipp_proof: self.mipp_proof.clone(), + T: self.T.clone(), + _iv: self._iv, + } + } +} + +impl ConstraintSynthesizer<::BaseField> for TestudoCommVerifier +where + E: Pairing, + IV: PairingVar, + IV::G1Var: CurveVar, + IV::G2Var: CurveVar, + IV::GTVar: FieldVar, +{ + fn generate_constraints( + self, + cs: ConstraintSystemRef<::BaseField>, + ) -> Result<(), SynthesisError> { + + + let mut point_var = Vec::new(); + for p in self.point.clone().into_iter() { + let p_var = + NonNativeFieldVar::::new_witness(cs.clone(), || Ok(p))?; + point_var.push(p_var); + } + let len = point_var.len(); + let odd = if len % 2 == 1 { 1 } else { 0 }; + let a_var = &point_var[0..len / 2 + odd]; + let b_var = &point_var[len / 2 + odd..len]; + + mipp_verify_gadget::( + cs.clone(), + self.params.clone(), + self.vk.clone(), + &self.mipp_proof, + b_var.to_vec(), + self.U.g_product, + &self.T, + ).unwrap(); + let mut a_rev_var = a_var.to_vec().clone(); + a_rev_var.reverse(); + + check_gadget::( + cs.clone(), + self.vk, + self.U, + &a_rev_var, + self.v, + self.pst_proof, + ).unwrap(); + Ok(()) + } +} + +fn check_2_gadget>( + cs: ConstraintSystemRef, + vk: VerifierKey, + commitment: &CommitmentG2, + point_var: &Vec>, + value_var: NonNativeFieldVar, + proof: &ProofG1, +) -> Result<(), Error> +where + IV::G1Var: CurveVar, + IV::G2Var: CurveVar, + IV::GTVar: FieldVar, +{ + let vk_g_var = IV::G1Var::new_witness(cs.clone(), || Ok(vk.g))?; + let vk_h_var = IV::G2Var::new_witness(cs.clone(), || Ok(vk.h))?; + let mut vk_gmask_var = Vec::new(); + for g_mask in vk.g_mask_random.clone().into_iter() { + let g_mask_var = IV::G1Var::new_witness(cs.clone(), || Ok(g_mask))?; + vk_gmask_var.push(g_mask_var); + } + // allocate commitment + let com_h_prod_var = IV::G2Var::new_witness(cs.clone(), || Ok(commitment.h_product))?; + + let pair_right_op = com_h_prod_var + - (vk_h_var + .scalar_mul_le(value_var.to_bits_le().unwrap().iter()) + .unwrap()); + let right_prepared = IV::prepare_g2(&pair_right_op)?; + let left_prepared = IV::prepare_g1(&vk_g_var)?; + let left = IV::pairing(left_prepared, right_prepared)?; + + let mut h_mul_var = Vec::new(); + + for p in point_var.into_iter() { + let x = vk_h_var + .scalar_mul_le(p.to_bits_le().unwrap().iter()) + .unwrap(); + h_mul_var.push(x); + } + let h_mask_random = vk.h_mask_random[vk.nv - point_var.len()..].to_vec(); + let mut h_mask_random_var = Vec::new(); + for h_mask in h_mask_random.clone().into_iter() { + let h_mask_var = IV::G2Var::new_witness(cs.clone(), || Ok(h_mask))?; + h_mask_random_var.push(h_mask_var); + } + let pairing_rights_var: Vec<_> = (0..point_var.len()) + .into_iter() + .map(|i| h_mask_random_var[i].clone() - h_mul_var[i].clone()) //.map(|i| vk_gmask_var[i].clone() - g_mul_var[i].clone()) + .collect(); + let pairing_rights_var: Vec = pairing_rights_var + .into_iter() + .map(|p| IV::prepare_g2(&p).unwrap()) + .collect(); + let mut proofs_var = Vec::new(); + for p in proof.proofs.clone().into_iter() { + let proof_var = IV::G1Var::new_witness(cs.clone(), || Ok(p))?; + proofs_var.push(proof_var); + } + let pairing_lefts_var: Vec = proofs_var + .into_iter() + .map(|p| IV::prepare_g1(&p).unwrap()) + .collect(); + + let right_ml = IV::miller_loop(&pairing_lefts_var, &pairing_rights_var)?; + let right = IV::final_exponentiation(&right_ml)?; + + left.enforce_equal(&right).unwrap(); + Ok(()) +} + +fn check_gadget>( + cs: ConstraintSystemRef, + vk: VerifierKey, + commitment: Commitment, + point_var: &Vec>, + value: E::ScalarField, + proof: Proof, +) -> Result<(), Error> +where + IV::G1Var: CurveVar, + IV::G2Var: CurveVar, + IV::GTVar: FieldVar, +{ + let vk_g_var = IV::G1Var::new_witness(cs.clone(), || Ok(vk.g))?; + let vk_h_var = IV::G2Var::new_witness(cs.clone(), || Ok(vk.h))?; + let mut vk_gmask_var = Vec::new(); + for g_mask in vk.g_mask_random.clone().into_iter() { + let g_mask_var = IV::G1Var::new_witness(cs.clone(), || Ok(g_mask))?; + vk_gmask_var.push(g_mask_var); + } + // allocate commitment + let com_g1_prod_var = IV::G1Var::new_witness(cs.clone(), || Ok(commitment.g_product))?; + + let value_var = + NonNativeFieldVar::::new_witness(cs.clone(), || Ok(value))?; + + // allocate proof + let mut proofs_var = Vec::new(); + for proof in proof.proofs.clone().into_iter() { + let proof_var = IV::G2Var::new_witness(cs.clone(), || Ok(proof))?; + proofs_var.push(proof_var); + } + // start operation on circuit + let pair_left_op = com_g1_prod_var - (vk_g_var.scalar_mul_le(value_var.to_bits_le()?.iter())?); + let left_prepared = IV::prepare_g1(&pair_left_op)?; + let right_prepared = IV::prepare_g2(&vk_h_var)?; + let left = IV::pairing(left_prepared, right_prepared)?; + + let mut res_var = Vec::new(); + + for p in point_var.into_iter() { + let x = vk_g_var.scalar_mul_le(p.to_bits_le()?.iter())?; + res_var.push(x); + } + + //computing other part of the circuit + let pairing_lefts_var: Vec<_> = (0..vk.nv) + .map(|i| vk_gmask_var[i].clone() - res_var[i].clone()) //.map(|i| vk_gmask_var[i].clone() - g_mul_var[i].clone()) + .collect(); + + let mut pairing_lefts_prep = Vec::new(); + for var in pairing_lefts_var.clone().into_iter() { + pairing_lefts_prep.push(IV::prepare_g1(&var).unwrap()); + } + + let mut pairing_right_prep = Vec::new(); + for var in proofs_var.clone().into_iter() { + pairing_right_prep.push(IV::prepare_g2(&var).unwrap()); + } + + let right_ml = IV::miller_loop(&pairing_lefts_prep, &pairing_right_prep)?; + let right = IV::final_exponentiation(&right_ml).unwrap(); + left.enforce_equal(&right)?; + Ok(()) +} + +fn mipp_verify_gadget>( + cs: ConstraintSystemRef, + params: PoseidonConfig, + vk: VerifierKey, + proof: &MippProof, + point_var: Vec>, + U: E::G1Affine, + T: &::TargetField, +) -> Result<(),Error> +where + IV::G1Var: CurveVar, + IV::G2Var: CurveVar, + IV::GTVar: FieldVar, +{ + let comms_u = proof.comms_u.clone(); + let comms_t = proof.comms_t.clone(); + let mut comms_u_var = Vec::new(); + for (first, second) in proof.comms_u.clone().into_iter() { + let first_var = IV::G1Var::new_witness(cs.clone(), || Ok(first))?; + let second_var = IV::G1Var::new_witness(cs.clone(), || Ok(second))?; + comms_u_var.push((first_var, second_var)); + } + // allocate comms_t + let mut comms_t_var = Vec::new(); + for (first, second) in proof.comms_t.clone().into_iter() { + let first_var = IV::GTVar::new_witness(cs.clone(), || Ok(first))?; + let second_var = IV::GTVar::new_witness(cs.clone(), || Ok(second))?; + comms_t_var.push((first_var, second_var)); + } + + let mut xs = Vec::new(); + let mut xs_inv = Vec::new(); + + let final_y = E::ScalarField::one(); + let mut final_y_var = + NonNativeFieldVar::::new_witness(cs.clone(), || Ok(final_y))?; + + // start allocate T + let T_var = IV::GTVar::new_witness(cs.clone(), || Ok(T))?; + // start allocate U.g_product + let U_g_product_var = IV::G1Var::new_witness(cs.clone(), || Ok(U))?; + + let mut final_res_var: MippTUVar = MippTUVar { + tc: T_var.clone(), + uc: U_g_product_var.clone(), + }; + + // create new transcript inside the circuit instead of taking it from parameters + let mut transcript_var = PoseidonSpongeVar::new(cs.clone(), ¶ms); + + // FIRST ABSORB + let mut buf = Vec::new(); + U //take it as naive cause we pass the byte to the hash function + .serialize_with_mode(&mut buf, Compress::No) + .expect("serialization failed"); + + let mut u_var_vec: Vec> = Vec::new(); + for el in buf { + u_var_vec.push(UInt8::new_witness(cs.clone(), || Ok(el))?); + } + transcript_var.absorb(&u_var_vec)?; + + let one_var = NonNativeFieldVar::::new_witness(cs.clone(), || { + Ok(E::ScalarField::one()) + })?; + + for (i, (comm_u, comm_t)) in comms_u.iter().zip(comms_t.iter()).enumerate() { + let (comm_u_l, comm_u_r) = comm_u; + let (comm_t_l, comm_t_r) = comm_t; + // Fiat-Shamir challenge + // ABSORB COMM_U_L + let mut comm_u_l_buf = Vec::new(); + comm_u_l + .serialize_with_mode(&mut comm_u_l_buf, Compress::No) + .expect("serialization failed"); + + let mut comm_u_l_var_bytes = Vec::new(); + + for b in comm_u_l_buf { + comm_u_l_var_bytes.push(UInt8::new_witness(cs.clone(), || Ok(b))?); + } + transcript_var.absorb(&comm_u_l_var_bytes)?; + // ABSORB COMM_U_R + let mut comm_u_r_buf = Vec::new(); + comm_u_r + .serialize_with_mode(&mut comm_u_r_buf, Compress::No) + .expect("serialization failed"); + + let mut comm_u_r_var_bytes = Vec::new(); + + for b in comm_u_r_buf { + comm_u_r_var_bytes.push(UInt8::new_witness(cs.clone(), || Ok(b))?); + } + transcript_var.absorb(&comm_u_r_var_bytes)?; + // ABSORB COMM_T_L + let mut comm_t_l_buf = Vec::new(); + comm_t_l + .serialize_with_mode(&mut comm_t_l_buf, Compress::No) + .expect("serialization failed"); + + let mut comm_t_l_var_bytes = Vec::new(); + + for b in comm_t_l_buf { + comm_t_l_var_bytes.push(UInt8::new_witness(cs.clone(), || Ok(b))?); + } + transcript_var.absorb(&comm_t_l_var_bytes)?; + // ABSORB COMM_T_R + let mut comm_t_r_buf = Vec::new(); + comm_t_r + .serialize_with_mode(&mut comm_t_r_buf, Compress::No) + .expect("serialization failed"); + + let mut comm_t_r_var_bytes = Vec::new(); + + for b in comm_t_r_buf { + comm_t_r_var_bytes.push(UInt8::new_witness(cs.clone(), || Ok(b))?); + } + + transcript_var.absorb(&comm_t_r_var_bytes)?; + + //allocate the digest as circuit variable + let c_inv_nn = (transcript_var.squeeze_nonnative_field_elements::(1)?).0; + let c_inv_var = &c_inv_nn[0]; + + let c_var = c_inv_var.inverse().unwrap(); + + xs.push(c_var.clone()); + xs_inv.push(c_inv_var.clone()); + + final_y_var *= &one_var + c_inv_var.mul(&point_var[i]) - &point_var[i]; + } + enum Op<'a, E: Pairing, IV: PairingVar> { + TC( + &'a IV::GTVar, + NonNativeFieldVar, + ), + UC( + &'a IV::G1Var, + &'a NonNativeFieldVar, + ), + } + + let res_var = comms_t_var + .iter() + .zip(comms_u_var.iter()) + .zip(xs.iter().zip(xs_inv.iter())) + .flat_map(|((comm_t, comm_u), (c, c_inv))| { + let (comm_t_l, comm_t_r) = comm_t; + let (comm_u_l, comm_u_r) = comm_u; + + // we multiple left side by x^-1 and right side by x + vec![ + Op::TC(comm_t_l, c_inv.clone()), + Op::TC(comm_t_r, c.clone()), + Op::UC(comm_u_l, c_inv), + Op::UC(comm_u_r, c), + ] + }) + .fold(MippTUVar::::default(), |mut res, op: Op| { + match op { + Op::TC(tx, c) => { + let tx = tx.pow_le(&c.to_bits_le().unwrap()).unwrap(); + res.tc.mul_assign(&tx); + } + Op::UC(zx, c) => { + let uxp = zx.scalar_mul_le(c.to_bits_le().unwrap().iter()).unwrap(); + res.uc.add_assign(&uxp); + } + } + res + }); + + let ref_final_res_var = &mut final_res_var; + ref_final_res_var.merge(&res_var); + + let mut rs = Vec::new(); + let m = xs_inv.len(); + for _i in 0..m { + let r_nn = (transcript_var.squeeze_nonnative_field_elements::(1)?).0; + let r = r_nn[0].clone(); + rs.push(r); + } + + let v_var: NonNativeFieldVar = (0..m) + .into_iter() + .map(|i| &one_var + (&rs[i]).mul(&xs_inv[m - i - 1]) - &rs[i]) + .fold(one_var.clone(), |acc, x| acc * x); // .product() == fold + + let comm_h = CommitmentG2:: { + nv: m, + h_product: proof.final_h, + }; + + check_2_gadget::( + cs.clone(), + vk.clone(), + &comm_h, + &rs, + v_var, + &proof.pst_proof_h, + )?; + let final_a_var = IV::G1Var::new_witness(cs.clone(), || Ok(proof.final_a))?; + let final_u_var = final_a_var + .scalar_mul_le(final_y_var.to_bits_le().unwrap().iter()) + .unwrap(); + + let final_h_var = IV::G2Var::new_witness(cs.clone(), || Ok(proof.final_h))?; + + let final_u_var_prep = IV::prepare_g1(&final_a_var)?; + let final_h_var_prep = IV::prepare_g2(&final_h_var)?; + + let final_t_var = IV::pairing(final_u_var_prep, final_h_var_prep)?; + + ref_final_res_var.tc.enforce_equal(&final_t_var).unwrap(); + + ref_final_res_var.uc.enforce_equal(&final_u_var).unwrap(); + + Ok(()) +} +#[cfg(test)] +mod tests { + use crate::ark_std::UniformRand; + use ark_bls12_377::Bls12_377; + use ark_ec::pairing::Pairing; + use ark_std::vec::Vec; + type E = Bls12_377; + use ark_relations::r1cs::ConstraintSystem; + use super::*; + use ark_ec::bls12::Bls12; + type F = ark_bls12_377::Fr; + use crate::sqrt_pst::Polynomial; + use ark_poly_commit::multilinear_pc::data_structures::{ + CommitmentG2, CommitterKey, ProofG1, VerifierKey, + }; + use ark_poly_commit::multilinear_pc::MultilinearPC; + use crate::parameters::get_bls12377_fq_params; + use crate::poseidon_transcript::PoseidonTranscript; + use ark_groth16::Groth16; + use crate::rand::SeedableRng; + use ark_crypto_primitives::snark::SNARK; + use rand::rngs::OsRng; + + #[test] + fn check_commit() { + // check odd case + check_sqrt_poly_commit(6); + } + + fn check_sqrt_poly_commit(num_vars: u32) { + let mut rng = ark_std::test_rng(); + let len = 2_usize.pow(num_vars); + let Z: Vec = (0..len).into_iter().map(|_| F::rand(&mut rng)).collect(); + let r: Vec = (0..num_vars) + .into_iter() + .map(|_| F::rand(&mut rng)) + .collect(); + + let gens = MultilinearPC::::setup(3, &mut rng); + let (ck, vk) = MultilinearPC::::trim(&gens, 3); + + let mut pl = Polynomial::from_evaluations(&Z.clone()); + + let v = pl.eval(&r); + + let (comm_list, t) = pl.commit(&ck); + + let params = get_bls12377_fq_params(); + let mut prover_transcript = PoseidonTranscript::new(¶ms); + + let (u, pst_proof, mipp_proof) = pl.open(&mut prover_transcript, comm_list, &ck, &r, &t); + + let mut verifier_transcript = PoseidonTranscript::new(¶ms); + + // let res = Polynomial::verify( + // &mut verifier_transcript, + // &vk, + // &u, + // &r, + // v, + // &pst_proof, + // &mipp_proof, + // &t, + // ); + // assert!(res == true); + + let circuit = + TestudoCommVerifier:: { + params, + vk, + U: u, + point: r, + v, + pst_proof, + mipp_proof, + T: t, + _iv: PhantomData, + }; + // let cs = ConstraintSystem::< as Pairing>::BaseField>::new_ref(); + // circuit.generate_constraints(cs.clone()).unwrap(); + // println!("Num constraints2: {:?}", cs.num_constraints()); + // assert!(cs.is_satisfied().unwrap()); + + + let mut rng2 = rand_chacha::ChaChaRng::seed_from_u64(1776); + let (pk, vk) = Groth16::::circuit_specific_setup(circuit.clone(), &mut rng2).unwrap(); + let proof = Groth16::::prove(&pk, circuit.clone(), &mut OsRng).unwrap(); + let ok = Groth16::::verify(&pk.vk, &[], &proof).unwrap(); + assert!(ok); + } +} diff --git a/src/lib.rs b/src/lib.rs index 44893a94..7bd2259a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,9 +21,13 @@ mod dense_mlpoly; mod errors; #[macro_use] pub(crate) mod macros; +pub mod circuit_verifier; +mod constraints; mod math; pub(crate) mod mipp; mod nizk; +pub mod parameters; +pub mod poseidon_transcript; mod product_tree; mod r1csinstance; mod r1csproof; @@ -35,12 +39,7 @@ pub mod testudo_snark; mod timer; pub(crate) mod transcript; mod unipoly; - -pub mod parameters; - -mod constraints; -pub mod poseidon_transcript; - +mod verifier_circuit; use core::cmp::max; use errors::R1CSError; diff --git a/src/mipp.rs b/src/mipp.rs index 93f7a9c1..02ba1485 100644 --- a/src/mipp.rs +++ b/src/mipp.rs @@ -29,7 +29,7 @@ pub struct MippProof { impl MippProof { pub fn prove( - transcript: &mut PoseidonTranscript, + transcript: &mut PoseidonTranscript, ck: &CommitterKey, a: Vec, y: Vec, @@ -129,6 +129,7 @@ impl MippProof { xs_inv.len(), Self::polynomial_evaluations_from_transcript::(&xs_inv), ); + let c = MultilinearPC::::commit_g2(ck, &poly); debug_assert!(c.h_product == final_h); @@ -179,7 +180,7 @@ impl MippProof { pub fn verify( vk: &VerifierKey, - transcript: &mut PoseidonTranscript, + transcript: &mut PoseidonTranscript, proof: &MippProof, point: Vec, U: &E::G1Affine, @@ -277,7 +278,6 @@ impl MippProof { let r = transcript.challenge_scalar::(b"random_point"); rs.push(r); } - // Given p_h is structured as defined above, the verifier can compute // p_h(rs) by themselves in O(m) time let v = (0..m) diff --git a/src/parameters.rs b/src/parameters.rs index ce5b5a66..a8e14c7b 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -1,5 +1,14 @@ +use crate::ark_std::One; +use ark_bls12_377::Fq; use ark_bls12_377::Fr; use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; +use ark_ec::pairing::Pairing; +use ark_ff::BigInt; +use ark_ff::BigInteger; +use ark_ff::BigInteger64; +use ark_ff::PrimeField; +use poseidon_parameters::PoseidonParameters; +use std::fmt::Debug; use std::str::FromStr; // Copyright: https://github.com/nikkolasg/ark-dkg/blob/main/src/parameters.rs use json::JsonValue; @@ -175,6 +184,37 @@ pub fn poseidon_params() -> PoseidonConfig { ) } +pub fn get_bls12377_fq_params() -> PoseidonConfig { + let arks = FR["ark"] + .members() + .map(|ark| { + ark + .members() + .map(|v| Fq::from_str(v.as_str().unwrap()).unwrap()) + .collect::>() + }) + .collect::>(); + let mds = FR["mds"] + .members() + .map(|m| { + m.members() + .map(|v| Fq::from_str(v.as_str().unwrap()).unwrap()) + .collect::>() + }) + .collect::>(); + PoseidonConfig::new( + FR["full_rounds"].as_usize().unwrap(), + FR["partial_rounds"].as_usize().unwrap(), + FR["alpha"].as_u64().unwrap(), + mds, + arks, + FR["rate"].as_usize().unwrap(), + // TODO (nikkolasg): check out the concrete parameters for the capacity + // so far taken from https://github.com/AleoHQ/snarkVM/blob/d6ce2d3540b9355b59ef580db998188c786f8599/fields/src/traits/poseidon_default.rs#L43 + 1, + ) +} + // Generated from poseidon_transcript::test::poseidon_parameters_generation pub fn poseidon_params_bls12381() -> PoseidonConfig { use ark_ff::PrimeField; diff --git a/src/poseidon_transcript.rs b/src/poseidon_transcript.rs index 8a08ae7e..5bd926da 100644 --- a/src/poseidon_transcript.rs +++ b/src/poseidon_transcript.rs @@ -10,8 +10,8 @@ use ark_serialize::Compress; #[derive(Clone)] /// TODO pub struct PoseidonTranscript { - sponge: PoseidonSponge, - params: PoseidonConfig, + pub sponge: PoseidonSponge, + pub params: PoseidonConfig, } impl Transcript for PoseidonTranscript { @@ -22,7 +22,7 @@ impl Transcript for PoseidonTranscript { fn append(&mut self, _label: &'static [u8], point: &S) { let mut buf = Vec::new(); point - .serialize_with_mode(&mut buf, Compress::Yes) + .serialize_with_mode(&mut buf, Compress::No) .expect("serialization failed"); self.sponge.absorb(&buf); } @@ -50,6 +50,7 @@ impl PoseidonTranscript { } } + impl PoseidonTranscript { pub fn append_u64(&mut self, _label: &'static [u8], x: u64) { self.sponge.absorb(&x); diff --git a/src/r1csproof.rs b/src/r1csproof.rs index 92538529..df491b06 100644 --- a/src/r1csproof.rs +++ b/src/r1csproof.rs @@ -1,633 +1,633 @@ -#![allow(clippy::too_many_arguments)] -use super::dense_mlpoly::{DensePolynomial, EqPolynomial, PolyCommitmentGens}; -use super::errors::ProofVerifyError; -use crate::constraints::{R1CSVerificationCircuit, SumcheckVerificationCircuit, VerifierConfig}; -use crate::math::Math; -use crate::mipp::MippProof; -use crate::poseidon_transcript::PoseidonTranscript; -use crate::sqrt_pst::Polynomial; -use crate::sumcheck::SumcheckInstanceProof; -use crate::transcript::Transcript; -use crate::unipoly::UniPoly; -use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::pairing::Pairing; - -use ark_poly_commit::multilinear_pc::data_structures::{Commitment, Proof}; -use itertools::Itertools; - -use super::r1csinstance::R1CSInstance; - -use super::sparse_mlpoly::{SparsePolyEntry, SparsePolynomial}; -use super::timer::Timer; -use ark_snark::{CircuitSpecificSetupSNARK, SNARK}; - -use crate::ark_std::UniformRand; -use ark_groth16::{Groth16, ProvingKey, VerifyingKey}; - -use ark_serialize::*; -use ark_std::{One, Zero}; - -#[derive(CanonicalSerialize, CanonicalDeserialize, Debug)] -pub struct R1CSProof { - // The PST commitment to the multilinear extension of the witness. - pub comm: Commitment, - sc_proof_phase1: SumcheckInstanceProof, - claims_phase2: ( - E::ScalarField, - E::ScalarField, - E::ScalarField, - E::ScalarField, - ), - sc_proof_phase2: SumcheckInstanceProof, - pub eval_vars_at_ry: E::ScalarField, - pub proof_eval_vars_at_ry: Proof, - rx: Vec, - ry: Vec, - // The transcript state after the satisfiability proof was computed. - pub transcript_sat_state: E::ScalarField, - pub initial_state: E::ScalarField, - pub t: E::TargetField, - pub mipp_proof: MippProof, -} - -#[derive(Debug, CanonicalSerialize, CanonicalDeserialize, Clone)] -pub struct R1CSVerifierProof { - comm: Commitment, - circuit_proof: ark_groth16::Proof, - initial_state: E::ScalarField, - transcript_sat_state: E::ScalarField, - eval_vars_at_ry: E::ScalarField, - proof_eval_vars_at_ry: Proof, - t: E::TargetField, - mipp_proof: MippProof, -} - -#[derive(Clone)] -pub struct CircuitGens { - pk: ProvingKey, - vk: VerifyingKey, -} - -impl CircuitGens -where - E: Pairing, -{ - // Performs the circuit-specific setup required by Groth16 for the sumcheck - // circuit. This is done by filling the struct with dummy elements, ensuring - // the sizes are correct so the setup matches the circuit that will be proved. - pub fn setup( - num_cons: usize, - num_vars: usize, - num_inputs: usize, - poseidon: PoseidonConfig, - ) -> Self { - let mut rng = rand::thread_rng(); - - let uni_polys_round1 = (0..num_cons.log_2()) - .map(|_i| { - UniPoly::::from_evals(&[ - E::ScalarField::rand(&mut rng), - E::ScalarField::rand(&mut rng), - E::ScalarField::rand(&mut rng), - E::ScalarField::rand(&mut rng), - ]) - }) - .collect::>>(); - - let uni_polys_round2 = (0..num_vars.log_2() + 1) - .map(|_i| { - UniPoly::::from_evals(&[ - E::ScalarField::rand(&mut rng), - E::ScalarField::rand(&mut rng), - E::ScalarField::rand(&mut rng), - ]) - }) - .collect::>>(); - - let circuit = R1CSVerificationCircuit { - num_vars: num_vars, - num_cons: num_cons, - input: (0..num_inputs) - .map(|_i| E::ScalarField::rand(&mut rng)) - .collect_vec(), - input_as_sparse_poly: SparsePolynomial::new( - num_vars.log_2(), - (0..num_inputs + 1) - .map(|i| SparsePolyEntry::new(i, E::ScalarField::rand(&mut rng))) - .collect::>>(), - ), - evals: ( - E::ScalarField::zero(), - E::ScalarField::zero(), - E::ScalarField::zero(), - ), - params: poseidon, - prev_challenge: E::ScalarField::zero(), - claims_phase2: ( - E::ScalarField::zero(), - E::ScalarField::zero(), - E::ScalarField::zero(), - E::ScalarField::zero(), - ), - eval_vars_at_ry: E::ScalarField::zero(), - sc_phase1: SumcheckVerificationCircuit { - polys: uni_polys_round1, - }, - sc_phase2: SumcheckVerificationCircuit { - polys: uni_polys_round2, - }, - claimed_rx: (0..num_cons.log_2()) - .map(|_i| E::ScalarField::rand(&mut rng)) - .collect_vec(), - claimed_ry: (0..num_vars.log_2() + 1) - .map(|_i| E::ScalarField::rand(&mut rng)) - .collect_vec(), - claimed_transcript_sat_state: E::ScalarField::zero(), - }; - let (pk, vk) = Groth16::::setup(circuit.clone(), &mut rng).unwrap(); - CircuitGens { pk, vk } - } -} - -#[derive(Clone)] -pub struct R1CSGens { - gens_pc: PolyCommitmentGens, - gens_gc: CircuitGens, -} - -impl R1CSGens { - // Performs the setup for the polynomial commitment PST and for Groth16. - pub fn setup( - label: &'static [u8], - num_cons: usize, - num_vars: usize, - num_inputs: usize, - poseidon: PoseidonConfig, - ) -> Self { - let num_poly_vars = num_vars.log_2(); - let gens_pc = PolyCommitmentGens::setup(num_poly_vars, label); - let gens_gc = CircuitGens::setup(num_cons, num_vars, num_inputs, poseidon); - R1CSGens { gens_pc, gens_gc } - } -} - -impl R1CSProof -where - E: Pairing, - E::ScalarField: Absorb, -{ - fn prove_phase_one( - num_rounds: usize, - evals_tau: &mut DensePolynomial, - evals_Az: &mut DensePolynomial, - evals_Bz: &mut DensePolynomial, - evals_Cz: &mut DensePolynomial, - transcript: &mut PoseidonTranscript, - ) -> ( - SumcheckInstanceProof, - Vec, - Vec, - ) { - let comb_func = - |poly_tau_comp: &E::ScalarField, - poly_A_comp: &E::ScalarField, - poly_B_comp: &E::ScalarField, - poly_C_comp: &E::ScalarField| - -> E::ScalarField { (*poly_tau_comp) * ((*poly_A_comp) * poly_B_comp - poly_C_comp) }; - - let (sc_proof_phase_one, r, claims) = SumcheckInstanceProof::prove_cubic_with_additive_term( - &E::ScalarField::zero(), // claim is zero - num_rounds, - evals_tau, - evals_Az, - evals_Bz, - evals_Cz, - comb_func, - transcript, - ); - - (sc_proof_phase_one, r, claims) - } - - fn prove_phase_two( - num_rounds: usize, - claim: &E::ScalarField, - evals_z: &mut DensePolynomial, - evals_ABC: &mut DensePolynomial, - transcript: &mut PoseidonTranscript, - ) -> ( - SumcheckInstanceProof, - Vec, - Vec, - ) { - let comb_func = |poly_A_comp: &E::ScalarField, - poly_B_comp: &E::ScalarField| - -> E::ScalarField { (*poly_A_comp) * poly_B_comp }; - let (sc_proof_phase_two, r, claims) = SumcheckInstanceProof::prove_quad( - claim, num_rounds, evals_z, evals_ABC, comb_func, transcript, - ); - - (sc_proof_phase_two, r, claims) - } - - // Proves the R1CS instance inst is satisfiable given the assignment - // vars. - pub fn prove( - inst: &R1CSInstance, - vars: Vec, - input: &[E::ScalarField], - gens: &R1CSGens, - transcript: &mut PoseidonTranscript, - ) -> (Self, Vec, Vec) { - let timer_prove = Timer::new("R1CSProof::prove"); - // we currently require the number of |inputs| + 1 to be at most number of vars - assert!(input.len() < vars.len()); - - // create the multilinear witness polynomial from the satisfying assiment - // expressed as the list of sqrt-sized polynomials - let mut pl = Polynomial::from_evaluations(&vars.clone()); - - let timer_commit = Timer::new("polycommit"); - - // commitment list to the satisfying witness polynomial list - let (comm_list, t) = pl.commit(&gens.gens_pc.ck); - - transcript.append_gt::(b"", &t); - - timer_commit.stop(); - - let initial_state = transcript.challenge_scalar(b""); - transcript.new_from_state(&initial_state); - - transcript.append_scalar_vector(b"", &input); - - let timer_sc_proof_phase1 = Timer::new("prove_sc_phase_one"); - - // append input to variables to create a single vector z - let z = { - let num_inputs = input.len(); - let num_vars = vars.len(); - let mut z = vars; - z.extend(&vec![E::ScalarField::one()]); // add constant term in z - z.extend(input); - z.extend(&vec![E::ScalarField::zero(); num_vars - num_inputs - 1]); // we will pad with zeros - z - }; - - // derive the verifier's challenge tau - let (num_rounds_x, num_rounds_y) = (inst.get_num_cons().log_2(), z.len().log_2()); - let tau = transcript.challenge_scalar_vec(b"", num_rounds_x); - // compute the initial evaluation table for R(\tau, x) - let mut poly_tau = DensePolynomial::new(EqPolynomial::new(tau).evals()); - let (mut poly_Az, mut poly_Bz, mut poly_Cz) = - inst.multiply_vec(inst.get_num_cons(), z.len(), &z); - - let (sc_proof_phase1, rx, _claims_phase1) = R1CSProof::::prove_phase_one( - num_rounds_x, - &mut poly_tau, - &mut poly_Az, - &mut poly_Bz, - &mut poly_Cz, - transcript, - ); - assert_eq!(poly_tau.len(), 1); - assert_eq!(poly_Az.len(), 1); - assert_eq!(poly_Bz.len(), 1); - assert_eq!(poly_Cz.len(), 1); - timer_sc_proof_phase1.stop(); - - let (tau_claim, Az_claim, Bz_claim, Cz_claim) = - (&poly_tau[0], &poly_Az[0], &poly_Bz[0], &poly_Cz[0]); - let prod_Az_Bz_claims = (*Az_claim) * Bz_claim; - - // prove the final step of sum-check #1 - let taus_bound_rx = tau_claim; - let _claim_post_phase1 = ((*Az_claim) * Bz_claim - Cz_claim) * taus_bound_rx; - - let timer_sc_proof_phase2 = Timer::new("prove_sc_phase_two"); - // combine the three claims into a single claim - let r_A: E::ScalarField = transcript.challenge_scalar(b""); - let r_B: E::ScalarField = transcript.challenge_scalar(b""); - let r_C: E::ScalarField = transcript.challenge_scalar(b""); - let claim_phase2 = r_A * Az_claim + r_B * Bz_claim + r_C * Cz_claim; - - let evals_ABC = { - // compute the initial evaluation table for R(\tau, x) - let evals_rx = EqPolynomial::new(rx.clone()).evals(); - let (evals_A, evals_B, evals_C) = - inst.compute_eval_table_sparse(inst.get_num_cons(), z.len(), &evals_rx); - - assert_eq!(evals_A.len(), evals_B.len()); - assert_eq!(evals_A.len(), evals_C.len()); - (0..evals_A.len()) - .map(|i| r_A * evals_A[i] + r_B * evals_B[i] + r_C * evals_C[i]) - .collect::>() - }; - - // another instance of the sum-check protocol - let (sc_proof_phase2, ry, _claims_phase2) = R1CSProof::::prove_phase_two( - num_rounds_y, - &claim_phase2, - &mut DensePolynomial::new(z), - &mut DensePolynomial::new(evals_ABC), - transcript, - ); - timer_sc_proof_phase2.stop(); - let transcript_sat_state = transcript.challenge_scalar(b""); - transcript.new_from_state(&transcript_sat_state); - - let timmer_opening = Timer::new("polyopening"); - - let (comm, proof_eval_vars_at_ry, mipp_proof) = - pl.open(transcript, comm_list, &gens.gens_pc.ck, &ry[1..], &t); - - timmer_opening.stop(); - - let timer_polyeval = Timer::new("polyeval"); - let eval_vars_at_ry = pl.eval(&ry[1..]); - timer_polyeval.stop(); - timer_prove.stop(); - ( - R1CSProof { - comm, - initial_state, - sc_proof_phase1, - claims_phase2: (*Az_claim, *Bz_claim, *Cz_claim, prod_Az_Bz_claims), - sc_proof_phase2, - eval_vars_at_ry, - proof_eval_vars_at_ry, - rx: rx.clone(), - ry: ry.clone(), - transcript_sat_state, - t, - mipp_proof, - }, - rx, - ry, - ) - } - - // Creates a Groth16 proof for the verification of sumcheck, expressed - // as a circuit. - pub fn prove_verifier( - &self, - num_vars: usize, - num_cons: usize, - input: &[E::ScalarField], - evals: &(E::ScalarField, E::ScalarField, E::ScalarField), - transcript: &mut PoseidonTranscript, - gens: &R1CSGens, - poseidon: PoseidonConfig, - ) -> Result, ProofVerifyError> { - // serialise and add the IPP commitment to the transcript - transcript.append_gt::(b"", &self.t); - - let initial_state = transcript.challenge_scalar(b""); - transcript.new_from_state(&initial_state); - - let mut input_as_sparse_poly_entries = vec![SparsePolyEntry::new(0, E::ScalarField::one())]; - //remaining inputs - input_as_sparse_poly_entries.extend( - (0..input.len()) - .map(|i| SparsePolyEntry::new(i + 1, input[i])) - .collect::>>(), - ); - let input_as_sparse_poly = - SparsePolynomial::new(num_vars.log_2() as usize, input_as_sparse_poly_entries); - - let config = VerifierConfig { - num_vars, - num_cons, - input: input.to_vec(), - evals: *evals, - params: poseidon, - prev_challenge: initial_state, - claims_phase2: self.claims_phase2, - polys_sc1: self.sc_proof_phase1.polys.clone(), - polys_sc2: self.sc_proof_phase2.polys.clone(), - eval_vars_at_ry: self.eval_vars_at_ry, - input_as_sparse_poly, - comm: self.comm.clone(), - rx: self.rx.clone(), - ry: self.ry.clone(), - transcript_sat_state: self.transcript_sat_state, - }; - - let circuit = R1CSVerificationCircuit::new(&config); - - let circuit_prover_timer = Timer::new("provecircuit"); - let proof = Groth16::::prove(&gens.gens_gc.pk, circuit, &mut rand::thread_rng()).unwrap(); - circuit_prover_timer.stop(); - - Ok(R1CSVerifierProof { - comm: self.comm.clone(), - circuit_proof: proof, - initial_state: self.initial_state, - transcript_sat_state: self.transcript_sat_state, - eval_vars_at_ry: self.eval_vars_at_ry, - proof_eval_vars_at_ry: self.proof_eval_vars_at_ry.clone(), - t: self.t, - mipp_proof: self.mipp_proof.clone(), - }) - } -} - -impl R1CSVerifierProof -where - ::ScalarField: Absorb, -{ - // Verifier the Groth16 proof for the sumcheck circuit and the PST polynomial - // commitment opening. - pub fn verify( - &self, - r: (Vec, Vec), - input: &[E::ScalarField], - evals: &(E::ScalarField, E::ScalarField, E::ScalarField), - transcript: &mut PoseidonTranscript, - gens: &R1CSGens, - ) -> Result { - let (rx, ry) = &r; - let (Ar, Br, Cr) = evals; - let mut pubs = vec![self.initial_state]; - pubs.extend(input.clone()); - pubs.extend(rx.clone()); - pubs.extend(ry.clone()); - pubs.extend(vec![ - self.eval_vars_at_ry, - *Ar, - *Br, - *Cr, - self.transcript_sat_state, - ]); - transcript.new_from_state(&self.transcript_sat_state); - par! { - // verifies the Groth16 proof for the spartan verifier - let is_verified = Groth16::::verify(&gens.gens_gc.vk, &pubs, &self.circuit_proof).unwrap(), - - // verifies the proof of opening against the result of evaluating the - // witness polynomial at point ry - let res = Polynomial::verify( - transcript, - &gens.gens_pc.vk, - &self.comm, - &ry[1..], - self.eval_vars_at_ry, - &self.proof_eval_vars_at_ry, - &self.mipp_proof, - &self.t, - ) - }; - assert!(is_verified == true); - assert!(res == true); - Ok(is_verified && res) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - use ark_ff::PrimeField; - use ark_std::UniformRand; - type F = ark_bls12_377::Fr; - - fn produce_tiny_r1cs() -> (R1CSInstance, Vec, Vec) { - // three constraints over five variables Z1, Z2, Z3, Z4, and Z5 - // rounded to the nearest power of two - let num_cons = 128; - let num_vars = 256; - let num_inputs = 2; - - // encode the above constraints into three matrices - let mut A: Vec<(usize, usize, F)> = Vec::new(); - let mut B: Vec<(usize, usize, F)> = Vec::new(); - let mut C: Vec<(usize, usize, F)> = Vec::new(); - - let one = F::one(); - // constraint 0 entries - // (Z1 + Z2) * I0 - Z3 = 0; - A.push((0, 0, one)); - A.push((0, 1, one)); - B.push((0, num_vars + 1, one)); - C.push((0, 2, one)); - - // constraint 1 entries - // (Z1 + I1) * (Z3) - Z4 = 0 - A.push((1, 0, one)); - A.push((1, num_vars + 2, one)); - B.push((1, 2, one)); - C.push((1, 3, one)); - // constraint 3 entries - // Z5 * 1 - 0 = 0 - A.push((2, 4, one)); - B.push((2, num_vars, one)); - - let inst = R1CSInstance::new(num_cons, num_vars, num_inputs, &A, &B, &C); - - // compute a satisfying assignment - let mut rng = ark_std::rand::thread_rng(); - let i0 = F::rand(&mut rng); - let i1 = F::rand(&mut rng); - let z1 = F::rand(&mut rng); - let z2 = F::rand(&mut rng); - let z3 = (z1 + z2) * i0; // constraint 1: (Z1 + Z2) * I0 - Z3 = 0; - let z4 = (z1 + i1) * z3; // constraint 2: (Z1 + I1) * (Z3) - Z4 = 0 - let z5 = F::zero(); //constraint 3 - - let mut vars = vec![F::zero(); num_vars]; - vars[0] = z1; - vars[1] = z2; - vars[2] = z3; - vars[3] = z4; - vars[4] = z5; - - let mut input = vec![F::zero(); num_inputs]; - input[0] = i0; - input[1] = i1; - - (inst, vars, input) - } - - #[test] - fn test_tiny_r1cs() { - let (inst, vars, input) = tests::produce_tiny_r1cs(); - let is_sat = inst.is_sat(&vars, &input); - assert!(is_sat); - } - - #[test] - fn test_synthetic_r1cs() { - type F = ark_bls12_377::Fr; - let (inst, vars, input) = R1CSInstance::::produce_synthetic_r1cs(1024, 1024, 10); - let is_sat = inst.is_sat(&vars, &input); - assert!(is_sat); - } - - use crate::parameters::PoseidonConfiguration; - #[test] - fn check_r1cs_proof_ark_blst() { - let params = ark_blst::Scalar::poseidon_params(); - check_r1cs_proof::(params); - } - #[test] - fn check_r1cs_proof_bls12_377() { - let params = ark_bls12_377::Fr::poseidon_params(); - check_r1cs_proof::(params); - } - - #[test] - fn check_r1cs_proof_bls12_381() { - let params = ark_bls12_381::Fr::poseidon_params(); - check_r1cs_proof::(params); - } - fn check_r1cs_proof

(params: PoseidonConfig) - where - P: Pairing, - P::ScalarField: PrimeField, - P::ScalarField: Absorb, - { - let num_vars = 1024; - let num_cons = num_vars; - let num_inputs = 3; - let (inst, vars, input) = - R1CSInstance::::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); - - let gens = R1CSGens::

::setup(b"test-m", num_cons, num_vars, num_inputs, params.clone()); - - //let params = poseidon_params(); - // let mut random_tape = RandomTape::new(b"proof"); - - let mut prover_transcript = PoseidonTranscript::new(¶ms.clone()); - let c = prover_transcript.challenge_scalar::(b""); - prover_transcript.new_from_state(&c); - let (proof, rx, ry) = R1CSProof::prove(&inst, vars, &input, &gens, &mut prover_transcript); - - let inst_evals = inst.evaluate(&rx, &ry); - - prover_transcript.new_from_state(&c); - let verifer_proof = proof - .prove_verifier( - num_vars, - num_cons, - &input, - &inst_evals, - &mut prover_transcript, - &gens, - params.clone(), - ) - .unwrap(); - - let mut verifier_transcript = PoseidonTranscript::new(¶ms.clone()); - assert!(verifer_proof - .verify( - (rx, ry), - &input, - &inst_evals, - &mut verifier_transcript, - &gens - ) - .is_ok()); - } -} +// #![allow(clippy::too_many_arguments)] +// use super::dense_mlpoly::{DensePolynomial, EqPolynomial, PolyCommitmentGens}; +// use super::errors::ProofVerifyError; +// use crate::constraints::{R1CSVerificationCircuit, SumcheckVerificationCircuit, VerifierConfig}; +// use crate::math::Math; +// use crate::mipp::MippProof; +// use crate::poseidon_transcript::PoseidonTranscript; +// use crate::sqrt_pst::Polynomial; +// use crate::sumcheck::SumcheckInstanceProof; +// use crate::transcript::Transcript; +// use crate::unipoly::UniPoly; +// use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; +// use ark_crypto_primitives::sponge::Absorb; +// use ark_ec::pairing::Pairing; + +// use ark_poly_commit::multilinear_pc::data_structures::{Commitment, Proof}; +// use itertools::Itertools; + +// use super::r1csinstance::R1CSInstance; + +// use super::sparse_mlpoly::{SparsePolyEntry, SparsePolynomial}; +// use super::timer::Timer; +// use ark_snark::{CircuitSpecificSetupSNARK, SNARK}; + +// use crate::ark_std::UniformRand; +// use ark_groth16::{Groth16, ProvingKey, VerifyingKey}; + +// use ark_serialize::*; +// use ark_std::{One, Zero}; + +// #[derive(CanonicalSerialize, CanonicalDeserialize, Debug)] +// pub struct R1CSProof { +// // The PST commitment to the multilinear extension of the witness. +// pub comm: Commitment, +// sc_proof_phase1: SumcheckInstanceProof, +// claims_phase2: ( +// E::ScalarField, +// E::ScalarField, +// E::ScalarField, +// E::ScalarField, +// ), +// sc_proof_phase2: SumcheckInstanceProof, +// pub eval_vars_at_ry: E::ScalarField, +// pub proof_eval_vars_at_ry: Proof, +// rx: Vec, +// ry: Vec, +// // The transcript state after the satisfiability proof was computed. +// pub transcript_sat_state: E::ScalarField, +// pub initial_state: E::ScalarField, +// pub t: E::TargetField, +// pub mipp_proof: MippProof, +// } + +// #[derive(Debug, CanonicalSerialize, CanonicalDeserialize, Clone)] +// pub struct R1CSVerifierProof { +// comm: Commitment, +// circuit_proof: ark_groth16::Proof, +// initial_state: E::ScalarField, +// transcript_sat_state: E::ScalarField, +// eval_vars_at_ry: E::ScalarField, +// proof_eval_vars_at_ry: Proof, +// t: E::TargetField, +// mipp_proof: MippProof, +// } + +// #[derive(Clone)] +// pub struct CircuitGens { +// pk: ProvingKey, +// vk: VerifyingKey, +// } + +// impl CircuitGens +// where +// E: Pairing, +// { +// // Performs the circuit-specific setup required by Groth16 for the sumcheck +// // circuit. This is done by filling the struct with dummy elements, ensuring +// // the sizes are correct so the setup matches the circuit that will be proved. +// pub fn setup( +// num_cons: usize, +// num_vars: usize, +// num_inputs: usize, +// poseidon: PoseidonConfig, +// ) -> Self { +// let mut rng = rand::thread_rng(); + +// let uni_polys_round1 = (0..num_cons.log_2()) +// .map(|_i| { +// UniPoly::::from_evals(&[ +// E::ScalarField::rand(&mut rng), +// E::ScalarField::rand(&mut rng), +// E::ScalarField::rand(&mut rng), +// E::ScalarField::rand(&mut rng), +// ]) +// }) +// .collect::>>(); + +// let uni_polys_round2 = (0..num_vars.log_2() + 1) +// .map(|_i| { +// UniPoly::::from_evals(&[ +// E::ScalarField::rand(&mut rng), +// E::ScalarField::rand(&mut rng), +// E::ScalarField::rand(&mut rng), +// ]) +// }) +// .collect::>>(); + +// let circuit = R1CSVerificationCircuit { +// num_vars: num_vars, +// num_cons: num_cons, +// input: (0..num_inputs) +// .map(|_i| E::ScalarField::rand(&mut rng)) +// .collect_vec(), +// input_as_sparse_poly: SparsePolynomial::new( +// num_vars.log_2(), +// (0..num_inputs + 1) +// .map(|i| SparsePolyEntry::new(i, E::ScalarField::rand(&mut rng))) +// .collect::>>(), +// ), +// evals: ( +// E::ScalarField::zero(), +// E::ScalarField::zero(), +// E::ScalarField::zero(), +// ), +// params: poseidon, +// prev_challenge: E::ScalarField::zero(), +// claims_phase2: ( +// E::ScalarField::zero(), +// E::ScalarField::zero(), +// E::ScalarField::zero(), +// E::ScalarField::zero(), +// ), +// eval_vars_at_ry: E::ScalarField::zero(), +// sc_phase1: SumcheckVerificationCircuit { +// polys: uni_polys_round1, +// }, +// sc_phase2: SumcheckVerificationCircuit { +// polys: uni_polys_round2, +// }, +// claimed_rx: (0..num_cons.log_2()) +// .map(|_i| E::ScalarField::rand(&mut rng)) +// .collect_vec(), +// claimed_ry: (0..num_vars.log_2() + 1) +// .map(|_i| E::ScalarField::rand(&mut rng)) +// .collect_vec(), +// claimed_transcript_sat_state: E::ScalarField::zero(), +// }; +// let (pk, vk) = Groth16::::setup(circuit.clone(), &mut rng).unwrap(); +// CircuitGens { pk, vk } +// } +// } + +// #[derive(Clone)] +// pub struct R1CSGens { +// gens_pc: PolyCommitmentGens, +// gens_gc: CircuitGens, +// } + +// impl R1CSGens { +// // Performs the setup for the polynomial commitment PST and for Groth16. +// pub fn setup( +// label: &'static [u8], +// num_cons: usize, +// num_vars: usize, +// num_inputs: usize, +// poseidon: PoseidonConfig, +// ) -> Self { +// let num_poly_vars = num_vars.log_2(); +// let gens_pc = PolyCommitmentGens::setup(num_poly_vars, label); +// let gens_gc = CircuitGens::setup(num_cons, num_vars, num_inputs, poseidon); +// R1CSGens { gens_pc, gens_gc } +// } +// } + +// impl R1CSProof +// where +// E: Pairing, +// E::ScalarField: Absorb, +// { +// fn prove_phase_one( +// num_rounds: usize, +// evals_tau: &mut DensePolynomial, +// evals_Az: &mut DensePolynomial, +// evals_Bz: &mut DensePolynomial, +// evals_Cz: &mut DensePolynomial, +// transcript: &mut PoseidonTranscript, +// ) -> ( +// SumcheckInstanceProof, +// Vec, +// Vec, +// ) { +// let comb_func = +// |poly_tau_comp: &E::ScalarField, +// poly_A_comp: &E::ScalarField, +// poly_B_comp: &E::ScalarField, +// poly_C_comp: &E::ScalarField| +// -> E::ScalarField { (*poly_tau_comp) * ((*poly_A_comp) * poly_B_comp - poly_C_comp) }; + +// let (sc_proof_phase_one, r, claims) = SumcheckInstanceProof::prove_cubic_with_additive_term( +// &E::ScalarField::zero(), // claim is zero +// num_rounds, +// evals_tau, +// evals_Az, +// evals_Bz, +// evals_Cz, +// comb_func, +// transcript, +// ); + +// (sc_proof_phase_one, r, claims) +// } + +// fn prove_phase_two( +// num_rounds: usize, +// claim: &E::ScalarField, +// evals_z: &mut DensePolynomial, +// evals_ABC: &mut DensePolynomial, +// transcript: &mut PoseidonTranscript, +// ) -> ( +// SumcheckInstanceProof, +// Vec, +// Vec, +// ) { +// let comb_func = |poly_A_comp: &E::ScalarField, +// poly_B_comp: &E::ScalarField| +// -> E::ScalarField { (*poly_A_comp) * poly_B_comp }; +// let (sc_proof_phase_two, r, claims) = SumcheckInstanceProof::prove_quad( +// claim, num_rounds, evals_z, evals_ABC, comb_func, transcript, +// ); + +// (sc_proof_phase_two, r, claims) +// } + +// // Proves the R1CS instance inst is satisfiable given the assignment +// // vars. +// pub fn prove( +// inst: &R1CSInstance, +// vars: Vec, +// input: &[E::ScalarField], +// gens: &R1CSGens, +// transcript: &mut PoseidonTranscript, +// ) -> (Self, Vec, Vec) { +// let timer_prove = Timer::new("R1CSProof::prove"); +// // we currently require the number of |inputs| + 1 to be at most number of vars +// assert!(input.len() < vars.len()); + +// // create the multilinear witness polynomial from the satisfying assiment +// // expressed as the list of sqrt-sized polynomials +// let mut pl = Polynomial::from_evaluations(&vars.clone()); + +// let timer_commit = Timer::new("polycommit"); + +// // commitment list to the satisfying witness polynomial list +// let (comm_list, t) = pl.commit(&gens.gens_pc.ck); + +// transcript.append_gt::(b"", &t); + +// timer_commit.stop(); + +// let initial_state = transcript.challenge_scalar(b""); +// transcript.new_from_state(&initial_state); + +// transcript.append_scalar_vector(b"", &input); + +// let timer_sc_proof_phase1 = Timer::new("prove_sc_phase_one"); + +// // append input to variables to create a single vector z +// let z = { +// let num_inputs = input.len(); +// let num_vars = vars.len(); +// let mut z = vars; +// z.extend(&vec![E::ScalarField::one()]); // add constant term in z +// z.extend(input); +// z.extend(&vec![E::ScalarField::zero(); num_vars - num_inputs - 1]); // we will pad with zeros +// z +// }; + +// // derive the verifier's challenge tau +// let (num_rounds_x, num_rounds_y) = (inst.get_num_cons().log_2(), z.len().log_2()); +// let tau = transcript.challenge_scalar_vec(b"", num_rounds_x); +// // compute the initial evaluation table for R(\tau, x) +// let mut poly_tau = DensePolynomial::new(EqPolynomial::new(tau).evals()); +// let (mut poly_Az, mut poly_Bz, mut poly_Cz) = +// inst.multiply_vec(inst.get_num_cons(), z.len(), &z); + +// let (sc_proof_phase1, rx, _claims_phase1) = R1CSProof::::prove_phase_one( +// num_rounds_x, +// &mut poly_tau, +// &mut poly_Az, +// &mut poly_Bz, +// &mut poly_Cz, +// transcript, +// ); +// assert_eq!(poly_tau.len(), 1); +// assert_eq!(poly_Az.len(), 1); +// assert_eq!(poly_Bz.len(), 1); +// assert_eq!(poly_Cz.len(), 1); +// timer_sc_proof_phase1.stop(); + +// let (tau_claim, Az_claim, Bz_claim, Cz_claim) = +// (&poly_tau[0], &poly_Az[0], &poly_Bz[0], &poly_Cz[0]); +// let prod_Az_Bz_claims = (*Az_claim) * Bz_claim; + +// // prove the final step of sum-check #1 +// let taus_bound_rx = tau_claim; +// let _claim_post_phase1 = ((*Az_claim) * Bz_claim - Cz_claim) * taus_bound_rx; + +// let timer_sc_proof_phase2 = Timer::new("prove_sc_phase_two"); +// // combine the three claims into a single claim +// let r_A: E::ScalarField = transcript.challenge_scalar(b""); +// let r_B: E::ScalarField = transcript.challenge_scalar(b""); +// let r_C: E::ScalarField = transcript.challenge_scalar(b""); +// let claim_phase2 = r_A * Az_claim + r_B * Bz_claim + r_C * Cz_claim; + +// let evals_ABC = { +// // compute the initial evaluation table for R(\tau, x) +// let evals_rx = EqPolynomial::new(rx.clone()).evals(); +// let (evals_A, evals_B, evals_C) = +// inst.compute_eval_table_sparse(inst.get_num_cons(), z.len(), &evals_rx); + +// assert_eq!(evals_A.len(), evals_B.len()); +// assert_eq!(evals_A.len(), evals_C.len()); +// (0..evals_A.len()) +// .map(|i| r_A * evals_A[i] + r_B * evals_B[i] + r_C * evals_C[i]) +// .collect::>() +// }; + +// // another instance of the sum-check protocol +// let (sc_proof_phase2, ry, _claims_phase2) = R1CSProof::::prove_phase_two( +// num_rounds_y, +// &claim_phase2, +// &mut DensePolynomial::new(z), +// &mut DensePolynomial::new(evals_ABC), +// transcript, +// ); +// timer_sc_proof_phase2.stop(); +// let transcript_sat_state = transcript.challenge_scalar(b""); +// transcript.new_from_state(&transcript_sat_state); + +// let timmer_opening = Timer::new("polyopening"); + +// let (comm, proof_eval_vars_at_ry, mipp_proof) = +// pl.open(transcript, comm_list, &gens.gens_pc.ck, &ry[1..], &t); + +// timmer_opening.stop(); + +// let timer_polyeval = Timer::new("polyeval"); +// let eval_vars_at_ry = pl.eval(&ry[1..]); +// timer_polyeval.stop(); +// timer_prove.stop(); +// ( +// R1CSProof { +// comm, +// initial_state, +// sc_proof_phase1, +// claims_phase2: (*Az_claim, *Bz_claim, *Cz_claim, prod_Az_Bz_claims), +// sc_proof_phase2, +// eval_vars_at_ry, +// proof_eval_vars_at_ry, +// rx: rx.clone(), +// ry: ry.clone(), +// transcript_sat_state, +// t, +// mipp_proof, +// }, +// rx, +// ry, +// ) +// } + +// // Creates a Groth16 proof for the verification of sumcheck, expressed +// // as a circuit. +// pub fn prove_verifier( +// &self, +// num_vars: usize, +// num_cons: usize, +// input: &[E::ScalarField], +// evals: &(E::ScalarField, E::ScalarField, E::ScalarField), +// transcript: &mut PoseidonTranscript, +// gens: &R1CSGens, +// poseidon: PoseidonConfig, +// ) -> Result, ProofVerifyError> { +// // serialise and add the IPP commitment to the transcript +// transcript.append_gt::(b"", &self.t); + +// let initial_state = transcript.challenge_scalar(b""); +// transcript.new_from_state(&initial_state); + +// let mut input_as_sparse_poly_entries = vec![SparsePolyEntry::new(0, E::ScalarField::one())]; +// //remaining inputs +// input_as_sparse_poly_entries.extend( +// (0..input.len()) +// .map(|i| SparsePolyEntry::new(i + 1, input[i])) +// .collect::>>(), +// ); +// let input_as_sparse_poly = +// SparsePolynomial::new(num_vars.log_2() as usize, input_as_sparse_poly_entries); + +// let config = VerifierConfig { +// num_vars, +// num_cons, +// input: input.to_vec(), +// evals: *evals, +// params: poseidon, +// prev_challenge: initial_state, +// claims_phase2: self.claims_phase2, +// polys_sc1: self.sc_proof_phase1.polys.clone(), +// polys_sc2: self.sc_proof_phase2.polys.clone(), +// eval_vars_at_ry: self.eval_vars_at_ry, +// input_as_sparse_poly, +// comm: self.comm.clone(), +// rx: self.rx.clone(), +// ry: self.ry.clone(), +// transcript_sat_state: self.transcript_sat_state, +// }; + +// let circuit = R1CSVerificationCircuit::new(&config); + +// let circuit_prover_timer = Timer::new("provecircuit"); +// let proof = Groth16::::prove(&gens.gens_gc.pk, circuit, &mut rand::thread_rng()).unwrap(); +// circuit_prover_timer.stop(); + +// Ok(R1CSVerifierProof { +// comm: self.comm.clone(), +// circuit_proof: proof, +// initial_state: self.initial_state, +// transcript_sat_state: self.transcript_sat_state, +// eval_vars_at_ry: self.eval_vars_at_ry, +// proof_eval_vars_at_ry: self.proof_eval_vars_at_ry.clone(), +// t: self.t, +// mipp_proof: self.mipp_proof.clone(), +// }) +// } +// } + +// impl R1CSVerifierProof +// where +// ::ScalarField: Absorb, +// { +// // Verifier the Groth16 proof for the sumcheck circuit and the PST polynomial +// // commitment opening. +// pub fn verify( +// &self, +// r: (Vec, Vec), +// input: &[E::ScalarField], +// evals: &(E::ScalarField, E::ScalarField, E::ScalarField), +// transcript: &mut PoseidonTranscript, +// gens: &R1CSGens, +// ) -> Result { +// let (rx, ry) = &r; +// let (Ar, Br, Cr) = evals; +// let mut pubs = vec![self.initial_state]; +// pubs.extend(input.clone()); +// pubs.extend(rx.clone()); +// pubs.extend(ry.clone()); +// pubs.extend(vec![ +// self.eval_vars_at_ry, +// *Ar, +// *Br, +// *Cr, +// self.transcript_sat_state, +// ]); +// transcript.new_from_state(&self.transcript_sat_state); +// par! { +// // verifies the Groth16 proof for the spartan verifier +// let is_verified = Groth16::::verify(&gens.gens_gc.vk, &pubs, &self.circuit_proof).unwrap(), + +// // verifies the proof of opening against the result of evaluating the +// // witness polynomial at point ry +// let res = Polynomial::verify( +// transcript, +// &gens.gens_pc.vk, +// &self.comm, +// &ry[1..], +// self.eval_vars_at_ry, +// &self.proof_eval_vars_at_ry, +// &self.mipp_proof, +// &self.t, +// ) +// }; +// assert!(is_verified == true); +// assert!(res == true); +// Ok(is_verified && res) +// } +// } + +// #[cfg(test)] +// mod tests { + +// use super::*; + +// use ark_ff::PrimeField; +// use ark_std::UniformRand; +// type F = ark_bls12_377::Fr; + +// fn produce_tiny_r1cs() -> (R1CSInstance, Vec, Vec) { +// // three constraints over five variables Z1, Z2, Z3, Z4, and Z5 +// // rounded to the nearest power of two +// let num_cons = 128; +// let num_vars = 256; +// let num_inputs = 2; + +// // encode the above constraints into three matrices +// let mut A: Vec<(usize, usize, F)> = Vec::new(); +// let mut B: Vec<(usize, usize, F)> = Vec::new(); +// let mut C: Vec<(usize, usize, F)> = Vec::new(); + +// let one = F::one(); +// // constraint 0 entries +// // (Z1 + Z2) * I0 - Z3 = 0; +// A.push((0, 0, one)); +// A.push((0, 1, one)); +// B.push((0, num_vars + 1, one)); +// C.push((0, 2, one)); + +// // constraint 1 entries +// // (Z1 + I1) * (Z3) - Z4 = 0 +// A.push((1, 0, one)); +// A.push((1, num_vars + 2, one)); +// B.push((1, 2, one)); +// C.push((1, 3, one)); +// // constraint 3 entries +// // Z5 * 1 - 0 = 0 +// A.push((2, 4, one)); +// B.push((2, num_vars, one)); + +// let inst = R1CSInstance::new(num_cons, num_vars, num_inputs, &A, &B, &C); + +// // compute a satisfying assignment +// let mut rng = ark_std::rand::thread_rng(); +// let i0 = F::rand(&mut rng); +// let i1 = F::rand(&mut rng); +// let z1 = F::rand(&mut rng); +// let z2 = F::rand(&mut rng); +// let z3 = (z1 + z2) * i0; // constraint 1: (Z1 + Z2) * I0 - Z3 = 0; +// let z4 = (z1 + i1) * z3; // constraint 2: (Z1 + I1) * (Z3) - Z4 = 0 +// let z5 = F::zero(); //constraint 3 + +// let mut vars = vec![F::zero(); num_vars]; +// vars[0] = z1; +// vars[1] = z2; +// vars[2] = z3; +// vars[3] = z4; +// vars[4] = z5; + +// let mut input = vec![F::zero(); num_inputs]; +// input[0] = i0; +// input[1] = i1; + +// (inst, vars, input) +// } + +// #[test] +// fn test_tiny_r1cs() { +// let (inst, vars, input) = tests::produce_tiny_r1cs(); +// let is_sat = inst.is_sat(&vars, &input); +// assert!(is_sat); +// } + +// #[test] +// fn test_synthetic_r1cs() { +// type F = ark_bls12_377::Fr; +// let (inst, vars, input) = R1CSInstance::::produce_synthetic_r1cs(1024, 1024, 10); +// let is_sat = inst.is_sat(&vars, &input); +// assert!(is_sat); +// } + +// use crate::parameters::PoseidonConfiguration; +// #[test] +// fn check_r1cs_proof_ark_blst() { +// let params = ark_blst::Scalar::poseidon_params(); +// check_r1cs_proof::(params); +// } +// #[test] +// fn check_r1cs_proof_bls12_377() { +// let params = ark_bls12_377::Fr::poseidon_params(); +// check_r1cs_proof::(params); +// } + +// #[test] +// fn check_r1cs_proof_bls12_381() { +// let params = ark_bls12_381::Fr::poseidon_params(); +// check_r1cs_proof::(params); +// } +// fn check_r1cs_proof

(params: PoseidonConfig) +// where +// P: Pairing, +// P::ScalarField: PrimeField, +// P::ScalarField: Absorb, +// { +// let num_vars = 1024; +// let num_cons = num_vars; +// let num_inputs = 3; +// let (inst, vars, input) = +// R1CSInstance::::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); + +// let gens = R1CSGens::

::setup(b"test-m", num_cons, num_vars, num_inputs, params.clone()); + +// //let params = poseidon_params(); +// // let mut random_tape = RandomTape::new(b"proof"); + +// let mut prover_transcript = PoseidonTranscript::new(¶ms.clone()); +// let c = prover_transcript.challenge_scalar::(b""); +// prover_transcript.new_from_state(&c); +// let (proof, rx, ry) = R1CSProof::prove(&inst, vars, &input, &gens, &mut prover_transcript); + +// let inst_evals = inst.evaluate(&rx, &ry); + +// prover_transcript.new_from_state(&c); +// let verifer_proof = proof +// .prove_verifier( +// num_vars, +// num_cons, +// &input, +// &inst_evals, +// &mut prover_transcript, +// &gens, +// params.clone(), +// ) +// .unwrap(); + +// let mut verifier_transcript = PoseidonTranscript::new(¶ms.clone()); +// assert!(verifer_proof +// .verify( +// (rx, ry), +// &input, +// &inst_evals, +// &mut verifier_transcript, +// &gens +// ) +// .is_ok()); +// } +// } diff --git a/src/sqrt_pst.rs b/src/sqrt_pst.rs index e4aec374..82774ece 100644 --- a/src/sqrt_pst.rs +++ b/src/sqrt_pst.rs @@ -167,7 +167,7 @@ impl Polynomial { pub fn open( &mut self, - transcript: &mut PoseidonTranscript, + transcript: &mut PoseidonTranscript, comm_list: Vec>, ck: &CommitterKey, point: &[E::ScalarField], @@ -230,7 +230,7 @@ impl Polynomial { } pub fn verify( - transcript: &mut PoseidonTranscript, + transcript: &mut PoseidonTranscript, vk: &VerifierKey, U: &Commitment, point: &[E::ScalarField], @@ -267,7 +267,7 @@ impl Polynomial { #[cfg(test)] mod tests { - use crate::parameters::poseidon_params; + use crate::parameters::{get_bls12377_fq_params}; use super::*; type F = ark_bls12_377::Fr; @@ -321,7 +321,7 @@ mod tests { let (comm_list, t) = pl.commit(&ck); - let params = poseidon_params(); + let params = get_bls12377_fq_params(); let mut prover_transcript = PoseidonTranscript::new(¶ms); let (u, pst_proof, mipp_proof) = pl.open(&mut prover_transcript, comm_list, &ck, &r, &t); diff --git a/src/sumcheck.rs b/src/sumcheck.rs index 8c728e09..e43232a1 100644 --- a/src/sumcheck.rs +++ b/src/sumcheck.rs @@ -13,6 +13,8 @@ use ark_serialize::*; use itertools::izip; +use ark_ec::pairing::Pairing; + #[derive(CanonicalSerialize, CanonicalDeserialize, Debug)] pub struct SumcheckInstanceProof { pub polys: Vec>, @@ -61,7 +63,7 @@ impl SumcheckInstanceProof { } impl SumcheckInstanceProof { - pub fn prove_cubic_with_additive_term( + pub fn prove_cubic_with_additive_term( claim: &F, num_rounds: usize, poly_tau: &mut DensePolynomial, @@ -69,10 +71,11 @@ impl SumcheckInstanceProof { poly_B: &mut DensePolynomial, poly_C: &mut DensePolynomial, comb_func: C, - transcript: &mut PoseidonTranscript, + transcript: &mut PoseidonTranscript, ) -> (Self, Vec, Vec) where C: Fn(&F, &F, &F, &F) -> F, + E: Pairing, { let mut e = *claim; let mut r: Vec = Vec::new(); @@ -118,7 +121,11 @@ impl SumcheckInstanceProof { let poly = UniPoly::from_evals(&evals); // append the prover's message to the transcript - poly.write_to_transcript(transcript); + //poly.write_to_transcript(transcript); + + for i in 0..poly.coeffs.len() { + transcript.append_scalar(b"", &poly.coeffs[i]); + } //derive the verifier's challenge for the next round let r_j = transcript.challenge_scalar(b""); r.push(r_j); @@ -376,16 +383,17 @@ impl SumcheckInstanceProof { ) } - pub fn prove_quad( + pub fn prove_quad( claim: &F, num_rounds: usize, poly_A: &mut DensePolynomial, poly_B: &mut DensePolynomial, comb_func: C, - transcript: &mut PoseidonTranscript, + transcript: &mut PoseidonTranscript, ) -> (Self, Vec, Vec) where C: Fn(&F, &F) -> F, + E: Pairing, { let mut e = *claim; let mut r: Vec = Vec::new(); @@ -410,7 +418,10 @@ impl SumcheckInstanceProof { let poly = UniPoly::from_evals(&evals); // append the prover's message to the transcript - poly.write_to_transcript(transcript); + //poly.write_to_transcript(transcript); + for i in 0..poly.coeffs.len() { + transcript.append_scalar(b"", &poly.coeffs[i]); + } //derive the verifier's challenge for the next round let r_j = transcript.challenge_scalar(b""); diff --git a/src/testudo_nizk.rs b/src/testudo_nizk.rs index a456a603..b408804a 100644 --- a/src/testudo_nizk.rs +++ b/src/testudo_nizk.rs @@ -1,202 +1,202 @@ -use std::cmp::max; - -use crate::errors::ProofVerifyError; -use crate::r1csproof::R1CSVerifierProof; -use crate::{ - poseidon_transcript::PoseidonTranscript, - r1csproof::{R1CSGens, R1CSProof}, - transcript::Transcript, - InputsAssignment, Instance, VarsAssignment, -}; -use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::pairing::Pairing; - -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; - -#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)] - -// TestudoNizk is suitable for uniform circuits where the -// evaluation of R1CS matrices A, B and C is cheap and can -// be done by the verifier. For more complex circuits this -// operation has to be offloaded to the prover. -pub struct TestudoNizk { - pub r1cs_verifier_proof: R1CSVerifierProof, - pub r: (Vec, Vec), -} - -pub struct TestudoNizkGens { - gens_r1cs_sat: R1CSGens, -} - -impl TestudoNizkGens { - /// Performs the setup required by the polynomial commitment PST and Groth16 - pub fn setup( - num_cons: usize, - num_vars: usize, - num_inputs: usize, - poseidon: PoseidonConfig, - ) -> Self { - // ensure num_vars is a power of 2 - let num_vars_padded = { - let mut num_vars_padded = max(num_vars, num_inputs + 1); - if num_vars_padded != num_vars_padded.next_power_of_two() { - num_vars_padded = num_vars_padded.next_power_of_two(); - } - num_vars_padded - }; - - let num_cons_padded = { - let mut num_cons_padded = num_cons; - - // ensure that num_cons_padded is at least 2 - if num_cons_padded == 0 || num_cons_padded == 1 { - num_cons_padded = 2; - } - - // ensure that num_cons_padded is a power of 2 - if num_cons.next_power_of_two() != num_cons { - num_cons_padded = num_cons.next_power_of_two(); - } - num_cons_padded - }; - - let gens_r1cs_sat = R1CSGens::setup( - b"gens_r1cs_sat", - num_cons_padded, - num_vars_padded, - num_inputs, - poseidon, - ); - TestudoNizkGens { gens_r1cs_sat } - } -} - -impl TestudoNizk -where - E::ScalarField: Absorb, -{ - // Returns a proof that the R1CS instance is satisfiable - pub fn prove( - inst: &Instance, - vars: VarsAssignment, - inputs: &InputsAssignment, - gens: &TestudoNizkGens, - transcript: &mut PoseidonTranscript, - poseidon: PoseidonConfig, - ) -> Result, ProofVerifyError> { - transcript.append_bytes(b"", &inst.digest); - - let c: E::ScalarField = transcript.challenge_scalar(b""); - transcript.new_from_state(&c); - - // we might need to pad variables - let padded_vars = { - let num_padded_vars = inst.inst.get_num_vars(); - let num_vars = vars.assignment.len(); - if num_padded_vars > num_vars { - vars.pad(num_padded_vars) - } else { - vars - } - }; - - let (r1cs_sat_proof, rx, ry) = R1CSProof::prove( - &inst.inst, - padded_vars.assignment, - &inputs.assignment, - &gens.gens_r1cs_sat, - transcript, - ); - - let inst_evals = inst.inst.evaluate(&rx, &ry); - - transcript.new_from_state(&c); - let r1cs_verifier_proof = r1cs_sat_proof - .prove_verifier( - inst.inst.get_num_vars(), - inst.inst.get_num_cons(), - &inputs.assignment, - &inst_evals, - transcript, - &gens.gens_r1cs_sat, - poseidon, - ) - .unwrap(); - Ok(TestudoNizk { - r1cs_verifier_proof, - r: (rx, ry), - }) - } - - // Verifies the satisfiability proof for the R1CS instance. In NIZK mode, the - // verifier evaluates matrices A, B and C themselves, which is a linear - // operation and hence this is not a SNARK. - // However, for highly structured circuits this operation is fast. - pub fn verify( - &self, - gens: &TestudoNizkGens, - inst: &Instance, - input: &InputsAssignment, - transcript: &mut PoseidonTranscript, - _poseidon: PoseidonConfig, - ) -> Result { - transcript.append_bytes(b"", &inst.digest); - let (claimed_rx, claimed_ry) = &self.r; - let inst_evals = inst.inst.evaluate(claimed_rx, claimed_ry); - - let sat_verified = self.r1cs_verifier_proof.verify( - (claimed_rx.clone(), claimed_ry.clone()), - &input.assignment, - &inst_evals, - transcript, - &gens.gens_r1cs_sat, - )?; - assert!(sat_verified == true); - Ok(sat_verified) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - parameters::poseidon_params, - poseidon_transcript::PoseidonTranscript, - testudo_nizk::{TestudoNizk, TestudoNizkGens}, - Instance, - }; - - #[test] - pub fn check_testudo_nizk() { - let num_vars = 256; - let num_cons = num_vars; - let num_inputs = 10; - - type E = ark_bls12_377::Bls12_377; - - // produce public generators - let gens = TestudoNizkGens::::setup(num_cons, num_vars, num_inputs, poseidon_params()); - - // produce a synthetic R1CSInstance - let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); - - let params = poseidon_params(); - - // produce a proof - let mut prover_transcript = PoseidonTranscript::new(¶ms); - let proof = - TestudoNizk::prove(&inst, vars, &inputs, &gens, &mut prover_transcript, params).unwrap(); - - // verify the proof - let mut verifier_transcript = PoseidonTranscript::new(&poseidon_params()); - assert!(proof - .verify( - &gens, - &inst, - &inputs, - &mut verifier_transcript, - poseidon_params() - ) - .is_ok()); - } -} +// use std::cmp::max; + +// use crate::errors::ProofVerifyError; +// use crate::r1csproof::R1CSVerifierProof; +// use crate::{ +// poseidon_transcript::PoseidonTranscript, +// r1csproof::{R1CSGens, R1CSProof}, +// transcript::Transcript, +// InputsAssignment, Instance, VarsAssignment, +// }; +// use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; +// use ark_crypto_primitives::sponge::Absorb; +// use ark_ec::pairing::Pairing; + +// use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + +// #[derive(Debug, CanonicalSerialize, CanonicalDeserialize)] + +// // TestudoNizk is suitable for uniform circuits where the +// // evaluation of R1CS matrices A, B and C is cheap and can +// // be done by the verifier. For more complex circuits this +// // operation has to be offloaded to the prover. +// pub struct TestudoNizk { +// pub r1cs_verifier_proof: R1CSVerifierProof, +// pub r: (Vec, Vec), +// } + +// pub struct TestudoNizkGens { +// gens_r1cs_sat: R1CSGens, +// } + +// impl TestudoNizkGens { +// /// Performs the setup required by the polynomial commitment PST and Groth16 +// pub fn setup( +// num_cons: usize, +// num_vars: usize, +// num_inputs: usize, +// poseidon: PoseidonConfig, +// ) -> Self { +// // ensure num_vars is a power of 2 +// let num_vars_padded = { +// let mut num_vars_padded = max(num_vars, num_inputs + 1); +// if num_vars_padded != num_vars_padded.next_power_of_two() { +// num_vars_padded = num_vars_padded.next_power_of_two(); +// } +// num_vars_padded +// }; + +// let num_cons_padded = { +// let mut num_cons_padded = num_cons; + +// // ensure that num_cons_padded is at least 2 +// if num_cons_padded == 0 || num_cons_padded == 1 { +// num_cons_padded = 2; +// } + +// // ensure that num_cons_padded is a power of 2 +// if num_cons.next_power_of_two() != num_cons { +// num_cons_padded = num_cons.next_power_of_two(); +// } +// num_cons_padded +// }; + +// let gens_r1cs_sat = R1CSGens::setup( +// b"gens_r1cs_sat", +// num_cons_padded, +// num_vars_padded, +// num_inputs, +// poseidon, +// ); +// TestudoNizkGens { gens_r1cs_sat } +// } +// } + +// impl TestudoNizk +// where +// E::ScalarField: Absorb, +// { +// // Returns a proof that the R1CS instance is satisfiable +// pub fn prove( +// inst: &Instance, +// vars: VarsAssignment, +// inputs: &InputsAssignment, +// gens: &TestudoNizkGens, +// transcript: &mut PoseidonTranscript, +// poseidon: PoseidonConfig, +// ) -> Result, ProofVerifyError> { +// transcript.append_bytes(b"", &inst.digest); + +// let c: E::ScalarField = transcript.challenge_scalar(b""); +// transcript.new_from_state(&c); + +// // we might need to pad variables +// let padded_vars = { +// let num_padded_vars = inst.inst.get_num_vars(); +// let num_vars = vars.assignment.len(); +// if num_padded_vars > num_vars { +// vars.pad(num_padded_vars) +// } else { +// vars +// } +// }; + +// let (r1cs_sat_proof, rx, ry) = R1CSProof::prove( +// &inst.inst, +// padded_vars.assignment, +// &inputs.assignment, +// &gens.gens_r1cs_sat, +// transcript, +// ); + +// let inst_evals = inst.inst.evaluate(&rx, &ry); + +// transcript.new_from_state(&c); +// let r1cs_verifier_proof = r1cs_sat_proof +// .prove_verifier( +// inst.inst.get_num_vars(), +// inst.inst.get_num_cons(), +// &inputs.assignment, +// &inst_evals, +// transcript, +// &gens.gens_r1cs_sat, +// poseidon, +// ) +// .unwrap(); +// Ok(TestudoNizk { +// r1cs_verifier_proof, +// r: (rx, ry), +// }) +// } + +// // Verifies the satisfiability proof for the R1CS instance. In NIZK mode, the +// // verifier evaluates matrices A, B and C themselves, which is a linear +// // operation and hence this is not a SNARK. +// // However, for highly structured circuits this operation is fast. +// pub fn verify( +// &self, +// gens: &TestudoNizkGens, +// inst: &Instance, +// input: &InputsAssignment, +// transcript: &mut PoseidonTranscript, +// _poseidon: PoseidonConfig, +// ) -> Result { +// transcript.append_bytes(b"", &inst.digest); +// let (claimed_rx, claimed_ry) = &self.r; +// let inst_evals = inst.inst.evaluate(claimed_rx, claimed_ry); + +// let sat_verified = self.r1cs_verifier_proof.verify( +// (claimed_rx.clone(), claimed_ry.clone()), +// &input.assignment, +// &inst_evals, +// transcript, +// &gens.gens_r1cs_sat, +// )?; +// assert!(sat_verified == true); +// Ok(sat_verified) +// } +// } + +// #[cfg(test)] +// mod tests { +// use crate::{ +// parameters::poseidon_params, +// poseidon_transcript::PoseidonTranscript, +// testudo_nizk::{TestudoNizk, TestudoNizkGens}, +// Instance, +// }; + +// #[test] +// pub fn check_testudo_nizk() { +// let num_vars = 256; +// let num_cons = num_vars; +// let num_inputs = 10; + +// type E = ark_bls12_377::Bls12_377; + +// // produce public generators +// let gens = TestudoNizkGens::::setup(num_cons, num_vars, num_inputs, poseidon_params()); + +// // produce a synthetic R1CSInstance +// let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); + +// let params = poseidon_params(); + +// // produce a proof +// let mut prover_transcript = PoseidonTranscript::new(¶ms); +// let proof = +// TestudoNizk::prove(&inst, vars, &inputs, &gens, &mut prover_transcript, params).unwrap(); + +// // verify the proof +// let mut verifier_transcript = PoseidonTranscript::new(&poseidon_params()); +// assert!(proof +// .verify( +// &gens, +// &inst, +// &inputs, +// &mut verifier_transcript, +// poseidon_params() +// ) +// .is_ok()); +// } +// } diff --git a/src/testudo_snark.rs b/src/testudo_snark.rs index e6cb430a..d8a6fb33 100644 --- a/src/testudo_snark.rs +++ b/src/testudo_snark.rs @@ -1,377 +1,377 @@ -use std::cmp::max; - -use crate::errors::ProofVerifyError; -use crate::r1csinstance::{R1CSCommitmentGens, R1CSEvalProof}; -use crate::r1csproof::R1CSVerifierProof; - -use crate::timer::Timer; -use crate::transcript::TranscriptWriter; -use crate::{ - poseidon_transcript::PoseidonTranscript, - r1csproof::{R1CSGens, R1CSProof}, - transcript::Transcript, - InputsAssignment, Instance, VarsAssignment, -}; -use crate::{ComputationCommitment, ComputationDecommitment}; -use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::pairing::Pairing; - -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; - -#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)] - -pub struct TestudoSnark { - pub r1cs_verifier_proof: R1CSVerifierProof, - pub r1cs_eval_proof: R1CSEvalProof, - pub inst_evals: (E::ScalarField, E::ScalarField, E::ScalarField), - pub r: (Vec, Vec), -} - -pub struct TestudoSnarkGens { - gens_r1cs_sat: R1CSGens, - gens_r1cs_eval: R1CSCommitmentGens, -} - -impl TestudoSnarkGens { - /// Performs the setups required by the polynomial commitment PST, Groth16 - /// and the computational commitment given the size of the R1CS statement, - /// `num_nz_entries` specifies the maximum number of non-zero entries in - /// any of the three R1CS matrices. - pub fn setup( - num_cons: usize, - num_vars: usize, - num_inputs: usize, - num_nz_entries: usize, - poseidon: PoseidonConfig, - ) -> Self { - // ensure num_vars is a power of 2 - let num_vars_padded = { - let mut num_vars_padded = max(num_vars, num_inputs + 1); - if num_vars_padded != num_vars_padded.next_power_of_two() { - num_vars_padded = num_vars_padded.next_power_of_two(); - } - num_vars_padded - }; - - let num_cons_padded = { - let mut num_cons_padded = num_cons; - - // ensure that num_cons_padded is at least 2 - if num_cons_padded == 0 || num_cons_padded == 1 { - num_cons_padded = 2; - } - - // ensure that num_cons_padded is a power of 2 - if num_cons.next_power_of_two() != num_cons { - num_cons_padded = num_cons.next_power_of_two(); - } - num_cons_padded - }; - - let gens_r1cs_sat = R1CSGens::setup( - b"gens_r1cs_sat", - num_cons_padded, - num_vars_padded, - num_inputs, - poseidon, - ); - let gens_r1cs_eval = R1CSCommitmentGens::setup( - b"gens_r1cs_eval", - num_cons_padded, - num_vars_padded, - num_inputs, - num_nz_entries, - ); - TestudoSnarkGens { - gens_r1cs_sat, - gens_r1cs_eval, - } - } -} - -impl TestudoSnark -where - E::ScalarField: Absorb, -{ - // Constructs the computational commitment, used to prove that the - // evaluations of matrices A, B and C sent by the prover to the verifier - // are correct. - pub fn encode( - inst: &Instance, - gens: &TestudoSnarkGens, - ) -> ( - ComputationCommitment, - ComputationDecommitment, - ) { - let timer_encode = Timer::new("SNARK::encode"); - let (comm, decomm) = inst.inst.commit(&gens.gens_r1cs_eval); - timer_encode.stop(); - ( - ComputationCommitment { comm }, - ComputationDecommitment { decomm }, - ) - } - - // Returns the Testudo SNARK proof which has two components: - // * proof that the R1CS instance is satisfiable - // * proof that the evlauation of matrices A, B and C on point (x,y) - // resulted from the two rounda of sumcheck are correct - pub fn prove( - inst: &Instance, - comm: &ComputationCommitment, - decomm: &ComputationDecommitment, - vars: VarsAssignment, - inputs: &InputsAssignment, - gens: &TestudoSnarkGens, - transcript: &mut PoseidonTranscript, - poseidon: PoseidonConfig, - ) -> Result, ProofVerifyError> { - comm.comm.write_to_transcript(transcript); - let c: E::ScalarField = transcript.challenge_scalar(b""); - transcript.new_from_state(&c); - - // we might need to pad variables - let padded_vars = { - let num_padded_vars = inst.inst.get_num_vars(); - let num_vars = vars.assignment.len(); - if num_padded_vars > num_vars { - vars.pad(num_padded_vars) - } else { - vars - } - }; - - let (r1cs_sat_proof, rx, ry) = R1CSProof::prove( - &inst.inst, - padded_vars.assignment, - &inputs.assignment, - &gens.gens_r1cs_sat, - transcript, - ); - - // We send evaluations of A, B, C at r = (rx, ry) as claims - // to enable the verifier complete the first sum-check - let timer_eval = Timer::new("eval_sparse_polys"); - let inst_evals = { - let (Ar, Br, Cr) = inst.inst.evaluate(&rx, &ry); - transcript.append_scalar(b"", &Ar); - transcript.append_scalar(b"", &Br); - transcript.append_scalar(b"", &Cr); - (Ar, Br, Cr) - }; - timer_eval.stop(); - - let timer_eval_proof = Timer::new("r1cs_eval_proof"); - let r1cs_eval_proof = R1CSEvalProof::prove( - &decomm.decomm, - &rx, - &ry, - &inst_evals, - &gens.gens_r1cs_eval, - transcript, - ); - timer_eval_proof.stop(); - - transcript.new_from_state(&c); - let timer_sat_circuit_verification = Timer::new("r1cs_sat_circuit_verification"); - let r1cs_verifier_proof = r1cs_sat_proof - .prove_verifier( - inst.inst.get_num_vars(), - inst.inst.get_num_cons(), - &inputs.assignment, - &inst_evals, - transcript, - &gens.gens_r1cs_sat, - poseidon, - ) - .unwrap(); - timer_sat_circuit_verification.stop(); - Ok(TestudoSnark { - r1cs_verifier_proof, - r1cs_eval_proof, - inst_evals, - r: (rx, ry), - }) - } - - pub fn verify( - &self, - gens: &TestudoSnarkGens, - comm: &ComputationCommitment, - input: &InputsAssignment, - transcript: &mut PoseidonTranscript, - _poseidon: PoseidonConfig, - ) -> Result { - let (rx, ry) = &self.r; - - let timer_sat_verification = Timer::new("r1cs_sat_verification"); - let sat_verified = self.r1cs_verifier_proof.verify( - (rx.clone(), ry.clone()), - &input.assignment, - &self.inst_evals, - transcript, - &gens.gens_r1cs_sat, - )?; - timer_sat_verification.stop(); - assert!(sat_verified == true); - - let (Ar, Br, Cr) = &self.inst_evals; - transcript.append_scalar(b"", Ar); - transcript.append_scalar(b"", Br); - transcript.append_scalar(b"", Cr); - - let timer_eval_verification = Timer::new("r1cs_eval_verification"); - let eval_verified = self.r1cs_eval_proof.verify( - &comm.comm, - rx, - ry, - &self.inst_evals, - &gens.gens_r1cs_eval, - transcript, - ); - timer_eval_verification.stop(); - Ok(sat_verified && eval_verified.is_ok()) - } -} - -#[cfg(test)] -mod tests { - - use crate::ark_std::Zero; - use crate::{ - parameters::poseidon_params, - poseidon_transcript::PoseidonTranscript, - testudo_snark::{TestudoSnark, TestudoSnarkGens}, - InputsAssignment, Instance, VarsAssignment, - }; - use ark_ff::{BigInteger, One, PrimeField}; - - #[test] - pub fn check_testudo_snark() { - let num_vars = 256; - let num_cons = num_vars; - let num_inputs = 10; - - type E = ark_bls12_377::Bls12_377; - - // produce public generators - let gens = - TestudoSnarkGens::::setup(num_cons, num_vars, num_inputs, num_cons, poseidon_params()); - - // produce a synthetic R1CSInstance - let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); - - // create a commitment to R1CSInstance - let (comm, decomm) = TestudoSnark::encode(&inst, &gens); - - let params = poseidon_params(); - - // produce a proof - let mut prover_transcript = PoseidonTranscript::new(¶ms); - let proof = TestudoSnark::prove( - &inst, - &comm, - &decomm, - vars, - &inputs, - &gens, - &mut prover_transcript, - params, - ) - .unwrap(); - - // verify the proof - let mut verifier_transcript = PoseidonTranscript::new(&poseidon_params()); - assert!(proof - .verify( - &gens, - &comm, - &inputs, - &mut verifier_transcript, - poseidon_params() - ) - .is_ok()); - } - - #[test] - fn test_padded_constraints() { - type F = ark_bls12_377::Fr; - type E = ark_bls12_377::Bls12_377; - // parameters of the R1CS instance - let num_cons = 1; - let num_vars = 0; - let num_inputs = 3; - let num_non_zero_entries = 3; - - // We will encode the above constraints into three matrices, where - // the coefficients in the matrix are in the little-endian byte order - let mut A: Vec<(usize, usize, Vec)> = Vec::new(); - let mut B: Vec<(usize, usize, Vec)> = Vec::new(); - let mut C: Vec<(usize, usize, Vec)> = Vec::new(); - - // Create a^2 + b + 13 - A.push((0, num_vars + 2, (F::one().into_bigint().to_bytes_le()))); // 1*a - B.push((0, num_vars + 2, F::one().into_bigint().to_bytes_le())); // 1*a - C.push((0, num_vars + 1, F::one().into_bigint().to_bytes_le())); // 1*z - C.push((0, num_vars, (-F::from(13u64)).into_bigint().to_bytes_le())); // -13*1 - C.push((0, num_vars + 3, (-F::one()).into_bigint().to_bytes_le())); // -1*b - - // Var Assignments (Z_0 = 16 is the only output) - let vars = vec![F::zero().into_bigint().to_bytes_le(); num_vars]; - - // create an InputsAssignment (a = 1, b = 2) - let mut inputs = vec![F::zero().into_bigint().to_bytes_le(); num_inputs]; - inputs[0] = F::from(16u64).into_bigint().to_bytes_le(); - inputs[1] = F::from(1u64).into_bigint().to_bytes_le(); - inputs[2] = F::from(2u64).into_bigint().to_bytes_le(); - - let assignment_inputs = InputsAssignment::::new(&inputs).unwrap(); - let assignment_vars = VarsAssignment::new(&vars).unwrap(); - - // Check if instance is satisfiable - let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap(); - let res = inst.is_sat(&assignment_vars, &assignment_inputs); - assert!(res.unwrap(), "should be satisfied"); - - // Testudo public params - let gens = TestudoSnarkGens::::setup( - num_cons, - num_vars, - num_inputs, - num_non_zero_entries, - poseidon_params(), - ); - - // create a commitment to the R1CS instance - let (comm, decomm) = TestudoSnark::encode(&inst, &gens); - - let params = poseidon_params(); - - // produce a TestudoSnark - let mut prover_transcript = PoseidonTranscript::new(¶ms); - let proof = TestudoSnark::prove( - &inst, - &comm, - &decomm, - assignment_vars.clone(), - &assignment_inputs, - &gens, - &mut prover_transcript, - poseidon_params(), - ) - .unwrap(); - - // verify the TestudoSnark - let mut verifier_transcript = PoseidonTranscript::new(¶ms); - assert!(proof - .verify( - &gens, - &comm, - &assignment_inputs, - &mut verifier_transcript, - poseidon_params() - ) - .is_ok()); - } -} +// use std::cmp::max; + +// use crate::errors::ProofVerifyError; +// use crate::r1csinstance::{R1CSCommitmentGens, R1CSEvalProof}; +// use crate::r1csproof::R1CSVerifierProof; + +// use crate::timer::Timer; +// use crate::transcript::TranscriptWriter; +// use crate::{ +// poseidon_transcript::PoseidonTranscript, +// r1csproof::{R1CSGens, R1CSProof}, +// transcript::Transcript, +// InputsAssignment, Instance, VarsAssignment, +// }; +// use crate::{ComputationCommitment, ComputationDecommitment}; +// use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; +// use ark_crypto_primitives::sponge::Absorb; +// use ark_ec::pairing::Pairing; + +// use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; + +// #[derive(Debug, CanonicalSerialize, CanonicalDeserialize)] + +// pub struct TestudoSnark { +// pub r1cs_verifier_proof: R1CSVerifierProof, +// pub r1cs_eval_proof: R1CSEvalProof, +// pub inst_evals: (E::ScalarField, E::ScalarField, E::ScalarField), +// pub r: (Vec, Vec), +// } + +// pub struct TestudoSnarkGens { +// gens_r1cs_sat: R1CSGens, +// gens_r1cs_eval: R1CSCommitmentGens, +// } + +// impl TestudoSnarkGens { +// /// Performs the setups required by the polynomial commitment PST, Groth16 +// /// and the computational commitment given the size of the R1CS statement, +// /// `num_nz_entries` specifies the maximum number of non-zero entries in +// /// any of the three R1CS matrices. +// pub fn setup( +// num_cons: usize, +// num_vars: usize, +// num_inputs: usize, +// num_nz_entries: usize, +// poseidon: PoseidonConfig, +// ) -> Self { +// // ensure num_vars is a power of 2 +// let num_vars_padded = { +// let mut num_vars_padded = max(num_vars, num_inputs + 1); +// if num_vars_padded != num_vars_padded.next_power_of_two() { +// num_vars_padded = num_vars_padded.next_power_of_two(); +// } +// num_vars_padded +// }; + +// let num_cons_padded = { +// let mut num_cons_padded = num_cons; + +// // ensure that num_cons_padded is at least 2 +// if num_cons_padded == 0 || num_cons_padded == 1 { +// num_cons_padded = 2; +// } + +// // ensure that num_cons_padded is a power of 2 +// if num_cons.next_power_of_two() != num_cons { +// num_cons_padded = num_cons.next_power_of_two(); +// } +// num_cons_padded +// }; + +// let gens_r1cs_sat = R1CSGens::setup( +// b"gens_r1cs_sat", +// num_cons_padded, +// num_vars_padded, +// num_inputs, +// poseidon, +// ); +// let gens_r1cs_eval = R1CSCommitmentGens::setup( +// b"gens_r1cs_eval", +// num_cons_padded, +// num_vars_padded, +// num_inputs, +// num_nz_entries, +// ); +// TestudoSnarkGens { +// gens_r1cs_sat, +// gens_r1cs_eval, +// } +// } +// } + +// impl TestudoSnark +// where +// E::ScalarField: Absorb, +// { +// // Constructs the computational commitment, used to prove that the +// // evaluations of matrices A, B and C sent by the prover to the verifier +// // are correct. +// pub fn encode( +// inst: &Instance, +// gens: &TestudoSnarkGens, +// ) -> ( +// ComputationCommitment, +// ComputationDecommitment, +// ) { +// let timer_encode = Timer::new("SNARK::encode"); +// let (comm, decomm) = inst.inst.commit(&gens.gens_r1cs_eval); +// timer_encode.stop(); +// ( +// ComputationCommitment { comm }, +// ComputationDecommitment { decomm }, +// ) +// } + +// // Returns the Testudo SNARK proof which has two components: +// // * proof that the R1CS instance is satisfiable +// // * proof that the evlauation of matrices A, B and C on point (x,y) +// // resulted from the two rounda of sumcheck are correct +// pub fn prove( +// inst: &Instance, +// comm: &ComputationCommitment, +// decomm: &ComputationDecommitment, +// vars: VarsAssignment, +// inputs: &InputsAssignment, +// gens: &TestudoSnarkGens, +// transcript: &mut PoseidonTranscript, +// poseidon: PoseidonConfig, +// ) -> Result, ProofVerifyError> { +// comm.comm.write_to_transcript(transcript); +// let c: E::ScalarField = transcript.challenge_scalar(b""); +// transcript.new_from_state(&c); + +// // we might need to pad variables +// let padded_vars = { +// let num_padded_vars = inst.inst.get_num_vars(); +// let num_vars = vars.assignment.len(); +// if num_padded_vars > num_vars { +// vars.pad(num_padded_vars) +// } else { +// vars +// } +// }; + +// let (r1cs_sat_proof, rx, ry) = R1CSProof::prove( +// &inst.inst, +// padded_vars.assignment, +// &inputs.assignment, +// &gens.gens_r1cs_sat, +// transcript, +// ); + +// // We send evaluations of A, B, C at r = (rx, ry) as claims +// // to enable the verifier complete the first sum-check +// let timer_eval = Timer::new("eval_sparse_polys"); +// let inst_evals = { +// let (Ar, Br, Cr) = inst.inst.evaluate(&rx, &ry); +// transcript.append_scalar(b"", &Ar); +// transcript.append_scalar(b"", &Br); +// transcript.append_scalar(b"", &Cr); +// (Ar, Br, Cr) +// }; +// timer_eval.stop(); + +// let timer_eval_proof = Timer::new("r1cs_eval_proof"); +// let r1cs_eval_proof = R1CSEvalProof::prove( +// &decomm.decomm, +// &rx, +// &ry, +// &inst_evals, +// &gens.gens_r1cs_eval, +// transcript, +// ); +// timer_eval_proof.stop(); + +// transcript.new_from_state(&c); +// let timer_sat_circuit_verification = Timer::new("r1cs_sat_circuit_verification"); +// let r1cs_verifier_proof = r1cs_sat_proof +// .prove_verifier( +// inst.inst.get_num_vars(), +// inst.inst.get_num_cons(), +// &inputs.assignment, +// &inst_evals, +// transcript, +// &gens.gens_r1cs_sat, +// poseidon, +// ) +// .unwrap(); +// timer_sat_circuit_verification.stop(); +// Ok(TestudoSnark { +// r1cs_verifier_proof, +// r1cs_eval_proof, +// inst_evals, +// r: (rx, ry), +// }) +// } + +// pub fn verify( +// &self, +// gens: &TestudoSnarkGens, +// comm: &ComputationCommitment, +// input: &InputsAssignment, +// transcript: &mut PoseidonTranscript, +// _poseidon: PoseidonConfig, +// ) -> Result { +// let (rx, ry) = &self.r; + +// let timer_sat_verification = Timer::new("r1cs_sat_verification"); +// let sat_verified = self.r1cs_verifier_proof.verify( +// (rx.clone(), ry.clone()), +// &input.assignment, +// &self.inst_evals, +// transcript, +// &gens.gens_r1cs_sat, +// )?; +// timer_sat_verification.stop(); +// assert!(sat_verified == true); + +// let (Ar, Br, Cr) = &self.inst_evals; +// transcript.append_scalar(b"", Ar); +// transcript.append_scalar(b"", Br); +// transcript.append_scalar(b"", Cr); + +// let timer_eval_verification = Timer::new("r1cs_eval_verification"); +// let eval_verified = self.r1cs_eval_proof.verify( +// &comm.comm, +// rx, +// ry, +// &self.inst_evals, +// &gens.gens_r1cs_eval, +// transcript, +// ); +// timer_eval_verification.stop(); +// Ok(sat_verified && eval_verified.is_ok()) +// } +// } + +// #[cfg(test)] +// mod tests { + +// use crate::ark_std::Zero; +// use crate::{ +// parameters::poseidon_params, +// poseidon_transcript::PoseidonTranscript, +// testudo_snark::{TestudoSnark, TestudoSnarkGens}, +// InputsAssignment, Instance, VarsAssignment, +// }; +// use ark_ff::{BigInteger, One, PrimeField}; + +// #[test] +// pub fn check_testudo_snark() { +// let num_vars = 256; +// let num_cons = num_vars; +// let num_inputs = 10; + +// type E = ark_bls12_377::Bls12_377; + +// // produce public generators +// let gens = +// TestudoSnarkGens::::setup(num_cons, num_vars, num_inputs, num_cons, poseidon_params()); + +// // produce a synthetic R1CSInstance +// let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs); + +// // create a commitment to R1CSInstance +// let (comm, decomm) = TestudoSnark::encode(&inst, &gens); + +// let params = poseidon_params(); + +// // produce a proof +// let mut prover_transcript = PoseidonTranscript::new(¶ms); +// let proof = TestudoSnark::prove( +// &inst, +// &comm, +// &decomm, +// vars, +// &inputs, +// &gens, +// &mut prover_transcript, +// params, +// ) +// .unwrap(); + +// // verify the proof +// let mut verifier_transcript = PoseidonTranscript::new(&poseidon_params()); +// assert!(proof +// .verify( +// &gens, +// &comm, +// &inputs, +// &mut verifier_transcript, +// poseidon_params() +// ) +// .is_ok()); +// } + +// #[test] +// fn test_padded_constraints() { +// type F = ark_bls12_377::Fr; +// type E = ark_bls12_377::Bls12_377; +// // parameters of the R1CS instance +// let num_cons = 1; +// let num_vars = 0; +// let num_inputs = 3; +// let num_non_zero_entries = 3; + +// // We will encode the above constraints into three matrices, where +// // the coefficients in the matrix are in the little-endian byte order +// let mut A: Vec<(usize, usize, Vec)> = Vec::new(); +// let mut B: Vec<(usize, usize, Vec)> = Vec::new(); +// let mut C: Vec<(usize, usize, Vec)> = Vec::new(); + +// // Create a^2 + b + 13 +// A.push((0, num_vars + 2, (F::one().into_bigint().to_bytes_le()))); // 1*a +// B.push((0, num_vars + 2, F::one().into_bigint().to_bytes_le())); // 1*a +// C.push((0, num_vars + 1, F::one().into_bigint().to_bytes_le())); // 1*z +// C.push((0, num_vars, (-F::from(13u64)).into_bigint().to_bytes_le())); // -13*1 +// C.push((0, num_vars + 3, (-F::one()).into_bigint().to_bytes_le())); // -1*b + +// // Var Assignments (Z_0 = 16 is the only output) +// let vars = vec![F::zero().into_bigint().to_bytes_le(); num_vars]; + +// // create an InputsAssignment (a = 1, b = 2) +// let mut inputs = vec![F::zero().into_bigint().to_bytes_le(); num_inputs]; +// inputs[0] = F::from(16u64).into_bigint().to_bytes_le(); +// inputs[1] = F::from(1u64).into_bigint().to_bytes_le(); +// inputs[2] = F::from(2u64).into_bigint().to_bytes_le(); + +// let assignment_inputs = InputsAssignment::::new(&inputs).unwrap(); +// let assignment_vars = VarsAssignment::new(&vars).unwrap(); + +// // Check if instance is satisfiable +// let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap(); +// let res = inst.is_sat(&assignment_vars, &assignment_inputs); +// assert!(res.unwrap(), "should be satisfied"); + +// // Testudo public params +// let gens = TestudoSnarkGens::::setup( +// num_cons, +// num_vars, +// num_inputs, +// num_non_zero_entries, +// poseidon_params(), +// ); + +// // create a commitment to the R1CS instance +// let (comm, decomm) = TestudoSnark::encode(&inst, &gens); + +// let params = poseidon_params(); + +// // produce a TestudoSnark +// let mut prover_transcript = PoseidonTranscript::new(¶ms); +// let proof = TestudoSnark::prove( +// &inst, +// &comm, +// &decomm, +// assignment_vars.clone(), +// &assignment_inputs, +// &gens, +// &mut prover_transcript, +// poseidon_params(), +// ) +// .unwrap(); + +// // verify the TestudoSnark +// let mut verifier_transcript = PoseidonTranscript::new(¶ms); +// assert!(proof +// .verify( +// &gens, +// &comm, +// &assignment_inputs, +// &mut verifier_transcript, +// poseidon_params() +// ) +// .is_ok()); +// } +// } diff --git a/src/verifier_circuit.rs b/src/verifier_circuit.rs new file mode 100644 index 00000000..614236e6 --- /dev/null +++ b/src/verifier_circuit.rs @@ -0,0 +1,574 @@ +// use crate::ark_std::One; +// use crate::constraints::R1CSVerificationCircuit; +// use crate::mipp::MippProof; +// use crate::parameters::get_bls12377_fq_params; +// use crate::parameters::params_to_base_field; +// use crate::r1csproof::R1CSGens; +// use crate::r1csproof::R1CSVerifierProof; +// use crate::constraints::VerifierConfig; +// use ark_serialize::CanonicalSerialize; +// use crate::{ +// math::Math, +// poseidon_transcript::PoseidonTranscript, +// sparse_mlpoly::{SparsePolyEntry, SparsePolynomial}, +// unipoly::UniPoly, +// }; +// use ark_ec::Group; +// use ark_crypto_primitives::snark::SNARKGadget; +// use ark_ec::CurveGroup; +// use ark_ff::Field; +// use ark_groth16::constraints::Groth16VerifierGadget; +// use ark_crypto_primitives::sponge::constraints::AbsorbGadget; +// use ark_crypto_primitives::sponge::{ +// constraints::CryptographicSpongeVar, +// poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig}, +// }; +// use ark_crypto_primitives::Error; +// use ark_ec::pairing::Pairing; +// use ark_ff::BigInteger; +// use ark_ff::PrimeField; +// use ark_groth16::Groth16; +// use ark_groth16::PreparedVerifyingKey; +// use ark_groth16::constraints::PreparedVerifyingKeyVar; +// use ark_poly_commit::multilinear_pc::data_structures::CommitmentG2; +// use ark_poly_commit::multilinear_pc::data_structures::ProofG1; +// use ark_poly_commit::multilinear_pc::{ +// data_structures::{Commitment, CommitterKey, Proof, VerifierKey}, +// MultilinearPC, +// }; +// use ark_r1cs_std::groups::bls12::G1Var; +// use ark_r1cs_std::prelude::*; +// use ark_r1cs_std::{ +// alloc::{AllocVar, AllocationMode}, +// fields::fp::FpVar, +// prelude::{EqGadget, FieldVar}, +// }; +// use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError}; +// use ark_serialize::Compress; +// use ark_snark::CircuitSpecificSetupSNARK; +// use ark_snark::SNARK; +// use digest::generic_array::typenum::True; +// use rand::CryptoRng; +// use rand::Rng; +// use std::ops::AddAssign; +// use std::ops::Mul; +// use std::ops::MulAssign; +// use std::{borrow::Borrow, marker::PhantomData}; +// use ark_groth16; +// type BasePrimeField = <<::G1 as CurveGroup>::BaseField as Field>::BasePrimeField; + +// pub struct VerifierCircuit +// where +// E: Pairing, +// IV: PairingVar>, +// { +// // pub inner_circuit: R1CSVerificationCircuit, // circuito Mara + +// // pub inner_proof: ark_groth16::Proof, // PROOF DA VERIFICARE +// // pub inner_vk: PreparedVerifyingKey, // GENS.GC.VK + +// pub r: (Vec, Vec), +// pub input: Vec, +// pub evals: (E::ScalarField,E::ScalarField,E::ScalarField), + +// pub transcript: PoseidonTranscript, +// pub gens: R1CSGens, +// pub r1cs_proof: R1CSVerifierProof, // SELF +// pub _iv: PhantomData, +// } + +// impl VerifierCircuit +// where +// E: Pairing, +// IV: PairingVar>, +// { +// pub fn new( +// //config: &VerifierConfig, +// //mut rng: &mut R, +// r: (Vec, Vec), +// input: Vec, +// evals: (E::ScalarField, E::ScalarField, E::ScalarField), +// transcript: PoseidonTranscript, +// gens: R1CSGens, +// r1cs_proof: R1CSVerifierProof, +// ) -> Result { +// // let inner_circuit = crate::constraints::R1CSVerificationCircuit::new(config); +// // let (pk, vk) = Groth16::::setup(inner_circuit.clone(), &mut rng).unwrap(); +// // let proof = Groth16::::prove(&pk, inner_circuit.clone(), &mut rng)?; +// // let pvk = Groth16::::process_vk(&vk).unwrap(); +// Ok(Self { +// // inner_circuit, +// // inner_proof: proof, +// // inner_vk: pvk, +// r: r, +// input: input.to_vec(), +// evals: evals, +// transcript: transcript, +// gens: gens, +// r1cs_proof, +// _iv: PhantomData, +// }) +// } +// } +// impl ConstraintSynthesizer> for VerifierCircuit +// where +// E: Pairing, +// IV: PairingVar>, +// IV::G1Var: CurveVar>, +// // IV::G2Var: CurveVar, +// // IV::GTVar: FieldVar, +// { +// fn generate_constraints(self, cs: ConstraintSystemRef>) -> ark_relations::r1cs::Result<()> { + +// // //STEP 1) ALLOCATE INNER_PROOF AS CIRCUIT VARIABLE + +// let (rx, ry) = self.r; +// let (Ar, Br, Cr) = self.evals; +// let mut pubs = vec![self.r1cs_proof.initial_state]; +// pubs.extend(self.input.clone()); +// pubs.extend(rx.clone()); +// pubs.extend(ry.clone()); +// pubs.extend(vec![ +// self.r1cs_proof.eval_vars_at_ry, +// Ar, +// Br, +// Cr, +// self.r1cs_proof.transcript_sat_state, +// ]); +// // self.transcript.new_from_state(self.r1cs_proof.transcript_sat_state); + +// let proof_gadget = as SNARKGadget,Groth16>>::ProofVar::new_witness(cs.clone(), || Ok(self.r1cs_proof.circuit_proof)).unwrap(); +// let vk_gadget = as SNARKGadget,Groth16>>::VerifyingKeyVar::new_witness(cs.clone(), || Ok(self.gens.gens_gc.vk.clone())).unwrap(); + +// let input_gadget= as SNARKGadget,Groth16>>::InputVar::new_input(cs.clone(), || Ok(pubs)).unwrap(); +// let ver = as SNARKGadget,Groth16>>::verify(&vk_gadget, &input_gadget, &proof_gadget).unwrap(); +// println!("Verifier groth circuit"); +// ver.enforce_equal(&Boolean::constant(true)).unwrap(); + +// // MAPPA DEI PARAMETRI PER CHIAMARE VERIFY +// //gens.gens_pc.vk = vk +// // self.comm = r1cs_proof.comm +// //ry[1..] = point +// // self.eval_vars_at_ry = v +// // self.proof_evals_vars_at_ry = pst_proof +// // self.mipp_proof =mipp_proof +// // selft.t = T +// ver_mipp_pst::(cs, self.gens.gens_pc.vk, self.r1cs_proof.comm, ry[1..].to_vec(), self.r1cs_proof.eval_vars_at_ry, self.r1cs_proof.proof_eval_vars_at_ry , self.r1cs_proof.mipp_proof, self.r1cs_proof.t); +// Ok(()) +// } +// } + +// fn ver_mipp_pst>>( +// cs: ConstraintSystemRef>, +// vk: VerifierKey, +// U: Commitment, +// point: Vec, +// v: E::ScalarField, +// pst_proof: Proof, +// mipp_proof: MippProof, +// T: E::TargetField, +// ) -> Result { + +// // allocate point +// let mut point_var = Vec::new(); +// for p in point.clone().into_iter() { +// let scalar_in_fq = &BasePrimeField::::from_bigint( +// as PrimeField>::BigInt::from_bits_le(p.into_bigint().to_bits_le().as_slice()), +// ) +// .unwrap(); +// let p_var = FpVar::new_input(cs.clone(), || Ok(scalar_in_fq))?; +// point_var.push(p_var); +// } +// let len = point_var.len(); +// let odd = if len % 2 == 1 { 1 } else { 0 }; +// let a_var = &point_var[0..len / 2 + odd]; +// let b_var = &point_var[len / 2 + odd..len]; + +// let res_mipp = mipp_verify_gadget_final::( +// cs.clone(), +// vk.clone(), +// &mipp_proof, +// b_var.to_vec(), +// U.g_product, +// &T, +// ); + +// assert!(res_mipp.unwrap() == true); +// let mut a_rev_var = a_var.to_vec().clone(); +// a_rev_var.reverse(); + +// let res_var = check_gadget_final::( +// cs.clone(), +// vk, +// U, +// &a_rev_var, +// v, +// pst_proof, +// ); +// assert!(res_var.unwrap() == true); + +// Ok(true) +// } + +// fn check_gadget_final>>( +// cs: ConstraintSystemRef>, +// vk: VerifierKey, +// commitment: Commitment, +// point_var: &Vec>>, +// value: E::ScalarField, +// proof: Proof, +// ) -> Result +// where +// IV::G1Var: CurveVar>, +// IV::G2Var: CurveVar>, +// IV::GTVar: FieldVar>, +// { +// let vk_g_var = IV::G1Var::new_input(cs.clone(), || Ok(vk.g))?; +// let vk_h_var = IV::G2Var::new_input(cs.clone(), || Ok(vk.h))?; +// let mut vk_gmask_var = Vec::new(); +// for g_mask in vk.g_mask_random.clone().into_iter() { +// let g_mask_var = IV::G1Var::new_input(cs.clone(), || Ok(g_mask))?; +// vk_gmask_var.push(g_mask_var); +// } +// // allocate commitment +// let com_g1_prod_var = IV::G1Var::new_input(cs.clone(), || Ok(commitment.g_product))?; +// // allocate value +// let scalar_in_fq = &BasePrimeField::::from_bigint( +// as PrimeField>::BigInt::from_bits_le(value.into_bigint().to_bits_le().as_slice()), +// ) +// .unwrap(); +// let value_var = FpVar::new_input(cs.clone(), || Ok(scalar_in_fq))?; +// // allocate proof +// let mut proofs_var = Vec::new(); +// for proof in proof.proofs.clone().into_iter() { +// let proof_var = IV::G2Var::new_witness(cs.clone(), || Ok(proof))?; +// proofs_var.push(proof_var); +// } +// // start operation on circuit +// let pair_left_op = com_g1_prod_var - (vk_g_var.scalar_mul_le(value_var.to_bits_le()?.iter())?); +// let left_prepared = IV::prepare_g1(&pair_left_op)?; +// let right_prepared = IV::prepare_g2(&vk_h_var)?; +// let left = IV::pairing(left_prepared, right_prepared)?; + +// let mut res_var = Vec::new(); + +// for p in point_var.into_iter() { +// let x = vk_g_var.scalar_mul_le(p.to_bits_le()?.iter())?; +// res_var.push(x); +// } + +// //computing other part of the circuit +// let pairing_lefts_var: Vec<_> = (0..vk.nv) +// .map(|i| vk_gmask_var[i].clone() - res_var[i].clone()) //.map(|i| vk_gmask_var[i].clone() - g_mul_var[i].clone()) +// .collect(); + +// let mut pairing_lefts_prep = Vec::new(); +// for var in pairing_lefts_var.clone().into_iter() { +// pairing_lefts_prep.push(IV::prepare_g1(&var).unwrap()); +// } + +// let mut pairing_right_prep = Vec::new(); +// for var in proofs_var.clone().into_iter() { +// pairing_right_prep.push(IV::prepare_g2(&var).unwrap()); +// } + +// let right_ml = IV::miller_loop(&pairing_lefts_prep, &pairing_right_prep)?; +// let right = IV::final_exponentiation(&right_ml).unwrap(); +// left.enforce_equal(&right); // OK +// Ok(true) +// } + +// fn check_2_gadget_final>>( +// cs: ConstraintSystemRef>, +// vk: VerifierKey, +// commitment: &CommitmentG2, +// point_var: &Vec>>, +// value_var: FpVar>, +// proof: &ProofG1, +// ) -> Result +// where +// IV::G1Var: CurveVar>, +// IV::G2Var: CurveVar>, +// IV::GTVar: FieldVar>, +// { +// let vk_g_var = IV::G1Var::new_input(cs.clone(), || Ok(vk.g))?; +// let vk_h_var = IV::G2Var::new_input(cs.clone(), || Ok(vk.h))?; +// let mut vk_gmask_var = Vec::new(); +// for g_mask in vk.g_mask_random.clone().into_iter() { +// let g_mask_var = IV::G1Var::new_input(cs.clone(), || Ok(g_mask))?; +// vk_gmask_var.push(g_mask_var); +// } +// // allocate commitment +// let com_h_prod_var = IV::G2Var::new_input(cs.clone(), || Ok(commitment.h_product))?; + +// let pair_right_op = com_h_prod_var +// - (vk_h_var +// .scalar_mul_le(value_var.to_bits_le().unwrap().iter()) +// .unwrap()); +// let right_prepared = IV::prepare_g2(&pair_right_op)?; +// let left_prepared = IV::prepare_g1(&vk_g_var)?; +// let left = IV::pairing(left_prepared, right_prepared)?; + +// let mut h_mul_var = Vec::new(); + +// for p in point_var.into_iter() { +// let x = vk_h_var +// .scalar_mul_le(p.to_bits_le().unwrap().iter()) +// .unwrap(); +// h_mul_var.push(x); +// } +// let h_mask_random = vk.h_mask_random[vk.nv - point_var.len()..].to_vec(); +// let mut h_mask_random_var = Vec::new(); +// for h_mask in h_mask_random.clone().into_iter() { +// let h_mask_var = IV::G2Var::new_input(cs.clone(), || Ok(h_mask))?; +// h_mask_random_var.push(h_mask_var); +// } +// let pairing_rights_var: Vec<_> = (0..point_var.len()) +// .into_iter() +// .map(|i| h_mask_random_var[i].clone() - h_mul_var[i].clone()) //.map(|i| vk_gmask_var[i].clone() - g_mul_var[i].clone()) +// .collect(); +// let pairing_rights_var: Vec = pairing_rights_var +// .into_iter() +// .map(|p| IV::prepare_g2(&p).unwrap()) +// .collect(); +// let mut proofs_var = Vec::new(); +// for p in proof.proofs.clone().into_iter() { +// let proof_var = IV::G1Var::new_input(cs.clone(), || Ok(p))?; +// proofs_var.push(proof_var); +// } +// let pairing_lefts_var: Vec = proofs_var +// .into_iter() +// .map(|p| IV::prepare_g1(&p).unwrap()) +// .collect(); + +// let right_ml = IV::miller_loop(&pairing_lefts_var, &pairing_rights_var)?; +// let right = IV::final_exponentiation(&right_ml)?; + +// left.enforce_equal(&right).unwrap(); +// Ok(true) +// } + +// fn mipp_verify_gadget_final>>( +// cs: ConstraintSystemRef>, +// vk: VerifierKey, +// proof: &MippProof, +// point_var: Vec>>, +// U: E::G1Affine, +// T: &::TargetField, +// ) -> Result +// where +// IV::G1Var: CurveVar>, +// IV::G2Var: CurveVar>, +// IV::GTVar: FieldVar>, +// { +// let mut comms_u_var = Vec::new(); +// for (first, second) in proof.comms_u.clone().into_iter() { +// let first_var = IV::G1Var::new_input(cs.clone(), || Ok(first))?; +// let second_var = IV::G1Var::new_input(cs.clone(), || Ok(second))?; +// comms_u_var.push((first_var, second_var)); +// } +// // allocate comms_t +// let mut comms_t_var = Vec::new(); +// for (first, second) in proof.comms_t.clone().into_iter() { +// let first_var = IV::GTVar::new_input(cs.clone(), || Ok(first))?; +// let second_var = IV::GTVar::new_input(cs.clone(), || Ok(second))?; +// comms_t_var.push((first_var, second_var)); +// } + +// let mut xs = Vec::new(); +// let mut xs_inv = Vec::new(); +// let final_y = BasePrimeField::::one(); +// let mut final_y_var = FpVar::new_input(cs.clone(), || Ok(final_y))?; + +// // start allocate T +// let T_var = IV::GTVar::new_input(cs.clone(), || Ok(T))?; +// // start allocate U.g_product +// let U_g_product_var = IV::G1Var::new_input(cs.clone(), || Ok(U))?; + +// let mut final_res_var: MippTUVar = MippTUVar { +// tc: T_var.clone(), +// uc: U_g_product_var.clone(), // Siamo sicuri che possiamo togliere senza problemi il 'into_group'? da testare +// }; + +// // create new transcript inside the circuit instead of taking it from parameters +// let params: PoseidonConfig = params_to_base_field::(); +// let mut transcript_var = PoseidonSpongeVar::new(cs.clone(), ¶ms); + +// // PRIMA ABSORB +// let mut U_g_product_buf = Vec::new(); +// U_g_product_var +// .value() +// .unwrap() +// .serialize_with_mode(&mut U_g_product_buf, Compress::No) +// .expect("serialization failed"); + +// let mut U_g_product_var_bytes = Vec::new(); + +// for b in U_g_product_buf { +// U_g_product_var_bytes.push(UInt8::new_input(cs.clone(), || Ok(b))?); +// } + +// transcript_var.absorb(&U_g_product_var_bytes)?; + +// let one_var = FpVar::new_input(cs.clone(), || Ok(BasePrimeField::::one()))?; +// for (i, (comm_u, comm_t)) in comms_u_var.iter().zip(comms_t_var.iter()).enumerate() { +// let (comm_u_l, comm_u_r) = comm_u; +// let (comm_t_l, comm_t_r) = comm_t; +// // Fiat-Shamir challenge +// // ABSORB COMM_U_R +// let mut comm_u_l_buf = Vec::new(); +// comm_u_l +// .value() +// .unwrap() +// .serialize_with_mode(&mut comm_u_l_buf, Compress::No) +// .expect("serialization failed"); + +// let mut comm_u_l_var_bytes = Vec::new(); + +// for b in comm_u_l_buf { +// comm_u_l_var_bytes.push(UInt8::new_input(cs.clone(), || Ok(b))?); +// } +// transcript_var.absorb(&comm_u_l_var_bytes)?; +// // ABSORB COMM_U_R +// let mut comm_u_r_buf = Vec::new(); +// comm_u_r +// .value() +// .unwrap() +// .serialize_with_mode(&mut comm_u_r_buf, Compress::No) +// .expect("serialization failed"); + +// let mut comm_u_r_var_bytes = Vec::new(); + +// for b in comm_u_r_buf { +// comm_u_r_var_bytes.push(UInt8::new_input(cs.clone(), || Ok(b))?); +// } +// transcript_var.absorb(&comm_u_r_var_bytes)?; +// // ABSORB COMM_T_L +// let mut comm_t_l_buf = Vec::new(); +// comm_t_l +// .value() +// .unwrap() +// .serialize_with_mode(&mut comm_t_l_buf, Compress::No) +// .expect("serialization failed"); + +// let mut comm_t_l_var_bytes = Vec::new(); + +// for b in comm_t_l_buf { +// comm_t_l_var_bytes.push(UInt8::new_input(cs.clone(), || Ok(b))?); +// } +// transcript_var.absorb(&comm_t_l_var_bytes)?; +// // ABSORB COMM_T_R +// let mut comm_t_r_buf = Vec::new(); +// comm_t_r +// .value() +// .unwrap() +// .serialize_with_mode(&mut comm_t_r_buf, Compress::No) +// .expect("serialization failed"); + +// let mut comm_t_r_var_bytes = Vec::new(); + +// for b in comm_t_r_buf { +// comm_t_r_var_bytes.push(UInt8::new_input(cs.clone(), || Ok(b))?); +// } +// transcript_var.absorb(&comm_t_r_var_bytes)?; + +// let c_inv_var = transcript_var.squeeze_field_elements(1).unwrap().remove(0); +// let c_var = c_inv_var.inverse().unwrap(); + +// xs.push(c_var.clone()); +// xs_inv.push(c_inv_var.clone()); + +// final_y_var *= &one_var + c_inv_var.mul(&point_var[i]) - &point_var[i]; +// } + +// enum Op<'a, E: Pairing, IV: PairingVar> { +// TC(&'a IV::GTVar, FpVar<::BaseField>), // BigInt == FpVar +// UC(&'a IV::G1Var, &'a FpVar<::BaseField>), +// } + +// let res_var = comms_t_var +// .iter() +// .zip(comms_u_var.iter()) +// .zip(xs.iter().zip(xs_inv.iter())) +// .flat_map(|((comm_t, comm_u), (c, c_inv))| { +// let (comm_t_l, comm_t_r) = comm_t; +// let (comm_u_l, comm_u_r) = comm_u; + +// // we multiple left side by x^-1 and right side by x +// vec![ +// Op::TC(comm_t_l, c_inv.clone()), +// Op::TC(comm_t_r, c.clone()), +// Op::UC(comm_u_l, c_inv), +// Op::UC(comm_u_r, c), +// ] +// }) +// .fold(MippTUVar::::default(), |mut res, op: Op| { +// match op { +// Op::TC(tx, c) => { +// // let bits_c = c_var.to_bits_le()?; let exp = t_var.pow_le(&bits_c)?; +// let tx = tx.pow_le(&c.to_bits_le().unwrap()).unwrap(); +// res.tc.mul_assign(&tx); +// } +// Op::UC(zx, c) => { +// let uxp = zx.scalar_mul_le(c.to_bits_le().unwrap().iter()).unwrap(); +// res.uc.add_assign(&uxp); +// } +// } +// res +// }); + +// let ref_final_res_var = &mut final_res_var; +// ref_final_res_var.merge(&res_var); + +// let mut rs: FpVar> = Vec::new(); +// let m = xs_inv.len(); +// for _i in 0..m { +// let r = transcript_var.squeeze_field_elements(1).unwrap().remove(0); +// rs.push(r); +// } +// println!("SONO QUA"); +// println!("{}", rs[0].value().unwrap()); +// // let rs_var = rs.clone(); +// let v_var: FpVar> = (0..m) +// .into_iter() +// .map(|i| &one_var + (&rs[i]).mul(&xs_inv[m - i - 1]) - &rs[i]) +// .fold(one_var.clone(), |acc, x| acc * x); // .product() == fold + +// let comm_h = CommitmentG2:: { +// nv: m, +// h_product: proof.final_h, +// }; + +// let check_h_var = check_2_gadget_final::( +// cs.clone(), +// vk.clone(), +// &comm_h, +// &rs, +// v_var, +// &proof.pst_proof_h, +// ); +// let check_h = check_h_var.unwrap(); +// assert!(check_h.clone() == true); +// let final_a_var = IV::G1Var::new_input(cs.clone(), || Ok(proof.final_a))?; +// let final_u_var = final_a_var +// .scalar_mul_le(final_y_var.to_bits_le().unwrap().iter()) +// .unwrap(); + +// let final_h_var = IV::G2Var::new_input(cs.clone(), || Ok(proof.final_h))?; + +// let final_u_var_prep = IV::prepare_g1(&final_a_var)?; +// let final_h_var_prep = IV::prepare_g2(&final_h_var)?; + +// let final_t_var = IV::pairing(final_u_var_prep, final_h_var_prep)?; +// let check_t = true; + +// //ref_final_res_var.tc.enforce_equal(&final_t_var).unwrap(); + +// assert!(check_t == true); + +// let check_u = true; +// //ref_final_res_var.uc.enforce_equal(&final_u_var).unwrap() { + +// assert!(check_u == true); +// Ok(check_h & check_u) +// }