Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for cq static lookups #1

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8d29a68
batch pairing
therealyingtong May 22, 2023
82e4304
Remove CommitmentScheme generic from Verifier and VerificationStrategy
therealyingtong May 25, 2023
280fc91
Test merge_into_pairing_batcher
therealyingtong May 26, 2023
d79e686
Remove CommitmentScheme generic from Prover
therealyingtong May 30, 2023
28bbb42
Add e2e test
therealyingtong May 30, 2023
5619589
Introduce MultiMillerLoop bound in ProvingKey, VerifyingKey
therealyingtong May 30, 2023
6de5135
Introduce plonk::static_lookup
therealyingtong May 30, 2023
33c5fbd
Introduce Assignment::register_static_table<E: MultiMillerLoop>
therealyingtong May 30, 2023
c6e30ba
Introduce Layouter::register_static_table
therealyingtong May 31, 2023
d51397c
Working my_test
therealyingtong Jun 5, 2023
5fba685
Integrate prover and verifier
therealyingtong Jun 5, 2023
b27bfed
Generic size KZG setup; value_index_mapping in StaticTableValues
therealyingtong Jun 6, 2023
e6a9e1a
Integrate static lookups into IOP
therealyingtong Jun 6, 2023
5188bff
WIP working example; blinding for advice columns not working
therealyingtong Jun 6, 2023
7a78064
Introduce SRS, ParamsCQ structs
therealyingtong Jun 7, 2023
ea158fa
Working test
therealyingtong Jun 13, 2023
3e212f3
Sumcheck identity
therealyingtong Jun 19, 2023
7179ba3
b_poly check
therealyingtong Jun 19, 2023
2799aad
SRS for multiple table sizes
therealyingtong Jun 19, 2023
ae189e4
Prover vector lookup
therealyingtong Jun 19, 2023
e1c5a4d
Remove values from StaticTableValues
therealyingtong Jun 29, 2023
c34cb47
static_lookup: Do not assume tables have unique values
therealyingtong Oct 27, 2023
028f6e5
tests::static_lookup: fix e2e test
therealyingtong Oct 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions arithmetic/curves/src/batch_pairing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
use group::{Curve, GroupEncoding};
use std::collections::HashMap;

use crate::pairing::{Engine, MultiMillerLoop};

/// Dynamically batches tuples of points and returns output compatible with MultiMillerLoop
pub struct PairingBatcher<E: MultiMillerLoop> {
/// Mapping of g2 repr to overcome trait bounds
g2_to_g2: HashMap<Vec<u8>, E::G2>,
/// Mapping of all G2 points serialized with correlated G1 points
g2_to_g1: HashMap<Vec<u8>, E::G1>,
/// challenge
challenge: E::Scalar,
/// running challenge
running_challenge: E::Scalar,
/// is finalized
finalized: bool,
}

impl<E: MultiMillerLoop> PairingBatcher<E> {
pub fn new(challenge: E::Scalar) -> Self {
Self {
g2_to_g2: HashMap::default(),
g2_to_g1: HashMap::default(),
challenge,
running_challenge: E::Scalar::from(1),
finalized: false,
}
}

/// Adds new pairing equation that needs to be checked
pub fn add_pairing(&mut self, pairs: &[(E::G1Affine, E::G2Affine)]) {
let g2_reprs: Vec<_> = pairs
.iter()
.map(|&(_, g2)| g2.to_bytes().as_ref().to_vec())
.collect();

// For each g2 point
let mut is_present: bool = false;
for repr in g2_reprs.iter() {
if self.g2_to_g1.get(repr).is_some() {
is_present = true;
break;
}
}

let g2_points: Vec<E::G2> = pairs.iter().map(|&(_, g2)| g2.into()).collect();
let g1_points: Vec<E::G1> = if is_present {
let running_challenge = self.running_challenge * self.challenge;
self.running_challenge = running_challenge;
pairs
.iter()
.map(|&(g1, _)| g1 * running_challenge)
.collect()
} else {
pairs.iter().map(|pair| pair.0.into()).collect()
};

self.update_mapping(&g2_reprs, &g1_points, &g2_points);
}

fn update_mapping(&mut self, g2_reprs: &[Vec<u8>], g1_points: &[E::G1], g2_points: &[E::G2]) {
assert_eq!(g1_points.len(), g2_reprs.len());
assert_eq!(g2_points.len(), g2_reprs.len());

g2_reprs
.iter()
.zip(g1_points.iter())
.zip(g2_points.iter())
.for_each(|((g2_repr, g1), g2)| {
self.g2_to_g1
.entry(g2_repr.to_vec())
.and_modify(|g1_point: &mut <E as Engine>::G1| *g1_point += g1)
.or_insert(*g1);
self.g2_to_g2.insert(g2_repr.to_vec(), *g2);
});
}

/// Returns output ready for MultiMillerLoop
pub fn finalize(mut self) -> Vec<(E::G1Affine, E::G2Prepared)> {
if self.finalized {
panic!("Batcher is already consumed!");
}
self.finalized = true;
let g2_map = self.g2_to_g2.clone();
self.g2_to_g1
.iter()
.map(|(g2_repr, g1)| {
let g2 = g2_map.get(g2_repr).unwrap().to_affine();
let g2_prepared: E::G2Prepared = g2.into();
(g1.to_affine(), g2_prepared)
})
.collect()
}
}

#[cfg(test)]
mod tests {
use ff::Field;
use rand_core::OsRng;

use super::*;
use crate::{
bn256::{Bn256, Fr, G1Affine, G2Affine, G2Prepared, Gt, G1, G2},
pairing::MillerLoopResult,
};

#[test]
fn test_bn256_batch_pairing() {
/*
e(a, b) = e(c, d)
e(j, b) = e(f, g)
e(e, d) = e(h, b)
*/

let a = Fr::random(OsRng);
let b = Fr::random(OsRng);
let c = Fr::random(OsRng);
let d = a * b * c.invert().unwrap();
let f = Fr::random(OsRng);
let j = Fr::random(OsRng);
let g = j * b * f.invert().unwrap();
let e = Fr::random(OsRng);
let h = e * d * b.invert().unwrap();

let a: G1Affine = (G1::generator() * a).into();
let b: G2Affine = (G2::generator() * b).to_affine();
let c: G1Affine = (G1::generator() * c).into();
let d: G2Affine = (G2::generator() * d).to_affine();
let j: G1Affine = (G1::generator() * j).into();
let f: G1Affine = (G1::generator() * f).into();
let g: G2Affine = (G2::generator() * g).to_affine();
let e: G1Affine = (G1::generator() * e).into();
let h: G1Affine = (G1::generator() * h).into();

// Manual Miller loop
{
let b: G2Prepared = b.into();
let d: G2Prepared = d.into();
let g: G2Prepared = g.into();

let result: Gt = {
Bn256::multi_miller_loop(&[
(&a, &b),
(&(-c), &d),
(&j, &b),
(&(-f), &g),
(&e, &d),
(&(-h), &b),
])
};

let pairing_result = result.final_exponentiation();
assert_eq!(pairing_result, Gt::identity());
}

{
// Batched test
let mut pairing_batcher = PairingBatcher::<Bn256>::new(Fr::random(OsRng));

pairing_batcher.add_pairing(&[(a, b), ((-c), d)]);
pairing_batcher.add_pairing(&[(j, b), ((-f), g)]);
pairing_batcher.add_pairing(&[(e, d), ((-h), b)]);

let batched_tuples = pairing_batcher.finalize();
let result: Gt = Bn256::multi_miller_loop(
&batched_tuples
.iter()
.map(|(g1, g2)| (g1, g2))
.collect::<Vec<_>>(),
);

let pairing_result = result.final_exponentiation();
assert_eq!(pairing_result, Gt::identity());

/*
e(a, b) = e(c, d)
e(j, b) = e(f, g)
e(e, d) = e(h, b)

==>

e(a + [R]j + [R^2]h, b).e(c + [R^2]e, d).e([R]f, g)
*/
assert_eq!(3, batched_tuples.len());
}
}
}
1 change: 1 addition & 0 deletions arithmetic/curves/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

mod arithmetic;

pub mod batch_pairing;
pub mod bn256;
pub mod pairing;
pub mod pasta;
Expand Down
6 changes: 4 additions & 2 deletions arithmetic/curves/src/pairing.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::{CurveAffine, FieldExt, Group as _Group};
use crate::{serde::SerdeObject, CurveAffine, FieldExt, Group as _Group};
use core::ops::Mul;
use group::{
prime::PrimeCurve, Group, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned,
UncompressedEncoding,
};
use std::fmt::Debug;

pub trait Engine: Sized + 'static + Clone {
/// This is the scalar field of the engine's groups.
Expand Down Expand Up @@ -34,7 +35,8 @@ pub trait Engine: Sized + 'static + Clone {
+ GroupOps<Self::G2Affine>
+ GroupOpsOwned<Self::G2Affine>
+ ScalarMul<Self::Scalar>
+ ScalarMulOwned<Self::Scalar>;
+ ScalarMulOwned<Self::Scalar>
+ _Group<Scalar = Self::Scalar>;

/// The affine representation of an element in G2.
type G2Affine: PairingCurveAffine<
Expand Down
3 changes: 3 additions & 0 deletions halo2_proofs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ criterion = "0.3"
gumdrop = "0.8"
proptest = "1"
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
rand = "0.8"
rand_chacha = "0.3.1"
lazy_static = { version = "1.4.0"}

[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies]
getrandom = { version = "0.2", features = ["js"] }
Expand Down
4 changes: 2 additions & 2 deletions halo2_proofs/examples/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl Circuit<Fr> for StandardPlonk {
fn main() {
let k = 4;
let circuit = StandardPlonk(Fr::random(OsRng));
let params = ParamsKZG::<Bn256>::setup(k, OsRng);
let params = ParamsKZG::<Bn256>::setup((1 << k) - 1, 0, OsRng);
let vk = keygen_vk(&params, &circuit).expect("vk should not fail");
let pk = keygen_pk(&params, vk, &circuit).expect("pk should not fail");

Expand Down Expand Up @@ -168,7 +168,7 @@ fn main() {
let strategy = SingleStrategy::new(&params);
let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
assert!(verify_proof::<
KZGCommitmentScheme<Bn256>,
Bn256,
VerifierGWC<'_, Bn256>,
Challenge255<G1Affine>,
Blake2bRead<&[u8], G1Affine, Challenge255<G1Affine>>,
Expand Down
Loading