diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..e4de0f4 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,74 @@ +name: Rust + +on: + # Run CI on push only for 'main' branch + push: + branches: [main] + # Run CI on pull request for all branches + pull_request: + branches: ["**"] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + RUST_BACKTRACE: 1 + +jobs: + format: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + components: rustfmt + - name: Format + run: cargo fmt --all --check + + build: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + - name: Build + run: cargo build --verbose + + build-wasm32: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: wasm32-unknown-unknown + - name: Build + run: cargo build --verbose --no-default-features --target wasm32-unknown-unknown + + test: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + - name: Run tests + run: cargo test --release + diff --git a/benches/multiexps.rs b/benches/multiexps.rs index f3ecd0b..1d0d750 100644 --- a/benches/multiexps.rs +++ b/benches/multiexps.rs @@ -2,7 +2,7 @@ use ark_ec::pairing::Pairing; use ark_ec::VariableBaseMSM; use ark_ff::{PrimeField, UniformRand}; use ark_std::test_rng; -use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use fflonk::utils::ec; @@ -11,8 +11,12 @@ fn small_multiexp_affine(c: &mut Criterion) { let n = 10; let bases = (0..n).map(|_| E::G1Affine::rand(rng)).collect::>(); - let exps_full = (0..n).map(|_| E::ScalarField::rand(rng)).collect::>(); - let exps_128 = (0..n).map(|_| E::ScalarField::from(u128::rand(rng))).collect::>(); + let exps_full = (0..n) + .map(|_| E::ScalarField::rand(rng)) + .collect::>(); + let exps_128 = (0..n) + .map(|_| E::ScalarField::from(u128::rand(rng))) + .collect::>(); let mut group = c.benchmark_group("small-multiexp-affine"); group.bench_with_input(BenchmarkId::new("small-multiexp-full", n), &n, |b, _n| { @@ -35,7 +39,9 @@ fn small_multiexp_proj(c: &mut Criterion) { let n = 10; let bases = (0..n).map(|_| E::G1::rand(rng)).collect::>(); - let exps_128 = (0..n).map(|_| E::ScalarField::from(u128::rand(rng))).collect::>(); + let exps_128 = (0..n) + .map(|_| E::ScalarField::from(u128::rand(rng))) + .collect::>(); let mut group = c.benchmark_group("small-multiexp-proj"); group.bench_with_input(BenchmarkId::new("in_affine", n), &n, |b, _n| { @@ -54,12 +60,21 @@ fn small_multiexp_vs_msm(c: &mut Criterion) { for n in [10, 20] { let bases = (0..n).map(|_| E::G1Affine::rand(rng)).collect::>(); - let exps_full = (0..n).map(|_| E::ScalarField::rand(rng)).collect::>(); - let exps_128 = (0..n).map(|_| E::ScalarField::from(u128::rand(rng))).collect::>(); - - let exps_full_repr = exps_full.iter().map(|exp| exp.into_bigint()).collect::>(); - let exps_128_repr = exps_128.iter().map(|exp| exp.into_bigint()).collect::>(); - + let exps_full = (0..n) + .map(|_| E::ScalarField::rand(rng)) + .collect::>(); + let exps_128 = (0..n) + .map(|_| E::ScalarField::from(u128::rand(rng))) + .collect::>(); + + let exps_full_repr = exps_full + .iter() + .map(|exp| exp.into_bigint()) + .collect::>(); + let exps_128_repr = exps_128 + .iter() + .map(|exp| exp.into_bigint()) + .collect::>(); group.bench_with_input(BenchmarkId::new("small-multiexp-full", n), &n, |b, _n| { b.iter(|| ec::small_multiexp_affine(&exps_full, &bases)) @@ -78,10 +93,10 @@ fn small_multiexp_vs_msm(c: &mut Criterion) { group.finish(); } - -criterion_group!(benches, +criterion_group!( + benches, small_multiexp_affine::, small_multiexp_proj::, small_multiexp_vs_msm::, ); -criterion_main!(benches); \ No newline at end of file +criterion_main!(benches); diff --git a/benches/primitives.rs b/benches/primitives.rs index 2072be0..4d3e043 100644 --- a/benches/primitives.rs +++ b/benches/primitives.rs @@ -1,11 +1,11 @@ use std::ops::Mul; use ark_bw6_761::BW6_761; -use ark_ec::{AffineRepr, CurveGroup, Group}; use ark_ec::pairing::Pairing; +use ark_ec::{AffineRepr, CurveGroup, Group}; use ark_ff::UniformRand; use ark_std::test_rng; -use criterion::{Criterion, criterion_group, criterion_main}; +use criterion::{criterion_group, criterion_main, Criterion}; use fflonk::utils::curve_name; @@ -24,7 +24,7 @@ fn scalar_mul(c: &mut Criterion) { let _res: E::G1 = bases_affine[0].mul(exps[0]); // result of affine mul is projective let mut i = 0; - group.bench_function("proj", |b| + group.bench_function("proj", |b| { b.iter_with_setup( || { let pair = (bases_projective[i], exps[i]); @@ -32,10 +32,11 @@ fn scalar_mul(c: &mut Criterion) { pair }, |(base, exp)| base.mul(exp), - )); + ) + }); let mut i = 0; - group.bench_function("aff", |b| + group.bench_function("aff", |b| { b.iter_with_setup( || { let pair = (bases_affine[i], exps[i]); @@ -43,7 +44,8 @@ fn scalar_mul(c: &mut Criterion) { pair }, |(base, exp)| base.mul(exp), - )); + ) + }); group.finish(); } @@ -73,6 +75,10 @@ fn additions(c: &mut Criterion) { group.finish(); } - -criterion_group!(benches, scalar_mul::, coordinates_conversion::, additions::); -criterion_main!(benches); \ No newline at end of file +criterion_group!( + benches, + scalar_mul::, + coordinates_conversion::, + additions:: +); +criterion_main!(benches); diff --git a/src/aggregation/merlin.rs b/src/aggregation/merlin.rs index 6532a87..5dda6ae 100644 --- a/src/aggregation/merlin.rs +++ b/src/aggregation/merlin.rs @@ -23,4 +23,4 @@ impl> Transcript for merlin::Transcript { self.challenge_bytes(b"zeta", &mut buf); F::from_random_bytes(&buf).unwrap() } -} \ No newline at end of file +} diff --git a/src/aggregation/mod.rs b/src/aggregation/mod.rs index 340ffc6..0d932b9 100644 --- a/src/aggregation/mod.rs +++ b/src/aggregation/mod.rs @@ -1,3 +1,3 @@ -pub mod single; -pub mod multiple; pub mod merlin; +pub mod multiple; +pub mod single; diff --git a/src/aggregation/multiple.rs b/src/aggregation/multiple.rs index 748ab95..b98200d 100644 --- a/src/aggregation/multiple.rs +++ b/src/aggregation/multiple.rs @@ -22,14 +22,19 @@ pub trait Transcript> { fn get_zeta(&mut self) -> F; } - pub fn aggregate_polys, T: Transcript>( ck: &CS::CK, fs: &[Poly], xss: &[BTreeSet], transcript: &mut T, ) -> (Poly, F, CS::C) { - assert_eq!(xss.len(), fs.len(), "{} opening sets specified for {} polynomials", xss.len(), fs.len()); + assert_eq!( + xss.len(), + fs.len(), + "{} opening sets specified for {} polynomials", + xss.len(), + fs.len() + ); // Both Halo-inf and fflonk/shplonk use the notation "complement" in set-theoretical sense to that used in the code. // The papers consider vanishing polynomials of the complements of the opening sets, // while in the code vanishing polynomials of the opening sets are used directly. @@ -37,18 +42,17 @@ pub fn aggregate_polys, T: Transcript>( // using https://eprint.iacr.org/2021/1167.pdf, Lemma 4.2. as the authority. // zi - the vanishing polynomial of the set xsi ("Si" in the paper) of the opening points for fi, i = 0,...,k-1 - let zs: Vec<_> = xss.iter() - .map(|xsi| poly::z_of_set(xsi)) - .collect(); + let zs: Vec<_> = xss.iter().map(|xsi| poly::z_of_set(xsi)).collect(); // The paper defines "T" as the set of all the opening points, "Z_T", it's vanishing polynomial, // and "Z_{T\S_i}" as the vanishing polynomial of the complement of "Si" in "T". // Observe that for zi computed above, "Z_T" = zi * "Z_{T\S_i}" (*) - // (qi, ri) - the quotient and the remainder of division of fi by the corresponding vanishing polynomial zi // qi = (fi - ri) / zi (**) let t_divisions = start_timer!(|| "polynomial divisions"); - let (qs, rs): (Vec<_>, Vec<_>) = fs.iter().zip(zs.iter()) + let (qs, rs): (Vec<_>, Vec<_>) = fs + .iter() + .zip(zs.iter()) .map(|(fi, zi)| fi.divide_with_q_and_r(zi)) .unzip(); end_timer!(t_divisions); @@ -60,7 +64,8 @@ pub fn aggregate_polys, T: Transcript>( // By (*) "Z_T" = zi * "Z_{T\S_i}", hence q = f / (zi * "Z_{T\S_i})" = sum(gamma^i * (fi - ri) / zi) // By (**) qi = (fi - ri) / zi, thus q = sum(gamma^i * qi) let q = poly::sum_with_powers(gamma, &qs); - let t_commit = start_timer!(|| ark_std::format!("commitment to a degree-{} polynomial", q.degree())); + let t_commit = + start_timer!(|| ark_std::format!("commitment to a degree-{} polynomial", q.degree())); let qc = CS::commit(ck, &q); // "W" in the paper end_timer!(t_commit); @@ -72,7 +77,9 @@ pub fn aggregate_polys, T: Transcript>( let zs_at_zeta: Vec<_> = zs.iter().map(|zi| zi.evaluate(&zeta)).collect(); // Let pi(X) = fi(X) - ri(zeta) - let ps: Vec> = fs.iter().zip(rs_at_zeta) + let ps: Vec> = fs + .iter() + .zip(rs_at_zeta) .map(|(fi, ri)| fi - &poly::constant(ri)) .collect(); @@ -102,7 +109,9 @@ fn get_coeffs(zs_at_zeta: Vec, gamma: F) -> (Vec, F) { let mut zs_at_zeta_inv = zs_at_zeta; ark_ff::batch_inversion(&mut zs_at_zeta_inv); - let coeffs = zs_at_zeta_inv.iter().zip(utils::powers(gamma)) + let coeffs = zs_at_zeta_inv + .iter() + .zip(utils::powers(gamma)) .map(|(zi_inv, gamma_to_i)| gamma_to_i * zi_inv * normalizer) .collect(); @@ -114,7 +123,8 @@ pub fn group_by_commitment>( xss: &Vec>, yss: &Vec>, ) -> Vec> { - fcs.iter().cloned() + fcs.iter() + .cloned() .zip(xss.iter().cloned()) .zip(yss.iter().cloned()) .map(|((c, xs), ys)| MultipointClaim { c, xs, ys }) @@ -126,8 +136,7 @@ pub fn aggregate_claims, T: Transcript>( qc: &CS::C, onec: &CS::C, transcript: &mut T, -) -> MultipointClaim -{ +) -> MultipointClaim { let gamma = transcript.get_gamma(); transcript.commit_to_q(&qc); let zeta = transcript.get_zeta(); @@ -137,7 +146,8 @@ pub fn aggregate_claims, T: Transcript>( // and ri is the interpolation polynomial of the set {(xj, yj)}. // ri(zeta), zi(zeta) let t_eval = start_timer!(|| "barycentric evaluations"); - let (rs_at_zeta, zs_at_zeta): (Vec<_>, Vec<_>) = claims.iter() + let (rs_at_zeta, zs_at_zeta): (Vec<_>, Vec<_>) = claims + .iter() .map(|MultipointClaim { c: _, xs, ys }| interpolate_evaluate(xs, ys, &zeta)) .unzip(); end_timer!(t_eval); @@ -145,7 +155,9 @@ pub fn aggregate_claims, T: Transcript>( let (mut coeffs, normalizer) = get_coeffs(zs_at_zeta, gamma); assert!(coeffs[0].is_one()); - let agg_r_at_zeta: F = rs_at_zeta.into_iter().zip(coeffs.iter()) + let agg_r_at_zeta: F = rs_at_zeta + .into_iter() + .zip(coeffs.iter()) .map(|(ri_at_zeta, coeff)| ri_at_zeta * coeff) .sum(); @@ -158,10 +170,13 @@ pub fn aggregate_claims, T: Transcript>( let t_combine = start_timer!(|| "multiexp"); let lc = CS::C::combine(&coeffs, &commitments); end_timer!(t_combine); - MultipointClaim { c: lc, xs: vec![zeta], ys: vec![F::zero()] } + MultipointClaim { + c: lc, + xs: vec![zeta], + ys: vec![F::zero()], + } } - #[cfg(test)] mod tests { use ark_ff::{One, UniformRand}; @@ -193,7 +208,8 @@ mod tests { assert!(coeffs.iter().zip(zs).all(|(c, z)| z * c == normalizer)); } - fn _test_aggregation>(d: usize) { // degree of polynomials + fn _test_aggregation>(d: usize) { + // degree of polynomials let rng = &mut test_rng(); let t = 8; // number of polynomials @@ -205,14 +221,18 @@ mod tests { let xss = random_xss(rng, t, max_m); let opening = random_opening::<_, _, CS>(rng, &ck, d, t, xss); - let sets_of_xss: Vec> = opening.xss.iter() + let sets_of_xss: Vec> = opening + .xss + .iter() .map(|xs| BTreeSet::from_iter(xs.iter().cloned())) .collect(); let transcript = &mut (F::rand(rng), F::rand(rng)); - let t_aggregate_polys = start_timer!(|| format!("Aggregate {} degree-{} polynomials", t, d)); - let (agg_poly, zeta, agg_proof) = aggregate_polys::<_, CS, _>(&ck, &opening.fs, &sets_of_xss, transcript); + let t_aggregate_polys = + start_timer!(|| format!("Aggregate {} degree-{} polynomials", t, d)); + let (agg_poly, zeta, agg_proof) = + aggregate_polys::<_, CS, _>(&ck, &opening.fs, &sets_of_xss, transcript); end_timer!(t_aggregate_polys); let claims = group_by_commitment(&opening.fcs, &opening.xss, &opening.yss); @@ -239,4 +259,4 @@ mod tests { fn bench_aggregation() { _test_aggregation::((1 << BENCH_DEG_LOG1) - 1); } -} \ No newline at end of file +} diff --git a/src/aggregation/single.rs b/src/aggregation/single.rs index ce8b5fc..6ecf2cd 100644 --- a/src/aggregation/single.rs +++ b/src/aggregation/single.rs @@ -4,8 +4,8 @@ use ark_poly::Polynomial; use ark_std::vec::Vec; use crate::pcs::{Commitment, PCS}; -use crate::Poly; use crate::utils::ec::small_multiexp_affine; +use crate::Poly; /// A tuple (c, x, y) of the form (G, F, F). Represents a claim that {f(x) = y, for a polynomial f such that commit(f) = c}. /// In other words, it is am instance in some language of "correct polynomial evaluations". @@ -18,7 +18,10 @@ pub struct Claim> { } impl> Claim { - pub fn new(ck: &CS::CK, poly: &Poly, at: F) -> Claim where CS: PCS { + pub fn new(ck: &CS::CK, poly: &Poly, at: F) -> Claim + where + CS: PCS, + { Claim { c: CS::commit(ck, poly), x: at, @@ -27,7 +30,6 @@ impl> Claim { } } - /// Aggregates claims for different polynomials evaluated at the same point. /// /// Claims `[(Ci, xi, yi)]`, such that `xi = x` for any `i`, @@ -36,19 +38,27 @@ impl> Claim { /// /// If CS is knowledge-sound than an aggregate opening is a proof of knowledge for /// `{[(C_i, x, y_i)]; [f_i]): fi(x) = yi and CS::commit(fi) = ci}`. -pub fn aggregate_claims>(claims: &[Claim], rs: &[F]) -> Claim { +pub fn aggregate_claims>( + claims: &[Claim], + rs: &[F], +) -> Claim { assert_eq!(claims.len(), rs.len()); let mut iter_over_xs = claims.iter().map(|cl| cl.x); let same_x = iter_over_xs.next().expect("claims is empty"); - assert!(iter_over_xs.all(|x| x == same_x), "multiple evaluation points"); + assert!( + iter_over_xs.all(|x| x == same_x), + "multiple evaluation points" + ); // TODO: Detect duplicate claims? // Consider (Cf, x, y1) and (Cf, x, y2). // If y1 = y2 = f(x) both claims are valid // If y1 != y2, at least one of the 2 claims is invalid - let (rcs, rys): (Vec, Vec) = claims.iter().zip(rs.iter()) + let (rcs, rys): (Vec, Vec) = claims + .iter() + .zip(rs.iter()) .map(|(cl, &r)| (cl.c.mul(r), r * cl.y)) .unzip(); @@ -60,9 +70,9 @@ pub fn aggregate_claims>(claims: &[Claim], r } pub fn aggregate_claims_multiexp(cs: Vec, ys: Vec, rs: &[F]) -> (C, F) - where - F: PrimeField, - C: AffineRepr +where + F: PrimeField, + C: AffineRepr, { assert_eq!(cs.len(), rs.len()); assert_eq!(ys.len(), rs.len()); @@ -76,7 +86,9 @@ pub fn aggregate_claims_multiexp(cs: Vec, ys: Vec, rs: &[F]) -> (C, // for opening in a single point, the aggregate polynomial doesn't depend on the point. pub fn aggregate_polys(polys: &[Poly], rs: &[F]) -> Poly { assert_eq!(polys.len(), rs.len()); - polys.iter().zip(rs.iter()) + polys + .iter() + .zip(rs.iter()) .map(|(p, &r)| p * r) .fold(Poly::zero(), |acc, p| acc + p) } @@ -108,12 +120,12 @@ mod tests { let agg_poly = aggregate_polys(&polys, &rs); let same_x = F::rand(rng); - let claims_at_same_x = polys.iter() + let claims_at_same_x = polys + .iter() .map(|p| Claim::new::(&ck, p, same_x)) .collect::>(); let agg_claim = aggregate_claims::(&claims_at_same_x, &rs); - assert_eq!(CS::commit(&ck, &agg_poly), agg_claim.c); assert_eq!(same_x, agg_claim.x); assert_eq!(agg_poly.evaluate(&same_x), agg_claim.y); diff --git a/src/fflonk.rs b/src/fflonk.rs index 770462d..2180d61 100644 --- a/src/fflonk.rs +++ b/src/fflonk.rs @@ -17,8 +17,8 @@ pub struct Fflonk> { } impl> Fflonk - where for<'a, 'b> &'a P: Div<&'b P, Output=P> - +where + for<'a, 'b> &'a P: Div<&'b P, Output = P>, { // Given `t` degree `> Fflonk fn z_of_roots(t: usize, root_t_of_x: F) -> P { let x = root_t_of_x.pow([t as u64]); let mut z = vec![F::zero(); t + 1]; // deg(Z) = t - // coeffs(Z) = [-x, ..., 1] + // coeffs(Z) = [-x, ..., 1] z[0] = -x; z[t] = F::one(); P::from_coefficients_vec(z) @@ -78,11 +78,16 @@ impl> Fflonk pub fn opening_as_points(t: usize, root_of_x: F, evals_at_x: &[F]) -> (Vec, Vec) { assert_eq!(evals_at_x.len(), t); //TODO: may be 0-padded let roots = Self::roots(t, root_of_x); - let evals_at_roots = roots.iter().map(|&root| { - evals_at_x.iter() - .zip(utils::powers(root)) - .map(|(&eval, next_root)| eval * next_root).sum() - }).collect(); + let evals_at_roots = roots + .iter() + .map(|&root| { + evals_at_x + .iter() + .zip(utils::powers(root)) + .map(|(&eval, next_root)| eval * next_root) + .sum() + }) + .collect(); (roots, evals_at_roots) } @@ -93,12 +98,15 @@ impl> Fflonk pub fn multiopening(t: usize, roots_of_xs: &[F], evals_at_xs: &[Vec]) -> (Vec, Vec) { assert_eq!(roots_of_xs.len(), evals_at_xs.len()); assert!(evals_at_xs.iter().all(|evals_at_x| evals_at_x.len() == t)); - let polys = evals_at_xs.iter() + let polys = evals_at_xs + .iter() .map(|evals_at_x| P::from_coefficients_slice(evals_at_x)); - let roots = roots_of_xs.iter() + let roots = roots_of_xs + .iter() .map(|&root_of_x| Self::roots(t, root_of_x)); let xs: Vec<_> = roots.clone().flatten().collect(); - let vs: Vec<_> = polys.zip(roots) + let vs: Vec<_> = polys + .zip(roots) .flat_map(|(poly, roots)| Self::multievaluate(&poly, &roots)) .collect(); (xs, vs) @@ -114,8 +122,8 @@ impl> Fflonk #[cfg(test)] mod tests { use ark_ff::Field; - use ark_poly::Polynomial; use ark_poly::univariate::{DenseOrSparsePolynomial, DensePolynomial}; + use ark_poly::Polynomial; use ark_std::{test_rng, UniformRand, Zero}; use super::*; @@ -134,10 +142,9 @@ mod tests { let root_t_of_x = F::rand(rng); // a t-th root of the opening point let x = root_t_of_x.pow([t as u64]); // the opening point - let fs: Vec

= (0..t) - .map(|_| P::rand(d, rng)) - .collect(); - let fs_at_x: Vec = fs.iter() // + let fs: Vec

= (0..t).map(|_| P::rand(d, rng)).collect(); + let fs_at_x: Vec = fs + .iter() // .map(|fi| fi.evaluate(&x)) .collect(); @@ -153,10 +160,8 @@ mod tests { // r -- interpolates vs in xs assert!(xs.iter().zip(vs.iter()).all(|(x, &v)| r.evaluate(x) == v)); // g mod z = r - let (_, g_mod_z) = DenseOrSparsePolynomial::divide_with_q_and_r( - &(&g.into()), - &(&z.into()), - ).unwrap(); + let (_, g_mod_z) = + DenseOrSparsePolynomial::divide_with_q_and_r(&(&g.into()), &(&z.into())).unwrap(); assert_eq!(r, g_mod_z); } @@ -171,14 +176,14 @@ mod tests { let roots_of_xs: Vec = (0..m) // t-th roots of opening points .map(|_| F::rand(rng)) .collect(); - let xs: Vec = roots_of_xs.iter() // opening points + let xs: Vec = roots_of_xs + .iter() // opening points .map(|root_t_of_x| root_t_of_x.pow([t as u64])) .collect(); - let fs: Vec

= (0..t) - .map(|_| P::rand(d, rng)) - .collect(); - let fs_at_xs: Vec> = xs.iter() + let fs: Vec

= (0..t).map(|_| P::rand(d, rng)).collect(); + let fs_at_xs: Vec> = xs + .iter() .map(|x| fs.iter().map(|fi| fi.evaluate(&x)).collect()) .collect(); @@ -198,10 +203,9 @@ mod tests { let root_t_of_x = F::rand(rng); // a t-th root of the opening point let x = root_t_of_x.pow([t as u64]); // the opening point - let fs: Vec

= (0..t) - .map(|_| P::rand(d, rng)) - .collect(); - let fs_at_x: Vec = fs.iter() // + let fs: Vec

= (0..t).map(|_| P::rand(d, rng)).collect(); + let fs_at_x: Vec = fs + .iter() // .map(|fi| fi.evaluate(&x)) .collect(); @@ -211,4 +215,4 @@ mod tests { assert!(xs.iter().all(|x| z.evaluate(x).is_zero())); assert!(xs.iter().zip(vs).all(|(x, v)| r.evaluate(x) == v)); } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 1f33a4b..2f8e43d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,9 +2,9 @@ use ark_ff::PrimeField; use ark_poly::univariate::{DenseOrSparsePolynomial, DensePolynomial}; +use ark_std::marker::PhantomData; use ark_std::rand::Rng; use ark_std::vec::Vec; -use ark_std::marker::PhantomData; use aggregation::multiple::Transcript; @@ -12,12 +12,11 @@ use crate::fflonk::Fflonk; use crate::pcs::PCS; use crate::shplonk::{AggregateProof, Shplonk}; -pub mod shplonk; +pub mod aggregation; pub mod fflonk; pub mod pcs; +pub mod shplonk; pub mod utils; -pub mod aggregation; - pub type Poly = DensePolynomial; // currently SparsePolynomial doesn't implement DenseUVPolynomial anyway @@ -33,7 +32,6 @@ impl EuclideanPolynomial for Poly { } } - pub struct FflonkyKzg> { _field: PhantomData, _pcs: PhantomData, @@ -47,26 +45,29 @@ impl> FflonkyKzg { pub fn open>( ck: &CS::CK, fss: &[Vec>], // vecs of polynomials to combine - ts: &[usize], // lengths of each combination + ts: &[usize], // lengths of each combination // TODO: ts can be inferred from li := len(fss[i]) as ti = min(x : x >= li and x | p-1) rootss: &[Vec], // sets of opening points per a combined polynomial presented as t-th roots transcript: &mut T, - ) -> AggregateProof - { + ) -> AggregateProof { let k = fss.len(); assert_eq!(k, ts.len()); assert_eq!(k, rootss.len()); - let gs: Vec> = fss.iter() + let gs: Vec> = fss + .iter() .zip(ts.iter()) .map(|(fs, t)| Fflonk::combine(*t, fs)) .collect(); - let xss: Vec<_> = rootss.iter() + let xss: Vec<_> = rootss + .iter() .zip(ts.iter()) - .map(|(roots, t)| - roots.iter() + .map(|(roots, t)| { + roots + .iter() .flat_map(|root| Fflonk::>::roots(*t, *root)) .collect() - ).collect(); + }) + .collect(); Shplonk::::open_many(ck, &gs, &xss, transcript) } @@ -79,14 +80,13 @@ impl> FflonkyKzg { rootss: &[Vec], vss: &[Vec>], transcript: &mut T, - ) -> bool - { - let (xss, yss) = rootss.iter() + ) -> bool { + let (xss, yss) = rootss + .iter() .zip(vss.iter()) .zip(ts.iter()) - .map(|((roots, vs), t)| - Fflonk::>::multiopening(*t, roots, vs) - ).unzip(); + .map(|((roots, vs), t)| Fflonk::>::multiopening(*t, roots, vs)) + .unzip(); Shplonk::::verify_many(vk, &gcs, proof, &xss, &yss, transcript) } @@ -94,11 +94,10 @@ impl> FflonkyKzg { pub fn open_single>( ck: &CS::CK, fs: &[Poly], // polynomials to combine - t: usize, // lengths of the combination - roots: &[F], // set of opening points presented as t-th roots + t: usize, // lengths of the combination + roots: &[F], // set of opening points presented as t-th roots transcript: &mut T, - ) -> AggregateProof - { + ) -> AggregateProof { Self::open(ck, &[fs.to_vec()], &[t], &[roots.to_vec()], transcript) } @@ -110,13 +109,19 @@ impl> FflonkyKzg { roots: &[F], vss: &[Vec], // evaluations per point // TODO: shplonk provides API with evals per polynomial transcript: &mut T, - ) -> bool - { - Self::verify(vk, &[(*gc).clone()], &[t], proof, &[roots.to_vec()], &[vss.to_vec()], transcript) + ) -> bool { + Self::verify( + vk, + &[(*gc).clone()], + &[t], + proof, + &[roots.to_vec()], + &[vss.to_vec()], + transcript, + ) } } - #[cfg(test)] mod tests { use ark_ec::pairing::Pairing; @@ -125,21 +130,21 @@ mod tests { use ark_std::test_rng; use ark_std::vec; - use crate::pcs::IdentityCommitment; use crate::pcs::kzg::KZG; + use crate::pcs::IdentityCommitment; use crate::pcs::PcsParams; use super::*; pub(crate) type TestCurve = ark_bls12_381::Bls12_381; pub(crate) type TestField = ::ScalarField; - pub(crate) type TestKzg = KZG::; + pub(crate) type TestKzg = KZG; pub(crate) type BenchCurve = ark_bw6_761::BW6_761; pub(crate) type BenchField = ::ScalarField; #[allow(dead_code)] // used by ignored tests - pub(crate) type BenchKzg = KZG::; + pub(crate) type BenchKzg = KZG; pub const BENCH_DEG_LOG1: usize = 10; // pub const BENCH_DEG_LOG2: usize = 16; @@ -150,9 +155,7 @@ mod tests { self.0 } - fn commit_to_q(&mut self, _q: &CS::C) { - - } + fn commit_to_q(&mut self, _q: &CS::C) {} fn get_zeta(&mut self) -> F { self.1 @@ -166,32 +169,28 @@ mod tests { m: usize, // number of opening points ) -> ( Vec>, // polynomials - Vec, // roots of evaluation points - Vec>, // evaluations per point - ) where + Vec, // roots of evaluation points + Vec>, // evaluations per point + ) + where R: Rng, F: PrimeField, { // polynomials - let fs: Vec> = (0..t) - .map(|_| Poly::rand(d, rng)) - .collect(); + let fs: Vec> = (0..t).map(|_| Poly::rand(d, rng)).collect(); - let roots: Vec<_> = (0..m) - .map(|_| F::rand(rng)) - .collect(); + let roots: Vec<_> = (0..m).map(|_| F::rand(rng)).collect(); - let xs: Vec = roots.iter() // opening points + let xs: Vec = roots + .iter() // opening points .map(|root| root.pow([t as u64])) .collect(); // evaluations per point - let vss: Vec<_> = xs.iter() - .map(|x| - fs.iter() - .map(|f| f.evaluate(x)) - .collect::>() - ).collect(); + let vss: Vec<_> = xs + .iter() + .map(|x| fs.iter().map(|f| f.evaluate(x)).collect::>()) + .collect(); (fs, roots, vss) } @@ -212,7 +211,15 @@ mod tests { let gc = CS::commit(¶ms.ck(), &g); let proof = FflonkyKzg::::open_single(¶ms.ck(), &fs, t, &roots, transcript); - assert!(FflonkyKzg::::verify_single(¶ms.vk(), &gc, t, proof, &roots, &vss, transcript)); + assert!(FflonkyKzg::::verify_single( + ¶ms.vk(), + &gc, + t, + proof, + &roots, + &vss, + transcript + )); } fn _test_fflonk>() { @@ -228,23 +235,29 @@ mod tests { let mut fss = vec![]; let mut rootss = vec![]; let mut vsss = vec![]; - for ((d, t), m) in ds.into_iter() - .zip(ts) - .zip(ms) - { + for ((d, t), m) in ds.into_iter().zip(ts).zip(ms) { let (fs, roots, vss) = generate_test_data(rng, d, t, m); fss.push(fs); rootss.push(roots); vsss.push(vss); } - let gcs: Vec<_> = fss.iter() + let gcs: Vec<_> = fss + .iter() .zip(ts) .map(|(fs, t)| CS::commit(¶ms.ck(), &Fflonk::combine(t, &fs))) .collect(); let proof = FflonkyKzg::::open(¶ms.ck(), &fss, &ts, &rootss, transcript); - assert!(FflonkyKzg::::verify(¶ms.vk(), &gcs, &ts, proof, &rootss, &vsss, transcript)); + assert!(FflonkyKzg::::verify( + ¶ms.vk(), + &gcs, + &ts, + proof, + &rootss, + &vsss, + transcript + )); } #[test] @@ -258,4 +271,4 @@ mod tests { _test_fflonk::(); _test_fflonk::(); } -} \ No newline at end of file +} diff --git a/src/pcs/id/mod.rs b/src/pcs/id/mod.rs index b49c862..a08a2b2 100644 --- a/src/pcs/id/mod.rs +++ b/src/pcs/id/mod.rs @@ -4,8 +4,8 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::vec::Vec; use crate::pcs::*; -use crate::Poly; use crate::utils::poly; +use crate::Poly; #[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] pub struct WrappedPolynomial(pub Poly); @@ -35,7 +35,7 @@ impl Sub for WrappedPolynomial { } impl core::iter::Sum for WrappedPolynomial { - fn sum>(iter: I) -> Self { + fn sum>(iter: I) -> Self { iter.reduce(|a, b| a + b).unwrap() } } @@ -48,13 +48,16 @@ impl Commitment for WrappedPolynomial { } fn combine(coeffs: &[F], commitments: &[Self]) -> Self { - let polys = commitments.to_vec().into_iter().map(|c| c.0).collect::>(); + let polys = commitments + .to_vec() + .into_iter() + .map(|c| c.0) + .collect::>(); let combined = poly::sum_with_coeffs(coeffs.to_vec(), &polys); WrappedPolynomial(combined) } } - impl CommitterKey for () { fn max_degree(&self) -> usize { usize::MAX >> 1 @@ -75,7 +78,6 @@ impl RawVerifierKey for () { } } - impl PcsParams for () { type CK = (); type VK = (); @@ -94,7 +96,6 @@ impl PcsParams for () { } } - #[derive(Clone)] pub struct IdentityCommitment {} @@ -121,4 +122,3 @@ impl PCS for IdentityCommitment { c.evaluate(&x) == z } } - diff --git a/src/pcs/kzg/commitment.rs b/src/pcs/kzg/commitment.rs index e2c090c..88da5c3 100644 --- a/src/pcs/kzg/commitment.rs +++ b/src/pcs/kzg/commitment.rs @@ -1,5 +1,5 @@ -use ark_ec::{AffineRepr, CurveGroup}; use ark_ec::pairing::Pairing; +use ark_ec::{AffineRepr, CurveGroup}; use ark_serialize::*; use ark_std::iter::Sum; use ark_std::ops::{Add, Mul, Sub}; @@ -12,8 +12,7 @@ use crate::utils::ec::small_multiexp_affine; #[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] pub struct KzgCommitment(pub E::G1Affine); - -impl Commitment for KzgCommitment { +impl Commitment for KzgCommitment { fn mul(&self, by: E::ScalarField) -> KzgCommitment { KzgCommitment(self.0.mul(by).into()) } @@ -42,7 +41,7 @@ impl Sub for KzgCommitment { } impl Sum for KzgCommitment { - fn sum>(iter: I) -> KzgCommitment { + fn sum>(iter: I) -> KzgCommitment { KzgCommitment(iter.map(|c| c.0.into_group()).sum::().into_affine()) } -} \ No newline at end of file +} diff --git a/src/pcs/kzg/lagrange.rs b/src/pcs/kzg/lagrange.rs index e421be3..b65acb4 100644 --- a/src/pcs/kzg/lagrange.rs +++ b/src/pcs/kzg/lagrange.rs @@ -3,21 +3,23 @@ use ark_ff::Zero; use ark_poly::{EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::rand::RngCore; -use ark_std::UniformRand; use ark_std::vec::Vec; +use ark_std::UniformRand; -use crate::pcs::CommitterKey; use crate::pcs::kzg::params::MonomialCK; +use crate::pcs::CommitterKey; /// Used to commit to univariate polynomials represented in the evaluation form. #[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)] -pub struct LagrangianCK = GeneralEvaluationDomain<::ScalarField>> { +pub struct LagrangianCK< + G: AffineRepr, + D: EvaluationDomain = GeneralEvaluationDomain<::ScalarField>, +> { // L_0(tau).G, L_1(tau).G, ..., L_{n-1}(tau).G pub lis_in_g: Vec, pub domain: D, } - impl CommitterKey for LagrangianCK { fn max_degree(&self) -> usize { self.lis_in_g.len() - 1 @@ -40,9 +42,14 @@ impl> LagrangianCK { } impl MonomialCK { - pub fn to_lagrangian>(&self, domain: D) -> LagrangianCK { + pub fn to_lagrangian>( + &self, + domain: D, + ) -> LagrangianCK { assert!(self.max_evals() >= domain.size()); - let mut monomial_bases = self.powers_in_g1.iter() + let mut monomial_bases = self + .powers_in_g1 + .iter() .take(domain.size()) .map(|p| p.into_group()) .collect(); @@ -53,14 +60,10 @@ impl MonomialCK { }; let lis_in_g = G::Group::normalize_batch(&lagrangian_bases); - LagrangianCK { - lis_in_g, - domain, - } + LagrangianCK { lis_in_g, domain } } } - #[cfg(test)] mod tests { use ark_ec::pairing::Pairing; @@ -84,7 +87,11 @@ mod tests { let monomial_ck = urs.ck().monomial; let lagrangian_ck_from_monomial_urs = monomial_ck.to_lagrangian(domain); - let lagrangian_ck_from_trapdoor = LagrangianCK::<::G1Affine>::from_trapdoor(domain, tau, g1); - assert_eq!(lagrangian_ck_from_monomial_urs.lis_in_g, lagrangian_ck_from_trapdoor.lis_in_g); + let lagrangian_ck_from_trapdoor = + LagrangianCK::<::G1Affine>::from_trapdoor(domain, tau, g1); + assert_eq!( + lagrangian_ck_from_monomial_urs.lis_in_g, + lagrangian_ck_from_trapdoor.lis_in_g + ); } -} \ No newline at end of file +} diff --git a/src/pcs/kzg/mod.rs b/src/pcs/kzg/mod.rs index 6991596..b286fc5 100644 --- a/src/pcs/kzg/mod.rs +++ b/src/pcs/kzg/mod.rs @@ -15,10 +15,10 @@ use crate::pcs::{CommitterKey, PCS}; use crate::utils::ec::{small_multiexp_affine, small_multiexp_proj}; use crate::Poly; -pub mod urs; -pub mod params; pub mod commitment; mod lagrange; +pub mod params; +pub mod urs; #[derive(Clone)] pub struct KZG { @@ -54,16 +54,26 @@ impl KZG { } fn parse(openings: Vec>) -> Vec<((E::G1, E::G1Affine), E::ScalarField)> { - openings.into_iter().map(|KzgOpening { c, x, y, proof }| - ((proof.mul(x) + &c, proof), y) - ).collect() + openings + .into_iter() + .map(|KzgOpening { c, x, y, proof }| ((proof.mul(x) + &c, proof), y)) + .collect() } - pub fn accumulate(openings: Vec>, rs: &[E::ScalarField], vk: &KzgVerifierKey) -> AccumulatedOpening { + pub fn accumulate( + openings: Vec>, + rs: &[E::ScalarField], + vk: &KzgVerifierKey, + ) -> AccumulatedOpening { assert_eq!(openings.len(), rs.len()); let openings = Self::parse(openings); - let ((accs, proofs), ys): ((Vec, Vec), Vec) = openings.into_iter().unzip(); - let sum_ry = rs.iter().zip(ys.into_iter()).map(|(r, y)| y * r).sum::(); + let ((accs, proofs), ys): ((Vec, Vec), Vec) = + openings.into_iter().unzip(); + let sum_ry = rs + .iter() + .zip(ys.into_iter()) + .map(|(r, y)| y * r) + .sum::(); let acc = vk.g1.mul(sum_ry) - small_multiexp_proj(rs, &accs); let proof = small_multiexp_affine(rs, &proofs); let points = E::G1::normalize_batch(&[acc, proof]); @@ -79,9 +89,11 @@ impl KZG { } pub fn verify_accumulated(opening: AccumulatedOpening, vk: &KzgVerifierKey) -> bool { - E::multi_pairing(&[opening.acc, opening.proof], - [vk.g2.clone(), vk.tau_in_g2.clone()], - ).is_zero() + E::multi_pairing( + &[opening.acc, opening.proof], + [vk.g2.clone(), vk.tau_in_g2.clone()], + ) + .is_zero() } pub fn verify_single(opening: KzgOpening, vk: &KzgVerifierKey) -> bool { @@ -89,9 +101,15 @@ impl KZG { Self::verify_accumulated(acc_opening, vk) } - pub fn verify_batch(openings: Vec>, vk: &KzgVerifierKey, rng: &mut R) -> bool { + pub fn verify_batch( + openings: Vec>, + vk: &KzgVerifierKey, + rng: &mut R, + ) -> bool { let one = ark_std::iter::once(E::ScalarField::one()); - let coeffs: Vec = one.chain((1..openings.len()).map(|_| u128::rand(rng).into())).collect(); + let coeffs: Vec = one + .chain((1..openings.len()).map(|_| u128::rand(rng).into())) + .collect(); let acc_opening = Self::accumulate(openings, &coeffs, vk); Self::verify_accumulated(acc_opening, vk) } @@ -119,14 +137,27 @@ impl PCS for KZG { fn commit(ck: &Self::CK, p: &Poly) -> Self::C { let ck = &ck.monomial; - assert!(p.degree() <= ck.max_degree(), "Can't commit to degree {} polynomial using {} bases", p.degree(), ck.max_evals()); + assert!( + p.degree() <= ck.max_degree(), + "Can't commit to degree {} polynomial using {} bases", + p.degree(), + ck.max_evals() + ); Self::_commit(&p.coeffs, &ck.powers_in_g1) } fn commit_evals(ck: &Self::CK, evals: &Evaluations) -> Self::C { - let ck = ck.lagrangian.as_ref().expect("lagrangian key hadn't been generated"); + let ck = ck + .lagrangian + .as_ref() + .expect("lagrangian key hadn't been generated"); assert_eq!(evals.domain(), ck.domain); - assert!(evals.evals.len() <= ck.max_evals(), "Can't commit to {} values using {} bases", evals.evals.len(), ck.max_evals()); + assert!( + evals.evals.len() <= ck.max_evals(), + "Can't commit to {} values using {} bases", + evals.evals.len(), + ck.max_evals() + ); Self::_commit(&evals.evals, &ck.lis_in_g) } @@ -135,16 +166,43 @@ impl PCS for KZG { Self::commit(ck, &q).0 } - fn verify(vk: &KzgVerifierKey, c: Self::C, x: E::ScalarField, y: E::ScalarField, proof: Self::Proof) -> bool { - let opening = KzgOpening { c: c.0, x, y, proof }; + fn verify( + vk: &KzgVerifierKey, + c: Self::C, + x: E::ScalarField, + y: E::ScalarField, + proof: Self::Proof, + ) -> bool { + let opening = KzgOpening { + c: c.0, + x, + y, + proof, + }; Self::verify_single(opening, vk) } - fn batch_verify(vk: &KzgVerifierKey, c: Vec, x: Vec, y: Vec, proof: Vec, rng: &mut R) -> bool { + fn batch_verify( + vk: &KzgVerifierKey, + c: Vec, + x: Vec, + y: Vec, + proof: Vec, + rng: &mut R, + ) -> bool { assert_eq!(c.len(), x.len()); assert_eq!(c.len(), y.len()); - let openings = c.into_iter().zip(x.into_iter()).zip(y.into_iter()).zip(proof.into_iter()) - .map(|(((c, x), y), proof)| KzgOpening { c: c.0, x, y, proof }) + let openings = c + .into_iter() + .zip(x.into_iter()) + .zip(y.into_iter()) + .zip(proof.into_iter()) + .map(|(((c, x), y), proof)| KzgOpening { + c: c.0, + x, + y, + proof, + }) .collect(); Self::verify_batch(openings, vk, rng) } @@ -170,7 +228,11 @@ mod tests { let max_degree = (1 << log_n) - 1; - let t_setup = start_timer!(|| format!("KZG setup of size 2^{} on {}", log_n, crate::utils::curve_name::())); + let t_setup = start_timer!(|| format!( + "KZG setup of size 2^{} on {}", + log_n, + crate::utils::curve_name::() + )); let urs = KZG::::setup(max_degree, rng); end_timer!(t_setup); @@ -181,7 +243,10 @@ mod tests { let x = E::ScalarField::rand(rng); let z = p.evaluate(&x); - let t_commit = start_timer!(|| format!("Committing to a dense degree-{} polynomial", ck.max_degree())); + let t_commit = start_timer!(|| format!( + "Committing to a dense degree-{} polynomial", + ck.max_degree() + )); let c = KZG::::commit(&ck, &p); end_timer!(t_commit); @@ -199,19 +264,20 @@ mod tests { ck: &KzgCommitterKey, xs: Vec, rng: &mut R, - ) -> Vec> - { + ) -> Vec> { assert_eq!(xs.len(), k); let d = ck.max_degree(); - (0..k).map(|i| { - let f = Poly::::rand(d, rng); - let x = xs[i]; - let y = f.evaluate(&x); - let c = KZG::::commit(ck, &f).0; - let proof = KZG::::open(ck, &f, x); - KzgOpening { c, x, y, proof } - }).collect() + (0..k) + .map(|i| { + let f = Poly::::rand(d, rng); + let x = xs[i]; + let y = f.evaluate(&x); + let c = KZG::::commit(ck, &f).0; + let proof = KZG::::open(ck, &f, x); + KzgOpening { c, x, y, proof } + }) + .collect() } fn _test_batch_verification(log_n: usize, k: usize) { @@ -224,13 +290,27 @@ mod tests { let xs = (0..k).map(|_| E::ScalarField::rand(rng)).collect(); let openings = random_openings(k, &ck, xs, rng); - let t_verify_batch = start_timer!(|| format!("Batch verification of {} openings of degree ~2^{} on {} with {}-bit xs", k, log_n, crate::utils::curve_name::(), E::ScalarField::MODULUS_BIT_SIZE)); + let t_verify_batch = start_timer!(|| format!( + "Batch verification of {} openings of degree ~2^{} on {} with {}-bit xs", + k, + log_n, + crate::utils::curve_name::(), + E::ScalarField::MODULUS_BIT_SIZE + )); assert!(KZG::::verify_batch(openings, &vk, rng)); end_timer!(t_verify_batch); - let xs = (0..k).map(|_| E::ScalarField::from(u128::rand(rng))).collect(); + let xs = (0..k) + .map(|_| E::ScalarField::from(u128::rand(rng))) + .collect(); let openings = random_openings(k, &ck, xs, rng); - let t_verify_batch = start_timer!(|| format!("Batch verification of {} openings of degree ~2^{} on {} with {}-bit xs", k, log_n, crate::utils::curve_name::(), 128)); + let t_verify_batch = start_timer!(|| format!( + "Batch verification of {} openings of degree ~2^{} on {} with {}-bit xs", + k, + log_n, + crate::utils::curve_name::(), + 128 + )); assert!(KZG::::verify_batch(openings, &vk, rng)); end_timer!(t_verify_batch); } diff --git a/src/pcs/kzg/params.rs b/src/pcs/kzg/params.rs index b4cb5a3..62e2dd5 100644 --- a/src/pcs/kzg/params.rs +++ b/src/pcs/kzg/params.rs @@ -1,12 +1,12 @@ -use ark_ec::AffineRepr; use ark_ec::pairing::Pairing; +use ark_ec::AffineRepr; use ark_poly::{EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::*; use ark_std::{vec, vec::Vec}; -use crate::pcs::{CommitterKey, PcsParams, RawVerifierKey, VerifierKey}; use crate::pcs::kzg::lagrange::LagrangianCK; use crate::pcs::kzg::urs::URS; +use crate::pcs::{CommitterKey, PcsParams, RawVerifierKey, VerifierKey}; impl PcsParams for URS { type CK = KzgCommitterKey; @@ -15,20 +15,31 @@ impl PcsParams for URS { fn ck(&self) -> Self::CK { let monomial = MonomialCK { - powers_in_g1: self.powers_in_g1.clone() + powers_in_g1: self.powers_in_g1.clone(), }; - KzgCommitterKey { monomial, lagrangian: None } + KzgCommitterKey { + monomial, + lagrangian: None, + } } fn ck_with_lagrangian(&self, domain_size: usize) -> Self::CK { let domain = GeneralEvaluationDomain::new(domain_size).unwrap(); - assert_eq!(domain.size(), domain_size, "domains of size {} are not supported", domain_size); + assert_eq!( + domain.size(), + domain_size, + "domains of size {} are not supported", + domain_size + ); assert!(domain_size <= self.powers_in_g1.len()); let monomial = MonomialCK { - powers_in_g1: self.powers_in_g1[0..domain_size].to_vec() + powers_in_g1: self.powers_in_g1[0..domain_size].to_vec(), }; let lagrangian = Some(monomial.to_lagrangian(domain)); - KzgCommitterKey { monomial, lagrangian } + KzgCommitterKey { + monomial, + lagrangian, + } } fn vk(&self) -> Self::VK { @@ -38,7 +49,11 @@ impl PcsParams for URS { /// Non-prepared verifier key. Can be used for serialization. fn raw_vk(&self) -> Self::RVK { assert!(self.powers_in_g1.len() > 0, "no G1 generator"); - assert!(self.powers_in_g2.len() > 1, "{} powers in G2", self.powers_in_g2.len()); + assert!( + self.powers_in_g2.len() > 1, + "{} powers in G2", + self.powers_in_g2.len() + ); RawKzgVerifierKey { g1: self.powers_in_g1[0], @@ -54,7 +69,6 @@ pub struct KzgCommitterKey { pub lagrangian: Option>, } - /// Used to commit to and to open univariate polynomials of degree up to self.max_degree(). #[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)] pub struct MonomialCK { @@ -74,7 +88,6 @@ impl CommitterKey for KzgCommitterKey { } } - /// Verifier key with G2 elements not "prepared". Exists only to be serializable. /// KzgVerifierKey is used for verification. #[derive(Clone, Debug, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] @@ -86,7 +99,6 @@ pub struct RawKzgVerifierKey { pub tau_in_g2: E::G2Affine, // tau.g2 } - impl RawVerifierKey for RawKzgVerifierKey { type VK = KzgVerifierKey; @@ -102,7 +114,6 @@ impl RawVerifierKey for RawKzgVerifierKey { } } - /// "Prepared" verifier key capable of verifying opening in a single point, given the commitment is in G1. /// Use RawKzgVerifierKey for serialization. #[derive(Clone, Debug)] @@ -121,8 +132,12 @@ impl VerifierKey for KzgVerifierKey {} impl From> for KzgCommitterKey { fn from(vk: KzgVerifierKey) -> Self { - let monomial = MonomialCK { powers_in_g1: vec![vk.g1] }; - Self { monomial, lagrangian: None } + let monomial = MonomialCK { + powers_in_g1: vec![vk.g1], + }; + Self { + monomial, + lagrangian: None, + } } } - diff --git a/src/pcs/kzg/urs.rs b/src/pcs/kzg/urs.rs index 96f7ce0..22d563e 100644 --- a/src/pcs/kzg/urs.rs +++ b/src/pcs/kzg/urs.rs @@ -31,7 +31,7 @@ impl URS { let tau = E::ScalarField::rand(rng); let g1 = E::G1::rand(rng); let g2 = E::G2::rand(rng); - (tau, g1 , g2) + (tau, g1, g2) } /// Generates URS of the form: g1, tau.g1, ..., tau^{n1-1}.g1, g2, tau.g2, ..., tau^{n2-1}.g2 @@ -43,7 +43,10 @@ impl URS { // // Assertion note: as `TWO_ADICITY` for the field can be >= 32 and on 32-bit machine targets // `usize` is just 32-bit we move the check in the `u64` domain to avoid a panic. - assert!(n as u64 <= 1u64 << E::ScalarField::TWO_ADICITY, "number of bases exceeds curve 2-adicity"); + assert!( + n as u64 <= 1u64 << E::ScalarField::TWO_ADICITY, + "number of bases exceeds curve 2-adicity" + ); let t_powers = start_timer!(|| format!("Computing {} scalars powers", n)); // tau^0, ..., tau^(n-1)) @@ -65,7 +68,6 @@ impl URS { } } - #[cfg(test)] mod tests { use ark_std::test_rng; @@ -78,7 +80,12 @@ mod tests { let n1 = 1 << log_n1; let n2 = 1 << log_n2; - let t_generate = start_timer!(|| format!("Generate 2^{} G1 and 2^{} G2 bases for {}", log_n1, log_n2, crate::utils::curve_name::())); + let t_generate = start_timer!(|| format!( + "Generate 2^{} G1 and 2^{} G2 bases for {}", + log_n1, + log_n2, + crate::utils::curve_name::() + )); let urs = URS::::generate(n1, n2, &mut test_rng()); end_timer!(t_generate); diff --git a/src/pcs/mod.rs b/src/pcs/mod.rs index 31dab7e..743144d 100644 --- a/src/pcs/mod.rs +++ b/src/pcs/mod.rs @@ -11,25 +11,24 @@ pub use id::IdentityCommitment; use crate::Poly; -pub mod kzg; mod id; +pub mod kzg; pub trait Commitment: -Eq -+ Sized -+ Clone -+ Debug -+ Add -+ Sub -+ Sum -+ CanonicalSerialize -+ CanonicalDeserialize + Eq + + Sized + + Clone + + Debug + + Add + + Sub + + Sum + + CanonicalSerialize + + CanonicalDeserialize { fn mul(&self, by: F) -> Self; fn combine(coeffs: &[F], commitments: &[Self]) -> Self; } - /// Can be used to commit and open commitments to DensePolynomial of degree up to max_degree. pub trait CommitterKey: Clone + Debug + CanonicalSerialize + CanonicalDeserialize { /// Maximal degree of a polynomial supported. @@ -41,7 +40,6 @@ pub trait CommitterKey: Clone + Debug + CanonicalSerialize + CanonicalDeserializ } } - /// Can be used to verify openings to commitments. pub trait VerifierKey: Clone + Debug { /// Maximal number of openings that can be verified. @@ -50,19 +48,19 @@ pub trait VerifierKey: Clone + Debug { } } - /// Generates a `VerifierKey`, serializable -pub trait RawVerifierKey: Clone + Debug + Eq + PartialEq + CanonicalSerialize + CanonicalDeserialize { +pub trait RawVerifierKey: + Clone + Debug + Eq + PartialEq + CanonicalSerialize + CanonicalDeserialize +{ type VK: VerifierKey; fn prepare(&self) -> Self::VK; } - pub trait PcsParams { type CK: CommitterKey; type VK: VerifierKey; - type RVK: RawVerifierKey; + type RVK: RawVerifierKey; fn ck(&self) -> Self::CK; fn vk(&self) -> Self::VK; @@ -73,7 +71,6 @@ pub trait PcsParams { } } - /// Polynomial commitment scheme. pub trait PCS { type C: Commitment; @@ -85,7 +82,7 @@ pub trait PCS { // vk needs to be convertible to a ck that is only required to commit to the p=1 constant polynomial, // see https://eprint.iacr.org/archive/2020/1536/1629188090.pdf, section 4.2 type VK: VerifierKey + Into; - type Params: PcsParams; + type Params: PcsParams; fn setup(max_degree: usize, rng: &mut R) -> Self::Params; @@ -100,10 +97,20 @@ pub trait PCS { fn verify(vk: &Self::VK, c: Self::C, x: F, z: F, proof: Self::Proof) -> bool; - fn batch_verify(vk: &Self::VK, c: Vec, x: Vec, y: Vec, proof: Vec, _rng: &mut R) -> bool { + fn batch_verify( + vk: &Self::VK, + c: Vec, + x: Vec, + y: Vec, + proof: Vec, + _rng: &mut R, + ) -> bool { assert_eq!(c.len(), x.len()); assert_eq!(c.len(), y.len()); - c.into_iter().zip(x.into_iter()).zip(y.into_iter()).zip(proof.into_iter()) + c.into_iter() + .zip(x.into_iter()) + .zip(y.into_iter()) + .zip(proof.into_iter()) .all(|(((c, x), y), proof)| Self::verify(vk, c, x, y, proof)) } } diff --git a/src/shplonk.rs b/src/shplonk.rs index a2f5b94..1078e39 100644 --- a/src/shplonk.rs +++ b/src/shplonk.rs @@ -1,11 +1,13 @@ use ark_ff::PrimeField; use ark_poly::{DenseUVPolynomial, Polynomial}; use ark_serialize::*; -use ark_std::vec::Vec; -use ark_std::marker::PhantomData; use ark_std::collections::BTreeSet; +use ark_std::marker::PhantomData; +use ark_std::vec::Vec; -use crate::aggregation::multiple::{aggregate_claims, aggregate_polys, group_by_commitment, Transcript}; +use crate::aggregation::multiple::{ + aggregate_claims, aggregate_polys, group_by_commitment, Transcript, +}; use crate::pcs::PCS; use crate::Poly; @@ -26,12 +28,14 @@ impl> Shplonk { fs: &[Poly], xss: &[BTreeSet], transcript: &mut T, - ) -> AggregateProof - { + ) -> AggregateProof { let (agg_poly, zeta, agg_proof) = aggregate_polys::(ck, fs, xss, transcript); assert!(agg_poly.evaluate(&zeta).is_zero()); let opening_proof = CS::open(ck, &agg_poly, zeta); - AggregateProof {agg_proof, opening_proof} + AggregateProof { + agg_proof, + opening_proof, + } } pub fn verify_many>( @@ -41,27 +45,37 @@ impl> Shplonk { xss: &Vec>, yss: &Vec>, transcript: &mut T, - ) -> bool - { - let AggregateProof {agg_proof, opening_proof} = proof; - let onec = CS::commit(&vk.clone().into(), &Poly::from_coefficients_slice(&[F::one()])); + ) -> bool { + let AggregateProof { + agg_proof, + opening_proof, + } = proof; + let onec = CS::commit( + &vk.clone().into(), + &Poly::from_coefficients_slice(&[F::one()]), + ); let claims = group_by_commitment(fcs, xss, yss); let agg_claim = aggregate_claims::(claims, &agg_proof, &onec, transcript); - CS::verify(vk, agg_claim.c, agg_claim.xs[0], agg_claim.ys[0], opening_proof) + CS::verify( + vk, + agg_claim.c, + agg_claim.xs[0], + agg_claim.ys[0], + opening_proof, + ) } } - #[cfg(test)] pub(crate) mod tests { use ark_std::iter::FromIterator; use ark_std::rand::Rng; use ark_std::test_rng; - use crate::pcs::{Commitment, PcsParams}; use crate::pcs::IdentityCommitment; - use crate::Poly; + use crate::pcs::{Commitment, PcsParams}; use crate::tests::{TestField, TestKzg}; + use crate::Poly; use super::*; @@ -74,43 +88,41 @@ pub(crate) mod tests { pub(crate) fn random_xss( rng: &mut R, - t: usize, // number of polynomials + t: usize, // number of polynomials max_m: usize, // maximal number of opening points per polynomial ) -> Vec> { (0..t) - .map(|_| (0..rng.gen_range(1..max_m)) - .map(|_| F::rand(rng)).collect::>()) + .map(|_| { + (0..rng.gen_range(1..max_m)) + .map(|_| F::rand(rng)) + .collect::>() + }) .collect() } pub(crate) fn random_opening( rng: &mut R, ck: &CS::CK, - d: usize, // degree of polynomials - t: usize, // number of polynomials + d: usize, // degree of polynomials + t: usize, // number of polynomials xss: Vec>, // vecs of opening points per polynomial - ) -> TestOpening where + ) -> TestOpening + where R: Rng, F: PrimeField, CS: PCS, { // polynomials - let fs: Vec<_> = (0..t) - .map(|_| Poly::::rand(d, rng)) - .collect(); + let fs: Vec<_> = (0..t).map(|_| Poly::::rand(d, rng)).collect(); // commitments - let fcs: Vec<_> = fs.iter() - .map(|fi| CS::commit(&ck, fi)) - .collect(); + let fcs: Vec<_> = fs.iter().map(|fi| CS::commit(&ck, fi)).collect(); // evaluations per polynomial - let yss: Vec<_> = fs.iter() + let yss: Vec<_> = fs + .iter() .zip(xss.iter()) - .map(|(f, xs)| - xs.iter().map( - |x| f.evaluate(x)) - .collect::>() - ).collect(); + .map(|(f, xs)| xs.iter().map(|x| f.evaluate(x)).collect::>()) + .collect(); TestOpening { fs, fcs, xss, yss } } @@ -127,15 +139,25 @@ pub(crate) mod tests { let xss = random_xss(rng, t, max_m); let opening = random_opening::<_, _, CS>(rng, ¶ms.ck(), d, t, xss); - let sets_of_xss: Vec> = opening.xss.iter() + let sets_of_xss: Vec> = opening + .xss + .iter() .map(|xs| BTreeSet::from_iter(xs.iter().cloned())) .collect(); let transcript = &mut (F::rand(rng), F::rand(rng)); - let proof = Shplonk::::open_many(¶ms.ck(), &opening.fs, &sets_of_xss, transcript); - - assert!(Shplonk::::verify_many(¶ms.vk(), &opening.fcs, proof, &opening.xss, &opening.yss, transcript)) + let proof = + Shplonk::::open_many(¶ms.ck(), &opening.fs, &sets_of_xss, transcript); + + assert!(Shplonk::::verify_many( + ¶ms.vk(), + &opening.fcs, + proof, + &opening.xss, + &opening.yss, + transcript + )) } #[test] @@ -143,4 +165,4 @@ pub(crate) mod tests { _test_shplonk::(); _test_shplonk::(); } -} \ No newline at end of file +} diff --git a/src/utils/ec.rs b/src/utils/ec.rs index 7edcee8..4403152 100644 --- a/src/utils/ec.rs +++ b/src/utils/ec.rs @@ -1,9 +1,13 @@ -use ark_ec::{AffineRepr, CurveGroup, AdditiveGroup}; +use ark_ec::{AdditiveGroup, AffineRepr, CurveGroup}; use ark_ff::{BigInteger, PrimeField, Zero}; use ark_std::vec::Vec; pub fn naive_multiexp_affine(coeffs: &[G::ScalarField], bases: &[G]) -> G::Group { - bases.iter().zip(coeffs.iter()).map(|(b, &c)| b.mul(c)).sum() + bases + .iter() + .zip(coeffs.iter()) + .map(|(b, &c)| b.mul(c)) + .sum() } /// Performs a small multi-exponentiation operation. @@ -11,7 +15,10 @@ pub fn naive_multiexp_affine(coeffs: &[G::ScalarField], bases: &[ // adopted from https://github.com/zcash/halo2/pull/20 pub fn small_multiexp_affine(coeffs: &[G::ScalarField], bases: &[G]) -> G::Group { let bytes_in_repr = ::BigInt::NUM_LIMBS * 8; - let coeffs: Vec<_> = coeffs.iter().map(|c| c.into_bigint().to_bytes_le()).collect(); + let coeffs: Vec<_> = coeffs + .iter() + .map(|c| c.into_bigint().to_bytes_le()) + .collect(); let mut acc = G::Group::zero(); @@ -40,7 +47,10 @@ pub fn small_multiexp_proj(coeffs: &[G::ScalarField], bases: &[G] pub fn _small_multiexp_proj_2(coeffs: &[G::ScalarField], bases: &[G]) -> G { let bytes_in_repr = ::BigInt::NUM_LIMBS * 8; - let coeffs: Vec<_> = coeffs.iter().map(|c| c.into_bigint().to_bytes_le()).collect(); + let coeffs: Vec<_> = coeffs + .iter() + .map(|c| c.into_bigint().to_bytes_le()) + .collect(); let mut acc = G::zero(); @@ -60,4 +70,4 @@ pub fn _small_multiexp_proj_2(coeffs: &[G::ScalarField], bases: & } acc -} \ No newline at end of file +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 16e78db..327deae 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,16 +4,18 @@ use ark_ff::Field; pub mod ec; pub mod poly; - -pub fn powers(base: F) -> impl Iterator { +pub fn powers(base: F) -> impl Iterator { ark_std::iter::successors(Some(F::one()), move |power| Some(base * power)) } - - pub fn curve_name() -> &'static str { // ark_ec::models::bw6::BW6 let full_name = ark_std::any::type_name::(); - full_name.split_once("<").unwrap().1 - .split_once(":").unwrap().0 -} \ No newline at end of file + full_name + .split_once("<") + .unwrap() + .1 + .split_once(":") + .unwrap() + .0 +} diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 9a616cf..2a58d4d 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -1,38 +1,32 @@ use ark_ff::{FftField, Field, PrimeField, Zero}; -use ark_poly::{DenseUVPolynomial, Polynomial}; use ark_poly::polynomial::univariate::DensePolynomial; +use ark_poly::{DenseUVPolynomial, Polynomial}; use ark_std::{vec, vec::Vec}; -use crate::Poly; use crate::utils::powers; +use crate::Poly; /// Field element represented as a constant polynomial. pub(crate) fn constant(c: F) -> Poly { Poly::from_coefficients_vec(vec![c]) } - /// The vanishing polynomial of a point x. /// z(X) = X - x pub(crate) fn z_of_point(x: &F) -> Poly { Poly::from_coefficients_vec(vec![x.neg(), F::one()]) } - /// The vanishing polynomial of a set. /// z(X) = (X - x1) * .. * (X - xn) -pub(crate) fn z_of_set<'a, F: FftField>(xs: impl IntoIterator) -> DensePolynomial { +pub(crate) fn z_of_set<'a, F: FftField>(xs: impl IntoIterator) -> DensePolynomial { xs.into_iter() .map(|x| z_of_point(x)) .reduce(|a, b| &a * &b) .unwrap() } - -pub fn sum_with_coeffs>( - coeffs: Vec, - polys: &[P], -) -> P { +pub fn sum_with_coeffs>(coeffs: Vec, polys: &[P]) -> P { assert_eq!(coeffs.len(), polys.len()); let mut res = P::zero(); for (c, p) in coeffs.into_iter().zip(polys.iter()) { @@ -41,16 +35,11 @@ pub fn sum_with_coeffs>( res } - -pub fn sum_with_powers>( - r: F, - polys: &[P], -) -> P { +pub fn sum_with_powers>(r: F, polys: &[P]) -> P { let powers = powers(r).take(polys.len()).collect::>(); sum_with_coeffs(powers, polys) } - pub fn interpolate(xs: &[F], ys: &[F]) -> Poly { let x1 = xs[0]; let mut l = z_of_point(&x1); @@ -83,7 +72,6 @@ pub fn interpolate(xs: &[F], ys: &[F]) -> Poly { res } - /// Given a polynomial `r` in evaluation form {(xi, yi)}, /// i.e. lowest degree `r` such that `r(xi) = yi` for all `i`s, /// and a point zeta, @@ -93,11 +81,14 @@ pub fn interpolate(xs: &[F], ys: &[F]) -> Poly { pub(crate) fn interpolate_evaluate(xs: &[F], ys: &[F], zeta: &F) -> (F, F) { assert_eq!(xs.len(), ys.len()); - let zeta_minus_xs = ark_std::iter::repeat(zeta).zip(xs.iter()) + let zeta_minus_xs = ark_std::iter::repeat(zeta) + .zip(xs.iter()) .map(|(&zeta, xi)| zeta - xi) .collect::>(); - let l_at_zeta = zeta_minus_xs.iter().cloned() + let l_at_zeta = zeta_minus_xs + .iter() + .cloned() .reduce(|acc, item| item * acc) .expect("TODO"); @@ -113,13 +104,19 @@ pub(crate) fn interpolate_evaluate(xs: &[F], ys: &[F], zeta: &F) ws.push(wj); } - let mut denominator = ws.into_iter().zip(zeta_minus_xs.iter()) + let mut denominator = ws + .into_iter() + .zip(zeta_minus_xs.iter()) .map(|(a, b)| a * b) .collect::>(); ark_ff::batch_inversion(&mut denominator); - let sum = denominator.into_iter().zip(ys.iter()).map(|(a, b)| a * b).sum::(); + let sum = denominator + .into_iter() + .zip(ys.iter()) + .map(|(a, b)| a * b) + .sum::(); (sum * l_at_zeta, l_at_zeta) } @@ -146,7 +143,10 @@ mod tests { let poly = interpolate(&xs, &ys); assert_eq!(poly.degree(), d); - assert!(xs.iter().zip(ys.iter()).all(|(x, &y)| poly.evaluate(x) == y)); + assert!(xs + .iter() + .zip(ys.iter()) + .all(|(x, &y)| poly.evaluate(x) == y)); for _ in 0..10 { let zeta = BenchField::rand(rng); diff --git a/tests/plonk/batchy.rs b/tests/plonk/batchy.rs index 69530d2..eee6e04 100644 --- a/tests/plonk/batchy.rs +++ b/tests/plonk/batchy.rs @@ -3,12 +3,12 @@ use std::marker::PhantomData; use ark_ff::{PrimeField, UniformRand}; use ark_poly::{DenseUVPolynomial, Polynomial}; use ark_serialize::*; -use ark_std::{end_timer, start_timer, test_rng}; use ark_std::rand::Rng; +use ark_std::{end_timer, start_timer, test_rng}; -use fflonk::pcs::{Commitment, PCS, PcsParams}; -use fflonk::Poly; +use fflonk::pcs::{Commitment, PcsParams, PCS}; use fflonk::utils::poly; +use fflonk::Poly; use crate::{DecoyPlonk, VanillaPlonkAssignments}; @@ -65,12 +65,22 @@ struct Challenges { impl Challenges { fn new(rng: &mut R) -> Self { - let beta_gamma: (F, F) = (Self::get_128_bit_challenge(rng), Self::get_128_bit_challenge(rng)); + let beta_gamma: (F, F) = ( + Self::get_128_bit_challenge(rng), + Self::get_128_bit_challenge(rng), + ); let alpha: F = Self::get_128_bit_challenge(rng); let zeta: F = Self::get_128_bit_challenge(rng); let one = std::iter::once(F::one()); - let nus = one.chain((1..6).map(|_| Self::get_128_bit_challenge(rng))).collect(); - Self { beta_gamma, alpha, zeta, nus } + let nus = one + .chain((1..6).map(|_| Self::get_128_bit_challenge(rng))) + .collect(); + Self { + beta_gamma, + alpha, + zeta, + nus, + } } fn get_128_bit_challenge(rng: &mut R) -> F { @@ -87,15 +97,20 @@ pub struct PlonkBatchKzgTest> { impl> PlonkBatchKzgTest { fn commit_polynomial(&self, ck: &CS::CK, poly: &Poly) -> CS::C { - let t_commitment = start_timer!(|| format!("Committing to degree {} polynomials", poly.degree())); + let t_commitment = + start_timer!(|| format!("Committing to degree {} polynomials", poly.degree())); let commitment = CS::commit(ck, poly); end_timer!(t_commitment); commitment } fn commit_polynomials(&self, ck: &CS::CK, polys: &[Poly]) -> Vec { - let t_commitment = start_timer!(|| format!("Committing to batch of {} polynomials", polys.len())); - let commitments = polys.iter().map(|p| self.commit_polynomial(ck, p)).collect(); + let t_commitment = + start_timer!(|| format!("Committing to batch of {} polynomials", polys.len())); + let commitments = polys + .iter() + .map(|p| self.commit_polynomial(ck, p)) + .collect(); end_timer!(t_commitment); commitments @@ -116,14 +131,18 @@ pub struct BatchyPlonkProof> { extra: (CS::C, F), // commitment and evaluation of the linearization poly //TODO: remove } - impl> DecoyPlonk for PlonkBatchKzgTest { type Proof = BatchyPlonkProof; fn new(polys: VanillaPlonkAssignments, rng: &mut R) -> Self { let linearization_polynomial = Poly::rand(polys.degree, rng); // TODO: compute from known commitments let challenges = Challenges::new(rng); - Self { polys, linearization_polynomial, challenges, cs: PhantomData } + Self { + polys, + linearization_polynomial, + challenges, + cs: PhantomData, + } } fn setup(&mut self, rng: &mut R) -> (CS::CK, CS::VK) { @@ -137,23 +156,35 @@ impl> DecoyPlonk for PlonkBatchKzgTest { fn prove(&mut self, ck: &CS::CK) -> BatchyPlonkProof { let wire_polynomials_c = self.commit_polynomials(ck, &self.polys.polys_to_commit_1()); - let permutation_polynomial_c = self.commit_polynomial(ck, &self.polys.poly_to_commit_2(self.challenges.beta_gamma)); - let quotient_polynomial_c = self.commit_polynomial(ck, &self.polys.poly_to_commit_3(self.challenges.alpha)); + let permutation_polynomial_c = + self.commit_polynomial(ck, &self.polys.poly_to_commit_2(self.challenges.beta_gamma)); + let quotient_polynomial_c = + self.commit_polynomial(ck, &self.polys.poly_to_commit_3(self.challenges.alpha)); let zeta = self.challenges.zeta; - let evals_at_zeta = self.polys.polys_to_evaluate_at_zeta_4().iter().map(|p| p.evaluate(&zeta)).collect(); + let evals_at_zeta = self + .polys + .polys_to_evaluate_at_zeta_4() + .iter() + .map(|p| p.evaluate(&zeta)) + .collect(); let zeta_omega = zeta * self.polys.omega; - let evals_at_zeta_omega = self.polys.poly_to_evaluate_at_zeta_omega_4().evaluate(&zeta_omega); + let evals_at_zeta_omega = self + .polys + .poly_to_evaluate_at_zeta_omega_4() + .evaluate(&zeta_omega); // TODO: should be computed by verifier from other commitments let linearization_polynomial = self.linearization_polynomial.clone(); let mut polys_to_open_at_zeta = vec![linearization_polynomial.clone()]; polys_to_open_at_zeta.extend_from_slice(&self.polys.polys_to_open_at_zeta_5()); - let agg_poly_at_zeta = poly::sum_with_coeffs(self.challenges.nus.clone(), &polys_to_open_at_zeta); + let agg_poly_at_zeta = + poly::sum_with_coeffs(self.challenges.nus.clone(), &polys_to_open_at_zeta); let proof_at_zeta = CS::open(ck, &agg_poly_at_zeta, zeta); - let proof_at_zeta_omega = CS::open(ck, &self.polys.poly_to_open_at_zeta_omega_5(), zeta_omega); + let proof_at_zeta_omega = + CS::open(ck, &self.polys.poly_to_open_at_zeta_omega_5(), zeta_omega); // TODO: compute let t_extra = start_timer!(|| "Extra: commiting to the linearization polynomial"); @@ -173,10 +204,25 @@ impl> DecoyPlonk for PlonkBatchKzgTest { } } - fn verify(&self, vk: &CS::VK, preprocessed_commitments: Vec, proof: BatchyPlonkProof) -> bool { + fn verify( + &self, + vk: &CS::VK, + preprocessed_commitments: Vec, + proof: BatchyPlonkProof, + ) -> bool { // TODO: - let t_reconstruct = start_timer!(|| "Reconstructing the commitment to the linearization polynomial: 7-multiexp"); - let bases = [&preprocessed_commitments[0..4], &vec![proof.permutation_polynomial_c.clone(), preprocessed_commitments[7].clone(), proof.quotient_polynomial_c]].concat(); + let t_reconstruct = start_timer!(|| { + "Reconstructing the commitment to the linearization polynomial: 7-multiexp" + }); + let bases = [ + &preprocessed_commitments[0..4], + &vec![ + proof.permutation_polynomial_c.clone(), + preprocessed_commitments[7].clone(), + proof.quotient_polynomial_c, + ], + ] + .concat(); assert_eq!(bases.len(), 7); // [q_C]_1 has exp = 1 let coeffs = (0..7).map(|_| F::rand(&mut test_rng())).collect::>(); let _comm = CS::C::combine(&coeffs, &bases); @@ -206,12 +252,14 @@ impl> DecoyPlonk for PlonkBatchKzgTest { let t_kzg_batch_opening = start_timer!(|| "batched KZG openning"); let zeta = self.challenges.zeta; let zeta_omega = zeta * self.polys.omega; - let valid = CS::batch_verify(vk, - vec![agg_comm, proof.permutation_polynomial_c], - vec![zeta, zeta_omega], - vec![agg_eval, proof.evals_at_zeta_omega], - vec![proof.proof_at_zeta, proof.proof_at_zeta_omega], - &mut test_rng()); + let valid = CS::batch_verify( + vk, + vec![agg_comm, proof.permutation_polynomial_c], + vec![zeta, zeta_omega], + vec![agg_eval, proof.evals_at_zeta_omega], + vec![proof.proof_at_zeta, proof.proof_at_zeta_omega], + &mut test_rng(), + ); end_timer!(t_kzg_batch_opening); end_timer!(t_kzg); valid diff --git a/tests/plonk/fflonky.rs b/tests/plonk/fflonky.rs index ee42dc1..915dad3 100644 --- a/tests/plonk/fflonky.rs +++ b/tests/plonk/fflonky.rs @@ -3,15 +3,15 @@ use std::marker::PhantomData; use ark_ff::{PrimeField, UniformRand, Zero}; use ark_poly::Polynomial; use ark_serialize::*; -use ark_std::{end_timer, start_timer}; use ark_std::rand::Rng; use ark_std::test_rng; +use ark_std::{end_timer, start_timer}; -use fflonk::{FflonkyKzg, Poly}; use fflonk::fflonk::Fflonk; -use fflonk::pcs::PCS; use fflonk::pcs::PcsParams; +use fflonk::pcs::PCS; use fflonk::shplonk::AggregateProof; +use fflonk::{FflonkyKzg, Poly}; use crate::{DecoyPlonk, VanillaPlonkAssignments}; @@ -29,9 +29,18 @@ impl VanillaPlonkAssignments { fs1.push(t0); let fs2 = vec![z, t1, t2, Poly::zero()]; //TODO: zero is not strictly necessary vec![ - Combination { fs: fs0, roots_of_xs: vec![zeta] }, - Combination { fs: fs1, roots_of_xs: vec![zeta] }, - Combination { fs: fs2, roots_of_xs: vec![zeta, zeta * omega] }, + Combination { + fs: fs0, + roots_of_xs: vec![zeta], + }, + Combination { + fs: fs1, + roots_of_xs: vec![zeta], + }, + Combination { + fs: fs2, + roots_of_xs: vec![zeta, zeta * omega], + }, ] } } @@ -55,15 +64,17 @@ impl Combination { } fn xs(&self) -> Vec { - self.roots_of_xs.iter() // opening points + self.roots_of_xs + .iter() // opening points .map(|root| root.pow([self.t() as u64])) .collect() } fn yss(&self) -> Vec> { - self.xs().iter().map(|x| - self.fs.iter().map(|f| f.evaluate(x)).collect() - ).collect() + self.xs() + .iter() + .map(|x| self.fs.iter().map(|f| f.evaluate(x)).collect()) + .collect() } } @@ -74,8 +85,14 @@ pub struct PlonkWithFflonkTest> { impl> PlonkWithFflonkTest { fn _commit_proof_polynomials(&self, ck: &CS::CK) -> Vec { - let t_commitment = start_timer!(|| format!("Committing to {} proof polynomials", self.combinations.len() - 1)); - let commitments = self.combinations.iter().enumerate() + let t_commitment = start_timer!(|| format!( + "Committing to {} proof polynomials", + self.combinations.len() - 1 + )); + let commitments = self + .combinations + .iter() + .enumerate() .skip(1) // preprocessing .map(|(i, _)| self._commit_single(i, ck)) .collect(); @@ -87,11 +104,19 @@ impl> PlonkWithFflonkTest { let combination = &self.combinations[i]; let t_commit = start_timer!(|| format!("Committing to combination #{}", i)); - let t_combine = start_timer!(|| format!("combining {} polynomials: t = {}, max_degree = {}", combination.fs.len(), combination.t(), combination.max_degree())); + let t_combine = start_timer!(|| format!( + "combining {} polynomials: t = {}, max_degree = {}", + combination.fs.len(), + combination.t(), + combination.max_degree() + )); let poly = Fflonk::combine(combination.t(), &combination.fs); end_timer!(t_combine); - let t_commit_combined = start_timer!(|| format!("committing to the combined polynomial: degree = {}", poly.degree())); + let t_commit_combined = start_timer!(|| format!( + "committing to the combined polynomial: degree = {}", + poly.degree() + )); let commitment = CS::commit(ck, &poly); end_timer!(t_commit_combined); @@ -100,10 +125,11 @@ impl> PlonkWithFflonkTest { } fn _open(&self, transcript: &mut merlin::Transcript, ck: &CS::CK) -> AggregateProof { - let (ts, (fss, xss)): (Vec<_>, (Vec<_>, Vec<_>)) = - self.combinations.iter() - .map(|c| (c.t(), (c.fs.clone(), c.roots_of_xs.clone()))) - .unzip(); + let (ts, (fss, xss)): (Vec<_>, (Vec<_>, Vec<_>)) = self + .combinations + .iter() + .map(|c| (c.t(), (c.fs.clone(), c.roots_of_xs.clone()))) + .unzip(); let t_open = start_timer!(|| "Opening"); let proof = FflonkyKzg::::open(ck, &fss, &ts, &xss, transcript); @@ -112,8 +138,7 @@ impl> PlonkWithFflonkTest { } fn _evaluate(&self) -> Vec>> { - self.combinations.iter() - .map(|c| c.yss()).collect() + self.combinations.iter().map(|c| c.yss()).collect() } } @@ -135,9 +160,12 @@ impl> DecoyPlonk for PlonkWithFflonkTest } fn setup(&mut self, rng: &mut R) -> (CS::CK, CS::VK) { - let max_degree = self.combinations.iter() + let max_degree = self + .combinations + .iter() .map(|c| c.max_combined_degree()) - .max().unwrap(); + .max() + .unwrap(); let params = CS::setup(max_degree, rng); (params.ck(), params.vk()) } @@ -152,17 +180,35 @@ impl> DecoyPlonk for PlonkWithFflonkTest let commitments = self._commit_proof_polynomials(ck); let cs_proof = self._open(empty_transcript, ck); let evals = self._evaluate(); - FflonkyPlonkProof { cs_proof, evals, commitments } + FflonkyPlonkProof { + cs_proof, + evals, + commitments, + } } - fn verify(&self, vk: &CS::VK, preprocessed_commitments: Vec, proof: FflonkyPlonkProof) -> bool { + fn verify( + &self, + vk: &CS::VK, + preprocessed_commitments: Vec, + proof: FflonkyPlonkProof, + ) -> bool { let empty_transcript = &mut merlin::Transcript::new(b"plonk-fflonk-shplonk-kzg"); - let (ts, xss): (Vec<_>, Vec<_>) = - self.combinations.iter() - .map(|c| (c.t(), c.roots_of_xs.clone())) - .unzip(); + let (ts, xss): (Vec<_>, Vec<_>) = self + .combinations + .iter() + .map(|c| (c.t(), c.roots_of_xs.clone())) + .unzip(); let commitments = [preprocessed_commitments, proof.commitments].concat(); - FflonkyKzg::::verify(vk, &commitments, &ts, proof.cs_proof, &xss, &proof.evals, empty_transcript) + FflonkyKzg::::verify( + vk, + &commitments, + &ts, + proof.cs_proof, + &xss, + &proof.evals, + empty_transcript, + ) } -} \ No newline at end of file +} diff --git a/tests/plonk/main.rs b/tests/plonk/main.rs index e3aa7b1..9ee56a4 100644 --- a/tests/plonk/main.rs +++ b/tests/plonk/main.rs @@ -4,9 +4,9 @@ use ark_poly::DenseUVPolynomial; use ark_poly::EvaluationDomain; use ark_poly::Radix2EvaluationDomain; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress}; -use ark_std::{end_timer, start_timer}; use ark_std::rand::Rng; use ark_std::test_rng; +use ark_std::{end_timer, start_timer}; use fflonk::pcs::kzg::KZG; use fflonk::pcs::PCS; @@ -15,9 +15,8 @@ use fflonk::Poly; use crate::batchy::PlonkBatchKzgTest; use crate::fflonky::PlonkWithFflonkTest; -mod fflonky; mod batchy; - +mod fflonky; struct VanillaPlonkAssignments { degree: usize, @@ -77,7 +76,8 @@ trait DecoyPlonk> { fn setup(&mut self, rng: &mut R) -> (CS::CK, CS::VK); fn preprocess(&mut self, ck: &CS::CK) -> Vec; fn prove(&mut self, ck: &CS::CK) -> Self::Proof; - fn verify(&self, vk: &CS::VK, preprocessed_commitments: Vec, proof: Self::Proof) -> bool; + fn verify(&self, vk: &CS::VK, preprocessed_commitments: Vec, proof: Self::Proof) + -> bool; } fn _test_vanilla_plonk_opening, T: DecoyPlonk>(log_n: usize) { @@ -87,7 +87,11 @@ fn _test_vanilla_plonk_opening, T: DecoyPlonk>( let mut test = T::new(polys, rng); - let t_test = start_timer!(|| format!("domain_size = {}, curve = {}", n, fflonk::utils::curve_name::())); + let t_test = start_timer!(|| format!( + "domain_size = {}, curve = {}", + n, + fflonk::utils::curve_name::() + )); let t_setup = start_timer!(|| "Setup"); let (ck, vk) = test.setup(rng); @@ -105,7 +109,9 @@ fn _test_vanilla_plonk_opening, T: DecoyPlonk>( let proof_size = proof.serialized_size(Compress::Yes); let mut serialized_proof = vec![0; proof_size]; - proof.serialize_compressed(&mut serialized_proof[..]).unwrap(); + proof + .serialize_compressed(&mut serialized_proof[..]) + .unwrap(); let proof = T::Proof::deserialize_compressed(&serialized_proof[..]).unwrap(); let t_verify = start_timer!(|| "Verifying"); @@ -114,7 +120,10 @@ fn _test_vanilla_plonk_opening, T: DecoyPlonk>( end_timer!(t_test); - println!("proof size = {}, preprocessed data size = {}", proof_size, preprocessed_size); + println!( + "proof size = {}, preprocessed data size = {}", + proof_size, preprocessed_size + ); assert!(valid); }