diff --git a/Cargo.toml b/Cargo.toml index eaea3b94..180136fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,60 +1,4 @@ -[package] -name = "plonk_verifier" -version = "0.1.0" -edition = "2021" - -[dependencies] -itertools = "0.10.3" -lazy_static = "1.4.0" -num-bigint = "0.4.3" -num-integer = "0.1.45" -num-traits = "0.2.15" -rand = "0.8" -hex = "0.4" -halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } - -# parallel -rayon = { version = "1.5.3", optional = true } - -# system_halo2 -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } - -# loader_evm -sha3 = { version = "0.10", optional = true } -bytes = { version = "1.1.0", default-features = false, optional = true } -primitive-types = { version = "0.12.1", default-features = false, features = ["std"], optional = true } -rlp = { version = "0.5.2", default-features = false, features = ["std"], optional = true } -revm = { version = "= 2.3.1", optional = true } - -# loader_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } -poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } - -[dev-dependencies] -rand_chacha = "0.3.1" -paste = "1.0.7" - -# system_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc" } - -# loader_evm -crossterm = { version = "0.25" } -tui = { version = "0.19", default-features = false, features = ["crossterm"] } - -[features] -default = ["loader_evm", "loader_halo2", "system_halo2"] - -parallel = ["dep:rayon"] - -loader_evm = ["dep:bytes", "dep:sha3", "dep:primitive-types", "dep:rlp", "dep:revm"] -loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] - -system_halo2 = ["dep:halo2_proofs"] - -[[example]] -name = "evm-verifier" -required-features = ["loader_evm", "system_halo2"] - -[[example]] -name = "evm-verifier-with-accumulator" -required-features = ["loader_halo2", "loader_evm", "system_halo2"] +[workspace] +members = [ + "snark-verifier", +] diff --git a/README.md b/README.md index bcd16c74..db401c9f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# PLONK Verifier +# SNARK Verifier -Generic PLONK verifier. +Generic (S)NARK verifier. diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml new file mode 100644 index 00000000..0d32d22f --- /dev/null +++ b/snark-verifier/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "snark-verifier" +version = "0.1.0" +edition = "2021" + +[dependencies] +itertools = "0.10.3" +lazy_static = "1.4.0" +num-bigint = "0.4.3" +num-integer = "0.1.45" +num-traits = "0.2.15" +rand = "0.8" +hex = "0.4" +halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } + +# parallel +rayon = { version = "1.5.3", optional = true } + +# system_halo2 +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } + +# loader_evm +sha3 = { version = "0.10", optional = true } +bytes = { version = "1.1.0", default-features = false, optional = true } +primitive-types = { version = "0.12.1", default-features = false, features = ["std"], optional = true } +rlp = { version = "0.5.2", default-features = false, features = ["std"], optional = true } +revm = { version = "= 2.3.1", optional = true } + +# loader_halo2 +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } +poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } + +[dev-dependencies] +rand_chacha = "0.3.1" +paste = "1.0.7" + +# system_halo2 +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc" } + +# loader_evm +crossterm = { version = "0.25" } +tui = { version = "0.19", default-features = false, features = ["crossterm"] } + +[features] +default = ["loader_evm", "loader_halo2", "system_halo2"] + +parallel = ["dep:rayon"] + +loader_evm = ["dep:bytes", "dep:sha3", "dep:primitive-types", "dep:rlp", "dep:revm"] +loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] + +system_halo2 = ["dep:halo2_proofs"] + +[[example]] +name = "evm-verifier" +required-features = ["loader_evm", "system_halo2"] + +[[example]] +name = "evm-verifier-with-accumulator" +required-features = ["loader_halo2", "loader_evm", "system_halo2"] diff --git a/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs similarity index 92% rename from examples/evm-verifier-with-accumulator.rs rename to snark-verifier/examples/evm-verifier-with-accumulator.rs index 95d0f69a..ba23e352 100644 --- a/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -14,24 +14,24 @@ use halo2_proofs::{ transcript::{EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer}, }; use itertools::Itertools; -use plonk_verifier::{ +use rand::rngs::OsRng; +use snark_verifier::{ loader::{ evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, native::NativeLoader, }, - pcs::kzg::{Gwc19, Kzg, KzgAs, LimbsEncoding}, + pcs::kzg::{Gwc19, KzgAs, LimbsEncoding}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, - verifier::{self, PlonkVerifier}, + verifier::{self, SnarkVerifier}, }; -use rand::rngs::OsRng; use std::{io::Cursor, rc::Rc}; const LIMBS: usize = 4; const BITS: usize = 68; -type Pcs = Kzg; -type As = KzgAs; -type Plonk = verifier::Plonk>; +type As = KzgAs; +type PlonkSuccinctVerifier = verifier::plonk::PlonkSuccinctVerifier>; +type PlonkVerifier = verifier::plonk::PlonkVerifier>; mod application { use halo2_curves::bn256::Fr; @@ -161,7 +161,7 @@ mod application { } mod aggregation { - use super::{As, Plonk, BITS, LIMBS}; + use super::{As, PlonkSuccinctVerifier, BITS, LIMBS}; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -177,7 +177,8 @@ mod aggregation { EccConfig, }; use itertools::Itertools; - use plonk_verifier::{ + use rand::rngs::OsRng; + use snark_verifier::{ loader::{self, native::NativeLoader}, pcs::{ kzg::{KzgAccumulator, KzgSuccinctVerifyingKey, LimbsEncodingInstructions}, @@ -185,10 +186,8 @@ mod aggregation { }, system, util::arithmetic::{fe_to_limbs, FieldExt}, - verifier::PlonkVerifier, - Protocol, + verifier::{plonk::PlonkProtocol, SnarkVerifier}, }; - use rand::rngs::OsRng; use std::rc::Rc; const T: usize = 5; @@ -203,13 +202,17 @@ mod aggregation { system::halo2::transcript::halo2::PoseidonTranscript; pub struct Snark { - protocol: Protocol, + protocol: PlonkProtocol, instances: Vec>, proof: Vec, } impl Snark { - pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { + pub fn new( + protocol: PlonkProtocol, + instances: Vec>, + proof: Vec, + ) -> Self { Self { protocol, instances, @@ -234,7 +237,7 @@ mod aggregation { #[derive(Clone)] pub struct SnarkWitness { - protocol: Protocol, + protocol: PlonkProtocol, instances: Vec>>, proof: Value>, } @@ -282,8 +285,10 @@ mod aggregation { let instances = assign_instances(&snark.instances); let mut transcript = PoseidonTranscript::, _>::new(loader, snark.proof()); - let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &protocol, &instances, &proof).unwrap() + let proof = + PlonkSuccinctVerifier::read_proof(svk, &protocol, &instances, &mut transcript) + .unwrap(); + PlonkSuccinctVerifier::verify(svk, &protocol, &instances, &proof).unwrap() }) .collect_vec(); @@ -352,10 +357,15 @@ mod aggregation { .flat_map(|snark| { let mut transcript = PoseidonTranscript::::new(snark.proof.as_slice()); - let proof = - Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript) - .unwrap(); - Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof).unwrap() + let proof = PlonkSuccinctVerifier::read_proof( + &svk, + &snark.protocol, + &snark.instances, + &mut transcript, + ) + .unwrap(); + PlonkSuccinctVerifier::verify(&svk, &snark.protocol, &snark.instances, &proof) + .unwrap() }) .collect_vec(); @@ -551,8 +561,6 @@ fn gen_aggregation_evm_verifier( num_instance: Vec, accumulator_indices: Vec<(usize, usize)>, ) -> Vec { - let svk = params.get_g()[0].into(); - let dk = (params.g2(), params.s_g2()).into(); let protocol = compile( params, vk, @@ -560,14 +568,15 @@ fn gen_aggregation_evm_verifier( .with_num_instance(num_instance.clone()) .with_accumulator_indices(Some(accumulator_indices)), ); + let vk = (params.get_g()[0], params.g2(), params.s_g2()).into(); let loader = EvmLoader::new::(); let protocol = protocol.loaded(&loader); let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances(num_instance); - let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + let proof = PlonkVerifier::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); + PlonkVerifier::verify(&vk, &protocol, &instances, &proof).unwrap(); evm::compile_yul(&loader.yul_code()) } diff --git a/examples/evm-verifier.rs b/snark-verifier/examples/evm-verifier.rs similarity index 94% rename from examples/evm-verifier.rs rename to snark-verifier/examples/evm-verifier.rs index a85665a8..58b08074 100644 --- a/examples/evm-verifier.rs +++ b/snark-verifier/examples/evm-verifier.rs @@ -18,16 +18,16 @@ use halo2_proofs::{ transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, }; use itertools::Itertools; -use plonk_verifier::{ +use rand::{rngs::OsRng, RngCore}; +use snark_verifier::{ loader::evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, - pcs::kzg::{Gwc19, Kzg}, + pcs::kzg::{Gwc19, KzgAs}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, - verifier::{self, PlonkVerifier}, + verifier::{self, SnarkVerifier}, }; -use rand::{rngs::OsRng, RngCore}; use std::rc::Rc; -type Plonk = verifier::Plonk>; +type PlonkVerifier = verifier::plonk::PlonkVerifier>; #[derive(Clone, Copy)] struct StandardPlonkConfig { @@ -205,21 +205,20 @@ fn gen_evm_verifier( vk: &VerifyingKey, num_instance: Vec, ) -> Vec { - let svk = params.get_g()[0].into(); - let dk = (params.g2(), params.s_g2()).into(); let protocol = compile( params, vk, Config::kzg().with_num_instance(num_instance.clone()), ); + let vk = (params.get_g()[0], params.g2(), params.s_g2()).into(); let loader = EvmLoader::new::(); let protocol = protocol.loaded(&loader); let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances(num_instance); - let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + let proof = PlonkVerifier::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); + PlonkVerifier::verify(&vk, &protocol, &instances, &proof).unwrap(); evm::compile_yul(&loader.yul_code()) } diff --git a/snark-verifier/src/cost.rs b/snark-verifier/src/cost.rs new file mode 100644 index 00000000..a85d6af4 --- /dev/null +++ b/snark-verifier/src/cost.rs @@ -0,0 +1,29 @@ +use std::ops::Add; + +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct Cost { + pub num_instance: usize, + pub num_commitment: usize, + pub num_evaluation: usize, + pub num_msm: usize, + pub num_pairing: usize, +} + +impl Add for Cost { + type Output = Cost; + + fn add(mut self, rhs: Cost) -> Self::Output { + self.num_instance += rhs.num_instance; + self.num_commitment += rhs.num_commitment; + self.num_evaluation += rhs.num_evaluation; + self.num_msm += rhs.num_msm; + self.num_pairing += rhs.num_pairing; + self + } +} + +pub trait CostEstimation { + type Input; + + fn estimate_cost(input: &Self::Input) -> Cost; +} diff --git a/snark-verifier/src/lib.rs b/snark-verifier/src/lib.rs new file mode 100644 index 00000000..c2b9350a --- /dev/null +++ b/snark-verifier/src/lib.rs @@ -0,0 +1,18 @@ +#![allow(clippy::type_complexity)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::upper_case_acronyms)] + +pub mod cost; +pub mod loader; +pub mod pcs; +pub mod system; +pub mod util; +pub mod verifier; + +#[derive(Clone, Debug)] +pub enum Error { + InvalidInstances, + InvalidProtocol(String), + AssertionFailure(String), + Transcript(std::io::ErrorKind, String), +} diff --git a/src/loader.rs b/snark-verifier/src/loader.rs similarity index 100% rename from src/loader.rs rename to snark-verifier/src/loader.rs diff --git a/src/loader/evm.rs b/snark-verifier/src/loader/evm.rs similarity index 100% rename from src/loader/evm.rs rename to snark-verifier/src/loader/evm.rs diff --git a/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs similarity index 100% rename from src/loader/evm/code.rs rename to snark-verifier/src/loader/evm/code.rs diff --git a/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs similarity index 100% rename from src/loader/evm/loader.rs rename to snark-verifier/src/loader/evm/loader.rs diff --git a/src/loader/evm/test.rs b/snark-verifier/src/loader/evm/test.rs similarity index 100% rename from src/loader/evm/test.rs rename to snark-verifier/src/loader/evm/test.rs diff --git a/src/loader/evm/test/tui.rs b/snark-verifier/src/loader/evm/test/tui.rs similarity index 100% rename from src/loader/evm/test/tui.rs rename to snark-verifier/src/loader/evm/test/tui.rs diff --git a/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs similarity index 97% rename from src/loader/evm/util.rs rename to snark-verifier/src/loader/evm/util.rs index 16eaa08d..2c74731a 100644 --- a/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -95,7 +95,7 @@ pub fn estimate_gas(cost: Cost) -> usize { let intrinsic_cost = 21000; let calldata_cost = (proof_size as f64 * 15.25).ceil() as usize; - let ec_operation_cost = 113100 + (cost.num_msm - 2) * 6350; + let ec_operation_cost = (45100 + cost.num_pairing * 34000) + (cost.num_msm - 2) * 6350; intrinsic_cost + calldata_cost + ec_operation_cost } diff --git a/src/loader/evm/util/executor.rs b/snark-verifier/src/loader/evm/util/executor.rs similarity index 100% rename from src/loader/evm/util/executor.rs rename to snark-verifier/src/loader/evm/util/executor.rs diff --git a/snark-verifier/src/loader/halo2.rs b/snark-verifier/src/loader/halo2.rs new file mode 100644 index 00000000..ce75b00c --- /dev/null +++ b/snark-verifier/src/loader/halo2.rs @@ -0,0 +1,29 @@ +pub(crate) mod loader; +mod shim; + +#[cfg(test)] +pub(crate) mod test; + +pub use loader::{EcPoint, Halo2Loader, Scalar}; +pub use shim::{Context, EccInstructions, IntegerInstructions}; +pub use util::Valuetools; + +pub use halo2_wrong_ecc; + +mod util { + use halo2_proofs::circuit::Value; + + pub trait Valuetools: Iterator> { + fn fold_zipped(self, init: B, mut f: F) -> Value + where + Self: Sized, + F: FnMut(B, V) -> B, + { + self.fold(Value::known(init), |acc, value| { + acc.zip(value).map(|(acc, value)| f(acc, value)) + }) + } + } + + impl>> Valuetools for I {} +} diff --git a/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs similarity index 100% rename from src/loader/halo2/loader.rs rename to snark-verifier/src/loader/halo2/loader.rs diff --git a/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs similarity index 100% rename from src/loader/halo2/shim.rs rename to snark-verifier/src/loader/halo2/shim.rs diff --git a/src/loader/halo2/test.rs b/snark-verifier/src/loader/halo2/test.rs similarity index 85% rename from src/loader/halo2/test.rs rename to snark-verifier/src/loader/halo2/test.rs index dd2fccaa..2de9d287 100644 --- a/src/loader/halo2/test.rs +++ b/snark-verifier/src/loader/halo2/test.rs @@ -1,18 +1,18 @@ use crate::{ util::{arithmetic::CurveAffine, Itertools}, - Protocol, + verifier::plonk::PlonkProtocol, }; use halo2_proofs::circuit::Value; #[derive(Clone, Debug)] pub struct Snark { - pub protocol: Protocol, + pub protocol: PlonkProtocol, pub instances: Vec>, pub proof: Vec, } impl Snark { - pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { + pub fn new(protocol: PlonkProtocol, instances: Vec>, proof: Vec) -> Self { assert_eq!( protocol.num_instance, instances @@ -30,7 +30,7 @@ impl Snark { #[derive(Clone, Debug)] pub struct SnarkWitness { - pub protocol: Protocol, + pub protocol: PlonkProtocol, pub instances: Vec>>, pub proof: Value>, } @@ -50,7 +50,7 @@ impl From> for SnarkWitness { } impl SnarkWitness { - pub fn new_without_witness(protocol: Protocol) -> Self { + pub fn new_without_witness(protocol: PlonkProtocol) -> Self { let instances = protocol .num_instance .iter() diff --git a/src/loader/native.rs b/snark-verifier/src/loader/native.rs similarity index 100% rename from src/loader/native.rs rename to snark-verifier/src/loader/native.rs diff --git a/src/pcs.rs b/snark-verifier/src/pcs.rs similarity index 62% rename from src/pcs.rs rename to snark-verifier/src/pcs.rs index bf944a43..45444a07 100644 --- a/src/pcs.rs +++ b/snark-verifier/src/pcs.rs @@ -8,19 +8,11 @@ use crate::{ Error, }; use rand::Rng; -use std::fmt::Debug; +use std::{fmt::Debug, marker::PhantomData}; pub mod ipa; pub mod kzg; -pub trait PolynomialCommitmentScheme: Clone + Debug -where - C: CurveAffine, - L: Loader, -{ - type Accumulator: Clone + Debug; -} - #[derive(Clone, Debug)] pub struct Query { pub poly: usize, @@ -38,56 +30,44 @@ impl Query { } } -pub trait MultiOpenScheme: PolynomialCommitmentScheme +pub trait PolynomialCommitmentScheme: Clone + Debug where C: CurveAffine, L: Loader, { - type SuccinctVerifyingKey: Clone + Debug; + type VerifyingKey: Clone + Debug; type Proof: Clone + Debug; + type Output: Clone + Debug; fn read_proof( - svk: &Self::SuccinctVerifyingKey, + vk: &Self::VerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result where T: TranscriptRead; - fn succinct_verify( - svk: &Self::SuccinctVerifyingKey, + fn verify( + vk: &Self::VerifyingKey, commitments: &[Msm], point: &L::LoadedScalar, queries: &[Query], proof: &Self::Proof, - ) -> Result; + ) -> Result; } -pub trait Decider: PolynomialCommitmentScheme +pub trait AccumulationScheme where C: CurveAffine, L: Loader, { - type DecidingKey: Clone + Debug; - type Output: Clone + Debug; - - fn decide(dk: &Self::DecidingKey, accumulator: Self::Accumulator) -> Self::Output; - - fn decide_all(dk: &Self::DecidingKey, accumulators: Vec) -> Self::Output; -} - -pub trait AccumulationScheme: Clone + Debug -where - C: CurveAffine, - L: Loader, - PCS: PolynomialCommitmentScheme, -{ + type Accumulator: Clone + Debug; type VerifyingKey: Clone + Debug; type Proof: Clone + Debug; fn read_proof( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, ) -> Result where @@ -95,45 +75,62 @@ where fn verify( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], proof: &Self::Proof, - ) -> Result; + ) -> Result; +} + +pub trait AccumulationDecider: AccumulationScheme +where + C: CurveAffine, + L: Loader, +{ + type DecidingKey: Clone + Debug; + + fn decide(dk: &Self::DecidingKey, accumulator: Self::Accumulator) -> Result<(), Error>; + + fn decide_all( + dk: &Self::DecidingKey, + accumulators: Vec, + ) -> Result<(), Error>; } -pub trait AccumulationSchemeProver: AccumulationScheme +pub trait AccumulationSchemeProver: AccumulationScheme where C: CurveAffine, - PCS: PolynomialCommitmentScheme, { type ProvingKey: Clone + Debug; fn create_proof( pk: &Self::ProvingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, rng: R, - ) -> Result + ) -> Result where T: TranscriptWrite, R: Rng; } -pub trait AccumulatorEncoding: Clone + Debug +pub trait AccumulatorEncoding: Clone + Debug where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme, { - fn from_repr(repr: &[&L::LoadedScalar]) -> Result; + type Accumulator: Clone + Debug; + + fn from_repr(repr: &[&L::LoadedScalar]) -> Result; } -impl AccumulatorEncoding for () +impl AccumulatorEncoding for PhantomData where C: CurveAffine, L: Loader, PCS: PolynomialCommitmentScheme, { - fn from_repr(_: &[&L::LoadedScalar]) -> Result { + type Accumulator = PCS::Output; + + fn from_repr(_: &[&L::LoadedScalar]) -> Result { unimplemented!() } } diff --git a/src/pcs/ipa.rs b/snark-verifier/src/pcs/ipa.rs similarity index 94% rename from src/pcs/ipa.rs rename to snark-verifier/src/pcs/ipa.rs index a2b34824..249e0f0d 100644 --- a/src/pcs/ipa.rs +++ b/snark-verifier/src/pcs/ipa.rs @@ -1,6 +1,5 @@ use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader, ScalarLoader}, - pcs::PolynomialCommitmentScheme, util::{ arithmetic::{ inner_product, powers, Curve, CurveAffine, Domain, Field, Fraction, PrimeField, @@ -24,21 +23,12 @@ mod multiopen; pub use accumulation::{IpaAs, IpaAsProof}; pub use accumulator::IpaAccumulator; pub use decider::IpaDecidingKey; -pub use multiopen::{Bgh19, Bgh19Proof, Bgh19SuccinctVerifyingKey}; +pub use multiopen::{Bgh19, Bgh19Proof}; #[derive(Clone, Debug)] -pub struct Ipa(PhantomData<(C, MOS)>); +pub struct Ipa(PhantomData); -impl PolynomialCommitmentScheme for Ipa -where - C: CurveAffine, - L: Loader, - MOS: Clone + Debug, -{ - type Accumulator = IpaAccumulator; -} - -impl Ipa +impl Ipa where C: CurveAffine, { @@ -204,11 +194,11 @@ impl IpaProvingKey { } pub fn svk(&self) -> IpaSuccinctVerifyingKey { - IpaSuccinctVerifyingKey::new(self.domain.clone(), self.h, self.s) + IpaSuccinctVerifyingKey::new(self.domain.clone(), self.g[0], self.h, self.s) } pub fn dk(&self) -> IpaDecidingKey { - IpaDecidingKey::new(self.g.clone()) + IpaDecidingKey::new(self.svk(), self.g.clone()) } pub fn commit(&self, poly: &Polynomial, omega: Option) -> C { @@ -244,13 +234,14 @@ impl IpaProvingKey { #[derive(Clone, Debug)] pub struct IpaSuccinctVerifyingKey { pub domain: Domain, + pub g: C, pub h: C, pub s: Option, } impl IpaSuccinctVerifyingKey { - pub fn new(domain: Domain, h: C, s: Option) -> Self { - Self { domain, h, s } + pub fn new(domain: Domain, g: C, h: C, s: Option) -> Self { + Self { domain, g, h, s } } pub fn zk(&self) -> bool { @@ -402,7 +393,7 @@ mod test { use crate::{ pcs::{ ipa::{self, IpaProvingKey}, - Decider, + AccumulationDecider, }, util::{arithmetic::Field, msm::Msm, poly::Polynomial}, }; @@ -414,7 +405,8 @@ mod test { #[test] fn test_ipa() { - type Ipa = ipa::Ipa; + type Ipa = ipa::Ipa; + type IpaAs = ipa::IpaAs; let k = 10; let mut rng = OsRng; @@ -441,7 +433,7 @@ mod test { }; let dk = pk.dk(); - assert!(Ipa::decide(&dk, accumulator)); + assert!(IpaAs::decide(&dk, accumulator).is_ok()); } } } diff --git a/src/pcs/ipa/accumulation.rs b/snark-verifier/src/pcs/ipa/accumulation.rs similarity index 84% rename from src/pcs/ipa/accumulation.rs rename to snark-verifier/src/pcs/ipa/accumulation.rs index eeea9efe..888e11aa 100644 --- a/src/pcs/ipa/accumulation.rs +++ b/snark-verifier/src/pcs/ipa/accumulation.rs @@ -4,7 +4,7 @@ use crate::{ ipa::{ h_coeffs, h_eval, Ipa, IpaAccumulator, IpaProof, IpaProvingKey, IpaSuccinctVerifyingKey, }, - AccumulationScheme, AccumulationSchemeProver, PolynomialCommitmentScheme, + AccumulationScheme, AccumulationSchemeProver, }, util::{ arithmetic::{Curve, CurveAffine, Field}, @@ -16,23 +16,24 @@ use crate::{ Error, }; use rand::Rng; -use std::{array, iter, marker::PhantomData}; +use std::{array, fmt::Debug, iter, marker::PhantomData}; #[derive(Clone, Debug)] -pub struct IpaAs(PhantomData); +pub struct IpaAs(PhantomData<(C, MOS)>); -impl AccumulationScheme for IpaAs +impl AccumulationScheme for IpaAs where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, + MOS: Clone + Debug, { + type Accumulator = IpaAccumulator; type VerifyingKey = IpaSuccinctVerifyingKey; - type Proof = IpaAsProof; + type Proof = IpaAsProof; fn read_proof( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, ) -> Result where @@ -43,9 +44,9 @@ where fn verify( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], proof: &Self::Proof, - ) -> Result { + ) -> Result { let loader = proof.z.loader(); let s = vk.s.as_ref().map(|s| loader.ec_point_load_const(s)); @@ -71,34 +72,31 @@ where } let v = loader.sum_products(&powers_of_alpha.iter().zip(h.iter()).collect_vec()); - Ipa::::succinct_verify(vk, &c, &proof.z, &v, &proof.ipa) + Ipa::succinct_verify(vk, &c, &proof.z, &v, &proof.ipa) } } #[derive(Clone, Debug)] -pub struct IpaAsProof +pub struct IpaAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { a_b_u: Option<(L::LoadedScalar, L::LoadedScalar, L::LoadedEcPoint)>, omega: Option, alpha: L::LoadedScalar, z: L::LoadedScalar, ipa: IpaProof, - _marker: PhantomData, } -impl IpaAsProof +impl IpaAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { fn read( vk: &IpaSuccinctVerifyingKey, - instances: &[PCS::Accumulator], + instances: &[IpaAccumulator], transcript: &mut T, ) -> Result where @@ -141,24 +139,23 @@ where alpha, z, ipa, - _marker: PhantomData, }) } } -impl AccumulationSchemeProver for IpaAs +impl AccumulationSchemeProver for IpaAs where C: CurveAffine, - PCS: PolynomialCommitmentScheme>, + MOS: Clone + Debug, { type ProvingKey = IpaProvingKey; fn create_proof( pk: &Self::ProvingKey, - instances: &[PCS::Accumulator], + instances: &[IpaAccumulator], transcript: &mut T, mut rng: R, - ) -> Result + ) -> Result, Error> where T: TranscriptWrite, R: Rng, @@ -216,7 +213,7 @@ where .map(|(power_of_alpha, h)| h * power_of_alpha) .sum::>(); - Ipa::::create_proof(pk, &h.to_vec(), &z, omega.as_ref(), transcript, &mut rng) + Ipa::create_proof(pk, &h.to_vec(), &z, omega.as_ref(), transcript, &mut rng) } } @@ -225,7 +222,7 @@ mod test { use crate::{ pcs::{ ipa::{self, IpaProvingKey}, - AccumulationScheme, AccumulationSchemeProver, Decider, + AccumulationDecider, AccumulationScheme, AccumulationSchemeProver, }, util::{arithmetic::Field, msm::Msm, poly::Polynomial, Itertools}, }; @@ -238,8 +235,8 @@ mod test { #[test] fn test_ipa_as() { - type Ipa = ipa::Ipa; - type IpaAs = ipa::IpaAs; + type Ipa = ipa::Ipa; + type IpaAs = ipa::IpaAs; let k = 10; let zk = true; @@ -286,6 +283,6 @@ mod test { }; let dk = pk.dk(); - assert!(Ipa::decide(&dk, accumulator)); + assert!(IpaAs::decide(&dk, accumulator).is_ok()); } } diff --git a/src/pcs/ipa/accumulator.rs b/snark-verifier/src/pcs/ipa/accumulator.rs similarity index 100% rename from src/pcs/ipa/accumulator.rs rename to snark-verifier/src/pcs/ipa/accumulator.rs diff --git a/snark-verifier/src/pcs/ipa/decider.rs b/snark-verifier/src/pcs/ipa/decider.rs new file mode 100644 index 00000000..db7b42fb --- /dev/null +++ b/snark-verifier/src/pcs/ipa/decider.rs @@ -0,0 +1,65 @@ +use crate::{pcs::ipa::IpaSuccinctVerifyingKey, util::arithmetic::CurveAffine}; + +#[derive(Clone, Debug)] +pub struct IpaDecidingKey { + svk: IpaSuccinctVerifyingKey, + g: Vec, +} + +impl IpaDecidingKey { + pub fn new(svk: IpaSuccinctVerifyingKey, g: Vec) -> Self { + Self { svk, g } + } +} + +impl AsRef> for IpaDecidingKey { + fn as_ref(&self) -> &IpaSuccinctVerifyingKey { + &self.svk + } +} + +mod native { + use crate::{ + loader::native::NativeLoader, + pcs::{ + ipa::{h_coeffs, IpaAccumulator, IpaAs, IpaDecidingKey}, + AccumulationDecider, + }, + util::{ + arithmetic::{Curve, CurveAffine, Field}, + msm::multi_scalar_multiplication, + Itertools, + }, + Error, + }; + use std::fmt::Debug; + + impl AccumulationDecider for IpaAs + where + C: CurveAffine, + MOS: Clone + Debug, + { + type DecidingKey = IpaDecidingKey; + + fn decide( + dk: &Self::DecidingKey, + IpaAccumulator { u, xi }: IpaAccumulator, + ) -> Result<(), Error> { + let h = h_coeffs(&xi, C::Scalar::one()); + (u == multi_scalar_multiplication(&h, &dk.g).to_affine()) + .then_some(()) + .ok_or_else(|| Error::AssertionFailure("U == commit(G, h)".to_string())) + } + + fn decide_all( + dk: &Self::DecidingKey, + accumulators: Vec>, + ) -> Result<(), Error> { + accumulators + .into_iter() + .map(|accumulator| Self::decide(dk, accumulator)) + .try_collect::<_, Vec<_>, _>()?; + Ok(()) + } + } +} diff --git a/snark-verifier/src/pcs/ipa/multiopen.rs b/snark-verifier/src/pcs/ipa/multiopen.rs new file mode 100644 index 00000000..99b0a565 --- /dev/null +++ b/snark-verifier/src/pcs/ipa/multiopen.rs @@ -0,0 +1,3 @@ +mod bgh19; + +pub use bgh19::{Bgh19, Bgh19Proof}; diff --git a/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs similarity index 92% rename from src/pcs/ipa/multiopen/bgh19.rs rename to snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index 29d291ad..6f19a44a 100644 --- a/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -1,11 +1,11 @@ use crate::{ loader::{LoadedScalar, Loader, ScalarLoader}, pcs::{ - ipa::{Ipa, IpaProof, IpaSuccinctVerifyingKey, Round}, - MultiOpenScheme, Query, + ipa::{Ipa, IpaAccumulator, IpaAs, IpaProof, IpaSuccinctVerifyingKey, Round}, + PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{ilog2, CurveAffine, Domain, FieldExt, Fraction}, + arithmetic::{ilog2, CurveAffine, FieldExt, Fraction}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -21,16 +21,17 @@ use std::{ #[derive(Clone, Debug)] pub struct Bgh19; -impl MultiOpenScheme for Ipa +impl PolynomialCommitmentScheme for IpaAs where C: CurveAffine, L: Loader, { - type SuccinctVerifyingKey = Bgh19SuccinctVerifyingKey; + type VerifyingKey = IpaSuccinctVerifyingKey; type Proof = Bgh19Proof; + type Output = IpaAccumulator; fn read_proof( - svk: &Self::SuccinctVerifyingKey, + svk: &Self::VerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result @@ -40,13 +41,13 @@ where Bgh19Proof::read(svk, queries, transcript) } - fn succinct_verify( - svk: &Self::SuccinctVerifyingKey, + fn verify( + svk: &Self::VerifyingKey, commitments: &[Msm], x: &L::LoadedScalar, queries: &[Query], proof: &Self::Proof, - ) -> Result { + ) -> Result { let loader = x.loader(); let g = loader.ec_point_load_const(&svk.g); @@ -87,22 +88,7 @@ where }; // IPA - Ipa::::succinct_verify(&svk.ipa, &p, &proof.x_3, &loader.load_zero(), &proof.ipa) - } -} - -#[derive(Clone, Debug)] -pub struct Bgh19SuccinctVerifyingKey { - g: C, - ipa: IpaSuccinctVerifyingKey, -} - -impl Bgh19SuccinctVerifyingKey { - pub fn new(domain: Domain, g: C, w: C, u: C) -> Self { - Self { - g, - ipa: IpaSuccinctVerifyingKey::new(domain, u, Some(w)), - } + Ipa::succinct_verify(svk, &p, &proof.x_3, &loader.load_zero(), &proof.ipa) } } @@ -129,7 +115,7 @@ where L: Loader, { fn read>( - svk: &Bgh19SuccinctVerifyingKey, + svk: &IpaSuccinctVerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result { @@ -151,7 +137,7 @@ where transcript.squeeze_challenge(), )) }) - .take(svk.ipa.domain.k) + .take(svk.domain.k) .collect::, _>>()?; let c = transcript.read_scalar()?; let blind = transcript.read_scalar()?; diff --git a/src/pcs/kzg.rs b/snark-verifier/src/pcs/kzg.rs similarity index 61% rename from src/pcs/kzg.rs rename to snark-verifier/src/pcs/kzg.rs index 056589a8..80d7ab63 100644 --- a/src/pcs/kzg.rs +++ b/snark-verifier/src/pcs/kzg.rs @@ -1,9 +1,4 @@ -use crate::{ - loader::Loader, - pcs::PolynomialCommitmentScheme, - util::arithmetic::{CurveAffine, MultiMillerLoop}, -}; -use std::{fmt::Debug, marker::PhantomData}; +use crate::util::arithmetic::CurveAffine; mod accumulation; mod accumulator; @@ -18,18 +13,6 @@ pub use multiopen::{Bdfg21, Bdfg21Proof, Gwc19, Gwc19Proof}; #[cfg(feature = "loader_halo2")] pub use accumulator::LimbsEncodingInstructions; -#[derive(Clone, Debug)] -pub struct Kzg(PhantomData<(M, MOS)>); - -impl PolynomialCommitmentScheme for Kzg -where - M: MultiMillerLoop, - L: Loader, - MOS: Clone + Debug, -{ - type Accumulator = KzgAccumulator; -} - #[derive(Clone, Copy, Debug)] pub struct KzgSuccinctVerifyingKey { pub g: C, diff --git a/src/pcs/kzg/accumulation.rs b/snark-verifier/src/pcs/kzg/accumulation.rs similarity index 70% rename from src/pcs/kzg/accumulation.rs rename to snark-verifier/src/pcs/kzg/accumulation.rs index 4273ce9a..202a8ce1 100644 --- a/src/pcs/kzg/accumulation.rs +++ b/snark-verifier/src/pcs/kzg/accumulation.rs @@ -1,47 +1,45 @@ use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader}, - pcs::{ - kzg::KzgAccumulator, AccumulationScheme, AccumulationSchemeProver, - PolynomialCommitmentScheme, - }, + pcs::{kzg::KzgAccumulator, AccumulationScheme, AccumulationSchemeProver}, util::{ - arithmetic::{Curve, CurveAffine, Field}, + arithmetic::{Curve, CurveAffine, Field, MultiMillerLoop}, msm::Msm, transcript::{TranscriptRead, TranscriptWrite}, }, Error, }; use rand::Rng; -use std::marker::PhantomData; +use std::{fmt::Debug, marker::PhantomData}; #[derive(Clone, Debug)] -pub struct KzgAs(PhantomData); +pub struct KzgAs(PhantomData<(M, MOS)>); -impl AccumulationScheme for KzgAs +impl AccumulationScheme for KzgAs where - C: CurveAffine, - L: Loader, - PCS: PolynomialCommitmentScheme>, + M: MultiMillerLoop, + L: Loader, + MOS: Clone + Debug, { + type Accumulator = KzgAccumulator; type VerifyingKey = KzgAsVerifyingKey; - type Proof = KzgAsProof; + type Proof = KzgAsProof; fn read_proof( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, ) -> Result where - T: TranscriptRead, + T: TranscriptRead, { KzgAsProof::read(vk, instances, transcript) } fn verify( _: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], proof: &Self::Proof, - ) -> Result { + ) -> Result { let (lhs, rhs) = instances .iter() .map(|accumulator| (&accumulator.lhs, &accumulator.rhs)) @@ -53,7 +51,7 @@ where bases .into_iter() .zip(powers_of_r.iter()) - .map(|(base, r)| Msm::::base(base) * r) + .map(|(base, r)| Msm::::base(base) * r) .sum::>() .evaluate(None) }); @@ -89,26 +87,23 @@ impl KzgAsVerifyingKey { } #[derive(Clone, Debug)] -pub struct KzgAsProof +pub struct KzgAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { blind: Option<(L::LoadedEcPoint, L::LoadedEcPoint)>, r: L::LoadedScalar, - _marker: PhantomData, } -impl KzgAsProof +impl KzgAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { fn read( vk: &KzgAsVerifyingKey, - instances: &[PCS::Accumulator], + instances: &[KzgAccumulator], transcript: &mut T, ) -> Result where @@ -128,29 +123,25 @@ where let r = transcript.squeeze_challenge(); - Ok(Self { - blind, - r, - _marker: PhantomData, - }) + Ok(Self { blind, r }) } } -impl AccumulationSchemeProver for KzgAs +impl AccumulationSchemeProver for KzgAs where - C: CurveAffine, - PCS: PolynomialCommitmentScheme>, + M: MultiMillerLoop, + MOS: Clone + Debug, { - type ProvingKey = KzgAsProvingKey; + type ProvingKey = KzgAsProvingKey; fn create_proof( pk: &Self::ProvingKey, - instances: &[PCS::Accumulator], + instances: &[KzgAccumulator], transcript: &mut T, rng: R, - ) -> Result + ) -> Result, Error> where - T: TranscriptWrite, + T: TranscriptWrite, R: Rng, { assert!(!instances.is_empty()); @@ -163,7 +154,7 @@ where let blind = pk .zk() .then(|| { - let s = C::Scalar::random(rng); + let s = M::Scalar::random(rng); let (g, s_g) = pk.0.unwrap(); let lhs = (s_g * s).to_affine(); let rhs = (g * s).to_affine(); @@ -186,7 +177,7 @@ where let [lhs, rhs] = [lhs, rhs].map(|msms| { msms.iter() .zip(powers_of_r.iter()) - .map(|(msm, power_of_r)| Msm::::base(msm) * power_of_r) + .map(|(msm, power_of_r)| Msm::::base(msm) * power_of_r) .sum::>() .evaluate(None) }); diff --git a/src/pcs/kzg/accumulator.rs b/snark-verifier/src/pcs/kzg/accumulator.rs similarity index 85% rename from src/pcs/kzg/accumulator.rs rename to snark-verifier/src/pcs/kzg/accumulator.rs index 50ce6ba8..b76ab80a 100644 --- a/src/pcs/kzg/accumulator.rs +++ b/snark-verifier/src/pcs/kzg/accumulator.rs @@ -34,7 +34,7 @@ mod native { loader::native::NativeLoader, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, - AccumulatorEncoding, PolynomialCommitmentScheme, + AccumulatorEncoding, }, util::{ arithmetic::{fe_from_limbs, CurveAffine}, @@ -43,17 +43,14 @@ mod native { Error, }; - impl AccumulatorEncoding + impl AccumulatorEncoding for LimbsEncoding where C: CurveAffine, - PCS: PolynomialCommitmentScheme< - C, - NativeLoader, - Accumulator = KzgAccumulator, - >, { - fn from_repr(limbs: &[&C::Scalar]) -> Result { + type Accumulator = KzgAccumulator; + + fn from_repr(limbs: &[&C::Scalar]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let [lhs_x, lhs_y, rhs_x, rhs_y]: [_; 4] = limbs @@ -88,7 +85,7 @@ mod evm { loader::evm::{EvmLoader, Scalar}, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, - AccumulatorEncoding, PolynomialCommitmentScheme, + AccumulatorEncoding, }, util::{ arithmetic::{CurveAffine, PrimeField}, @@ -98,18 +95,15 @@ mod evm { }; use std::rc::Rc; - impl AccumulatorEncoding, PCS> + impl AccumulatorEncoding> for LimbsEncoding where C: CurveAffine, C::Scalar: PrimeField, - PCS: PolynomialCommitmentScheme< - C, - Rc, - Accumulator = KzgAccumulator>, - >, { - fn from_repr(limbs: &[&Scalar]) -> Result { + type Accumulator = KzgAccumulator>; + + fn from_repr(limbs: &[&Scalar]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let loader = limbs[0].loader(); @@ -140,7 +134,7 @@ mod halo2 { loader::halo2::{EccInstructions, Halo2Loader, Scalar, Valuetools}, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, - AccumulatorEncoding, PolynomialCommitmentScheme, + AccumulatorEncoding, }, util::{ arithmetic::{fe_from_limbs, CurveAffine}, @@ -186,18 +180,15 @@ mod halo2 { ) -> Result, plonk::Error>; } - impl<'a, C, PCS, EccChip, const LIMBS: usize, const BITS: usize> - AccumulatorEncoding>, PCS> for LimbsEncoding + impl<'a, C, EccChip, const LIMBS: usize, const BITS: usize> + AccumulatorEncoding>> for LimbsEncoding where C: CurveAffine, - PCS: PolynomialCommitmentScheme< - C, - Rc>, - Accumulator = KzgAccumulator>>, - >, EccChip: LimbsEncodingInstructions<'a, C, LIMBS, BITS>, { - fn from_repr(limbs: &[&Scalar<'a, C, EccChip>]) -> Result { + type Accumulator = KzgAccumulator>>; + + fn from_repr(limbs: &[&Scalar<'a, C, EccChip>]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let loader = limbs[0].loader(); diff --git a/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs similarity index 66% rename from src/pcs/kzg/decider.rs rename to snark-verifier/src/pcs/kzg/decider.rs index 1ec0eb09..53cbd601 100644 --- a/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -1,16 +1,22 @@ -use crate::util::arithmetic::MultiMillerLoop; +use crate::{pcs::kzg::KzgSuccinctVerifyingKey, util::arithmetic::MultiMillerLoop}; use std::marker::PhantomData; #[derive(Debug, Clone, Copy)] pub struct KzgDecidingKey { - pub g2: M::G2Affine, - pub s_g2: M::G2Affine, + svk: KzgSuccinctVerifyingKey, + g2: M::G2Affine, + s_g2: M::G2Affine, _marker: PhantomData, } impl KzgDecidingKey { - pub fn new(g2: M::G2Affine, s_g2: M::G2Affine) -> Self { + pub fn new( + svk: impl Into>, + g2: M::G2Affine, + s_g2: M::G2Affine, + ) -> Self { Self { + svk: svk.into(), g2, s_g2, _marker: PhantomData, @@ -18,9 +24,15 @@ impl KzgDecidingKey { } } -impl From<(M::G2Affine, M::G2Affine)> for KzgDecidingKey { - fn from((g2, s_g2): (M::G2Affine, M::G2Affine)) -> KzgDecidingKey { - KzgDecidingKey::new(g2, s_g2) +impl From<(M::G1Affine, M::G2Affine, M::G2Affine)> for KzgDecidingKey { + fn from((g1, g2, s_g2): (M::G1Affine, M::G2Affine, M::G2Affine)) -> KzgDecidingKey { + KzgDecidingKey::new(g1, g2, s_g2) + } +} + +impl AsRef> for KzgDecidingKey { + fn as_ref(&self) -> &KzgSuccinctVerifyingKey { + &self.svk } } @@ -28,39 +40,47 @@ mod native { use crate::{ loader::native::NativeLoader, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgDecidingKey}, - Decider, + kzg::{KzgAccumulator, KzgAs, KzgDecidingKey}, + AccumulationDecider, + }, + util::{ + arithmetic::{Group, MillerLoopResult, MultiMillerLoop}, + Itertools, }, - util::arithmetic::{Group, MillerLoopResult, MultiMillerLoop}, + Error, }; use std::fmt::Debug; - impl Decider for Kzg + impl AccumulationDecider for KzgAs where M: MultiMillerLoop, MOS: Clone + Debug, { type DecidingKey = KzgDecidingKey; - type Output = bool; fn decide( dk: &Self::DecidingKey, KzgAccumulator { lhs, rhs }: KzgAccumulator, - ) -> bool { + ) -> Result<(), Error> { let terms = [(&lhs, &dk.g2.into()), (&rhs, &(-dk.s_g2).into())]; - M::multi_miller_loop(&terms) - .final_exponentiation() - .is_identity() - .into() + bool::from( + M::multi_miller_loop(&terms) + .final_exponentiation() + .is_identity(), + ) + .then_some(()) + .ok_or_else(|| Error::AssertionFailure("e(lhs, g2)·e(rhs, -s_g2) == O".to_string())) } fn decide_all( dk: &Self::DecidingKey, accumulators: Vec>, - ) -> bool { - !accumulators + ) -> Result<(), Error> { + accumulators .into_iter() - .any(|accumulator| !Self::decide(dk, accumulator)) + .map(|accumulator| Self::decide(dk, accumulator)) + .try_collect::<_, Vec<_>, _>()?; + Ok(()) } } } @@ -73,29 +93,29 @@ mod evm { LoadedScalar, }, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgDecidingKey}, - Decider, + kzg::{KzgAccumulator, KzgAs, KzgDecidingKey}, + AccumulationDecider, }, util::{ arithmetic::{CurveAffine, MultiMillerLoop, PrimeField}, msm::Msm, }, + Error, }; use std::{fmt::Debug, rc::Rc}; - impl Decider> for Kzg + impl AccumulationDecider> for KzgAs where M: MultiMillerLoop, M::Scalar: PrimeField, MOS: Clone + Debug, { type DecidingKey = KzgDecidingKey; - type Output = (); fn decide( dk: &Self::DecidingKey, KzgAccumulator { lhs, rhs }: KzgAccumulator>, - ) { + ) -> Result<(), Error> { let loader = lhs.loader(); let [g2, minus_s_g2] = [dk.g2, -dk.s_g2].map(|ec_point| { let coordinates = ec_point.coordinates().unwrap(); @@ -109,12 +129,13 @@ mod evm { ) }); loader.pairing(&lhs, g2, &rhs, minus_s_g2); + Ok(()) } fn decide_all( dk: &Self::DecidingKey, mut accumulators: Vec>>, - ) { + ) -> Result<(), Error> { assert!(!accumulators.is_empty()); let accumulator = if accumulators.len() == 1 { @@ -149,7 +170,7 @@ mod evm { KzgAccumulator::new(lhs, rhs) }; - Self::decide(dk, accumulator) + >>::decide(dk, accumulator) } } } diff --git a/src/pcs/kzg/multiopen.rs b/snark-verifier/src/pcs/kzg/multiopen.rs similarity index 100% rename from src/pcs/kzg/multiopen.rs rename to snark-verifier/src/pcs/kzg/multiopen.rs diff --git a/src/pcs/kzg/multiopen/bdfg21.rs b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs similarity index 95% rename from src/pcs/kzg/multiopen/bdfg21.rs rename to snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs index f542f750..b532f684 100644 --- a/src/pcs/kzg/multiopen/bdfg21.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs @@ -2,8 +2,8 @@ use crate::{ cost::{Cost, CostEstimation}, loader::{LoadedScalar, Loader, ScalarLoader}, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgSuccinctVerifyingKey}, - MultiOpenScheme, Query, + kzg::{KzgAccumulator, KzgAs, KzgSuccinctVerifyingKey}, + PolynomialCommitmentScheme, Query, }, util::{ arithmetic::{ilog2, CurveAffine, FieldExt, Fraction, MultiMillerLoop}, @@ -21,13 +21,14 @@ use std::{ #[derive(Clone, Debug)] pub struct Bdfg21; -impl MultiOpenScheme for Kzg +impl PolynomialCommitmentScheme for KzgAs where M: MultiMillerLoop, L: Loader, { - type SuccinctVerifyingKey = KzgSuccinctVerifyingKey; + type VerifyingKey = KzgSuccinctVerifyingKey; type Proof = Bdfg21Proof; + type Output = KzgAccumulator; fn read_proof( _: &KzgSuccinctVerifyingKey, @@ -40,13 +41,13 @@ where Bdfg21Proof::read(transcript) } - fn succinct_verify( + fn verify( svk: &KzgSuccinctVerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, queries: &[Query], proof: &Bdfg21Proof, - ) -> Result { + ) -> Result { let sets = query_sets(queries); let f = { let coeffs = query_set_coeffs(&sets, z, &proof.z_prime); @@ -366,13 +367,17 @@ where } } -impl CostEstimation for Kzg +impl CostEstimation for KzgAs where M: MultiMillerLoop, { type Input = Vec>; fn estimate_cost(_: &Vec>) -> Cost { - Cost::new(0, 2, 0, 2) + Cost { + num_commitment: 2, + num_msm: 2, + ..Default::default() + } } } diff --git a/src/pcs/kzg/multiopen/gwc19.rs b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs similarity index 87% rename from src/pcs/kzg/multiopen/gwc19.rs rename to snark-verifier/src/pcs/kzg/multiopen/gwc19.rs index 6e3f579f..31786e7d 100644 --- a/src/pcs/kzg/multiopen/gwc19.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs @@ -2,8 +2,8 @@ use crate::{ cost::{Cost, CostEstimation}, loader::{LoadedScalar, Loader}, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgSuccinctVerifyingKey}, - MultiOpenScheme, Query, + kzg::{KzgAccumulator, KzgAs, KzgSuccinctVerifyingKey}, + PolynomialCommitmentScheme, Query, }, util::{ arithmetic::{CurveAffine, MultiMillerLoop, PrimeField}, @@ -17,16 +17,17 @@ use crate::{ #[derive(Clone, Debug)] pub struct Gwc19; -impl MultiOpenScheme for Kzg +impl PolynomialCommitmentScheme for KzgAs where M: MultiMillerLoop, L: Loader, { - type SuccinctVerifyingKey = KzgSuccinctVerifyingKey; + type VerifyingKey = KzgSuccinctVerifyingKey; type Proof = Gwc19Proof; + type Output = KzgAccumulator; fn read_proof( - _: &Self::SuccinctVerifyingKey, + _: &Self::VerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result @@ -36,13 +37,13 @@ where Gwc19Proof::read(queries, transcript) } - fn succinct_verify( - svk: &Self::SuccinctVerifyingKey, + fn verify( + svk: &Self::VerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, queries: &[Query], proof: &Self::Proof, - ) -> Result { + ) -> Result { let sets = query_sets(queries); let powers_of_u = &proof.u.powers(sets.len()); let f = { @@ -152,7 +153,7 @@ where }) } -impl CostEstimation for Kzg +impl CostEstimation for KzgAs where M: MultiMillerLoop, { @@ -160,6 +161,10 @@ where fn estimate_cost(queries: &Vec>) -> Cost { let num_w = query_sets(queries).len(); - Cost::new(0, num_w, 0, num_w) + Cost { + num_commitment: num_w, + num_msm: num_w, + ..Default::default() + } } } diff --git a/src/system.rs b/snark-verifier/src/system.rs similarity index 100% rename from src/system.rs rename to snark-verifier/src/system.rs diff --git a/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs similarity index 99% rename from src/system/halo2.rs rename to snark-verifier/src/system/halo2.rs index 7c26387d..bb7b1bb9 100644 --- a/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -1,12 +1,12 @@ use crate::{ util::{ arithmetic::{root_of_unity, CurveAffine, Domain, FieldExt, Rotation}, - protocol::{ - CommonPolynomial, Expression, InstanceCommittingKey, Query, QuotientPolynomial, - }, Itertools, }, - Protocol, + verifier::plonk::protocol::{ + CommonPolynomial, Expression, InstanceCommittingKey, PlonkProtocol, Query, + QuotientPolynomial, + }, }; use halo2_proofs::{ plonk::{self, Any, ConstraintSystem, FirstPhase, SecondPhase, ThirdPhase, VerifyingKey}, @@ -84,7 +84,7 @@ pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( params: &P, vk: &VerifyingKey, config: Config, -) -> Protocol { +) -> PlonkProtocol { assert_eq!(vk.get_domain().k(), params.k()); let cs = vk.cs(); @@ -150,7 +150,7 @@ pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( .map(|accumulator_indices| polynomials.accumulator_indices(accumulator_indices)) .unwrap_or_default(); - Protocol { + PlonkProtocol { domain, preprocessed, num_instance: polynomials.num_instance(), diff --git a/src/system/halo2/strategy.rs b/snark-verifier/src/system/halo2/strategy.rs similarity index 100% rename from src/system/halo2/strategy.rs rename to snark-verifier/src/system/halo2/strategy.rs diff --git a/src/system/halo2/test.rs b/snark-verifier/src/system/halo2/test.rs similarity index 95% rename from src/system/halo2/test.rs rename to snark-verifier/src/system/halo2/test.rs index 1ec03306..03e5503a 100644 --- a/src/system/halo2/test.rs +++ b/snark-verifier/src/system/halo2/test.rs @@ -207,15 +207,13 @@ macro_rules! halo2_native_verify { $protocol:expr, $instances:expr, $transcript:expr, - $svk:expr, - $dk:expr + $vk:expr ) => {{ use halo2_proofs::poly::commitment::ParamsProver; - use $crate::verifier::PlonkVerifier; + use $crate::verifier::SnarkVerifier; - let proof = - <$plonk_verifier>::read_proof($svk, $protocol, $instances, $transcript).unwrap(); - assert!(<$plonk_verifier>::verify($svk, $dk, $protocol, $instances, &proof).unwrap()) + let proof = <$plonk_verifier>::read_proof($vk, $protocol, $instances, $transcript).unwrap(); + assert!(<$plonk_verifier>::verify($vk, $protocol, $instances, &proof).is_ok()) }}; } diff --git a/src/system/halo2/test/circuit.rs b/snark-verifier/src/system/halo2/test/circuit.rs similarity index 100% rename from src/system/halo2/test/circuit.rs rename to snark-verifier/src/system/halo2/test/circuit.rs diff --git a/src/system/halo2/test/circuit/maingate.rs b/snark-verifier/src/system/halo2/test/circuit/maingate.rs similarity index 100% rename from src/system/halo2/test/circuit/maingate.rs rename to snark-verifier/src/system/halo2/test/circuit/maingate.rs diff --git a/src/system/halo2/test/circuit/standard.rs b/snark-verifier/src/system/halo2/test/circuit/standard.rs similarity index 100% rename from src/system/halo2/test/circuit/standard.rs rename to snark-verifier/src/system/halo2/test/circuit/standard.rs diff --git a/src/system/halo2/test/ipa.rs b/snark-verifier/src/system/halo2/test/ipa.rs similarity index 91% rename from src/system/halo2/test/ipa.rs rename to snark-verifier/src/system/halo2/test/ipa.rs index 07fd6efd..b85666d8 100644 --- a/src/system/halo2/test/ipa.rs +++ b/snark-verifier/src/system/halo2/test/ipa.rs @@ -121,7 +121,7 @@ macro_rules! halo2_ipa_native_verify { $transcript:expr ) => {{ use $crate::{ - pcs::ipa::{Bgh19SuccinctVerifyingKey, IpaDecidingKey}, + pcs::ipa::{IpaDecidingKey, IpaSuccinctVerifyingKey}, system::halo2::test::{halo2_native_verify, ipa::w_u}, }; @@ -132,8 +132,15 @@ macro_rules! halo2_ipa_native_verify { $protocol, $instances, $transcript, - &Bgh19SuccinctVerifyingKey::new($protocol.domain.clone(), $params.get_g()[0], w, u), - &IpaDecidingKey::new($params.get_g().to_vec()) + &IpaDecidingKey::new( + IpaSuccinctVerifyingKey::new( + $protocol.domain.clone(), + $params.get_g()[0], + u, + Some(w) + ), + $params.get_g().to_vec() + ) ) }}; } diff --git a/src/system/halo2/test/ipa/native.rs b/snark-verifier/src/system/halo2/test/ipa/native.rs similarity index 92% rename from src/system/halo2/test/ipa/native.rs rename to snark-verifier/src/system/halo2/test/ipa/native.rs index 7d9e09bb..07621771 100644 --- a/src/system/halo2/test/ipa/native.rs +++ b/snark-verifier/src/system/halo2/test/ipa/native.rs @@ -1,10 +1,10 @@ use crate::{ - pcs::ipa::{Bgh19, Ipa}, + pcs::ipa::{Bgh19, IpaAs}, system::halo2::test::ipa::{ halo2_ipa_config, halo2_ipa_create_snark, halo2_ipa_native_verify, halo2_ipa_prepare, }, system::halo2::test::StandardPlonk, - verifier::Plonk, + verifier::plonk::PlonkVerifier, }; use halo2_curves::pasta::pallas; use halo2_proofs::{ @@ -47,7 +47,7 @@ macro_rules! test { } }; ($name:ident, $k:expr, $config:expr, $create_cirucit:expr) => { - test!(@ $name, $k, $config, $create_cirucit, ProverIPA, VerifierIPA, Plonk::>); + test!(@ $name, $k, $config, $create_cirucit, ProverIPA, VerifierIPA, PlonkVerifier::>); } } diff --git a/src/system/halo2/test/kzg.rs b/snark-verifier/src/system/halo2/test/kzg.rs similarity index 97% rename from src/system/halo2/test/kzg.rs rename to snark-verifier/src/system/halo2/test/kzg.rs index 2b267758..77c26964 100644 --- a/src/system/halo2/test/kzg.rs +++ b/snark-verifier/src/system/halo2/test/kzg.rs @@ -109,8 +109,7 @@ macro_rules! halo2_kzg_native_verify { $protocol, $instances, $transcript, - &$params.get_g()[0].into(), - &($params.g2(), $params.s_g2()).into() + &($params.get_g()[0], $params.g2(), $params.s_g2()).into() ) }}; } diff --git a/src/system/halo2/test/kzg/evm.rs b/snark-verifier/src/system/halo2/test/kzg/evm.rs similarity index 85% rename from src/system/halo2/test/kzg/evm.rs rename to snark-verifier/src/system/halo2/test/kzg/evm.rs index 1ab52083..8c44ced2 100644 --- a/src/system/halo2/test/kzg/evm.rs +++ b/snark-verifier/src/system/halo2/test/kzg/evm.rs @@ -1,6 +1,6 @@ use crate::{ loader::native::NativeLoader, - pcs::kzg::{Bdfg21, Gwc19, Kzg, LimbsEncoding}, + pcs::kzg::{Bdfg21, Gwc19, KzgAs, LimbsEncoding}, system::halo2::{ test::{ kzg::{ @@ -11,7 +11,7 @@ use crate::{ }, transcript::evm::{ChallengeEvm, EvmTranscript}, }, - verifier::Plonk, + verifier::plonk::PlonkVerifier, }; use halo2_curves::bn256::{Bn256, G1Affine}; use halo2_proofs::poly::kzg::multiopen::{ProverGWC, ProverSHPLONK, VerifierGWC, VerifierSHPLONK}; @@ -30,13 +30,12 @@ macro_rules! halo2_kzg_evm_verify { transcript::evm::EvmTranscript, }, util::Itertools, - verifier::PlonkVerifier, + verifier::SnarkVerifier, }; let loader = EvmLoader::new::(); let deployment_code = { - let svk = $params.get_g()[0].into(); - let dk = ($params.g2(), $params.s_g2()).into(); + let vk = ($params.get_g()[0].into(), $params.g2(), $params.s_g2()).into(); let protocol = $protocol.loaded(&loader); let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances( @@ -45,9 +44,9 @@ macro_rules! halo2_kzg_evm_verify { .map(|instances| instances.len()) .collect_vec(), ); - let proof = <$plonk_verifier>::read_proof(&svk, &protocol, &instances, &mut transcript) - .unwrap(); - <$plonk_verifier>::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + let proof = + <$plonk_verifier>::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); + <$plonk_verifier>::verify(&vk, &protocol, &instances, &proof).unwrap(); compile_yul(&loader.yul_code()) }; @@ -101,11 +100,11 @@ macro_rules! test { } }; ($name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test], shplonk, $name, $k, $config, $create_circuit, ProverSHPLONK<_>, VerifierSHPLONK<_>, Plonk, LimbsEncoding>); - test!(@ #[test], plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + test!(@ #[test], shplonk, $name, $k, $config, $create_circuit, ProverSHPLONK<_>, VerifierSHPLONK<_>, PlonkVerifier, LimbsEncoding>); + test!(@ #[test], plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, PlonkVerifier, LimbsEncoding>); }; ($(#[$attr:meta],)* $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test] $(,#[$attr])*, plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + test!(@ #[test] $(,#[$attr])*, plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, PlonkVerifier, LimbsEncoding>); }; } diff --git a/src/system/halo2/test/kzg/halo2.rs b/snark-verifier/src/system/halo2/test/kzg/halo2.rs similarity index 92% rename from src/system/halo2/test/kzg/halo2.rs rename to snark-verifier/src/system/halo2/test/kzg/halo2.rs index 314af5c7..1fd461da 100644 --- a/src/system/halo2/test/kzg/halo2.rs +++ b/snark-verifier/src/system/halo2/test/kzg/halo2.rs @@ -6,7 +6,7 @@ use crate::{ }, pcs::{ kzg::{ - Bdfg21, Kzg, KzgAccumulator, KzgAs, KzgAsProvingKey, KzgAsVerifyingKey, + Bdfg21, KzgAccumulator, KzgAs, KzgAsProvingKey, KzgAsVerifyingKey, KzgSuccinctVerifyingKey, LimbsEncoding, LimbsEncodingInstructions, }, AccumulationScheme, AccumulationSchemeProver, @@ -25,7 +25,7 @@ use crate::{ }, }, util::{arithmetic::fe_to_limbs, Itertools}, - verifier::{self, PlonkVerifier}, + verifier::{self, SnarkVerifier}, }; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ @@ -59,12 +59,12 @@ type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip type PoseidonTranscript = system::halo2::transcript::halo2::PoseidonTranscript; -type Pcs = Kzg; type Svk = KzgSuccinctVerifyingKey; -type As = KzgAs; +type As = KzgAs; type AsPk = KzgAsProvingKey; type AsVk = KzgAsVerifyingKey; -type Plonk = verifier::Plonk>; +type PlonkSuccinctVerifier = verifier::plonk::PlonkSuccinctVerifier>; +type PlonkVerifier = verifier::plonk::PlonkVerifier>; pub fn accumulate<'a>( svk: &Svk, @@ -92,8 +92,10 @@ pub fn accumulate<'a>( let instances = assign_instances(&snark.instances); let mut transcript = PoseidonTranscript::, _>::new(loader, snark.proof()); - let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &protocol, &instances, &proof).unwrap() + let proof = + PlonkSuccinctVerifier::read_proof(svk, &protocol, &instances, &mut transcript) + .unwrap(); + PlonkSuccinctVerifier::verify(svk, &protocol, &instances, &proof).unwrap() }) .collect_vec(); @@ -133,10 +135,15 @@ impl Accumulation { .flat_map(|snark| { let mut transcript = PoseidonTranscript::::new(snark.proof.as_slice()); - let proof = - Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript) - .unwrap(); - Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof).unwrap() + let proof = PlonkSuccinctVerifier::read_proof( + &svk, + &snark.protocol, + &snark.instances, + &mut transcript, + ) + .unwrap(); + PlonkSuccinctVerifier::verify(&svk, &snark.protocol, &snark.instances, &proof) + .unwrap() }) .collect_vec(); @@ -343,7 +350,7 @@ macro_rules! test { &circuits ); halo2_kzg_native_verify!( - Plonk, + PlonkVerifier, params, &snark.protocol, &snark.instances, diff --git a/src/system/halo2/test/kzg/native.rs b/snark-verifier/src/system/halo2/test/kzg/native.rs similarity index 88% rename from src/system/halo2/test/kzg/native.rs rename to snark-verifier/src/system/halo2/test/kzg/native.rs index e52ceb38..b1d38e06 100644 --- a/src/system/halo2/test/kzg/native.rs +++ b/snark-verifier/src/system/halo2/test/kzg/native.rs @@ -1,5 +1,5 @@ use crate::{ - pcs::kzg::{Bdfg21, Gwc19, Kzg, LimbsEncoding}, + pcs::kzg::{Bdfg21, Gwc19, KzgAs, LimbsEncoding}, system::halo2::test::{ kzg::{ halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_verify, halo2_kzg_prepare, @@ -7,7 +7,7 @@ use crate::{ }, StandardPlonk, }, - verifier::Plonk, + verifier::plonk::PlonkVerifier, }; use halo2_curves::bn256::{Bn256, G1Affine}; use halo2_proofs::{ @@ -49,8 +49,8 @@ macro_rules! test { } }; ($name:ident, $k:expr, $config:expr, $create_cirucit:expr) => { - test!(@ shplonk, $name, $k, $config, $create_cirucit, ProverSHPLONK<_>, VerifierSHPLONK<_>, Plonk, LimbsEncoding>); - test!(@ plonk, $name, $k, $config, $create_cirucit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + test!(@ shplonk, $name, $k, $config, $create_cirucit, ProverSHPLONK<_>, VerifierSHPLONK<_>, PlonkVerifier, LimbsEncoding>); + test!(@ plonk, $name, $k, $config, $create_cirucit, ProverGWC<_>, VerifierGWC<_>, PlonkVerifier, LimbsEncoding>); } } diff --git a/src/system/halo2/transcript.rs b/snark-verifier/src/system/halo2/transcript.rs similarity index 100% rename from src/system/halo2/transcript.rs rename to snark-verifier/src/system/halo2/transcript.rs diff --git a/src/system/halo2/transcript/evm.rs b/snark-verifier/src/system/halo2/transcript/evm.rs similarity index 100% rename from src/system/halo2/transcript/evm.rs rename to snark-verifier/src/system/halo2/transcript/evm.rs diff --git a/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs similarity index 100% rename from src/system/halo2/transcript/halo2.rs rename to snark-verifier/src/system/halo2/transcript/halo2.rs diff --git a/src/util.rs b/snark-verifier/src/util.rs similarity index 98% rename from src/util.rs rename to snark-verifier/src/util.rs index b42db61c..bbfa8c89 100644 --- a/src/util.rs +++ b/snark-verifier/src/util.rs @@ -2,7 +2,6 @@ pub mod arithmetic; pub mod hash; pub mod msm; pub mod poly; -pub mod protocol; pub mod transcript; pub(crate) use itertools::Itertools; diff --git a/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs similarity index 100% rename from src/util/arithmetic.rs rename to snark-verifier/src/util/arithmetic.rs diff --git a/src/util/hash.rs b/snark-verifier/src/util/hash.rs similarity index 100% rename from src/util/hash.rs rename to snark-verifier/src/util/hash.rs diff --git a/src/util/hash/poseidon.rs b/snark-verifier/src/util/hash/poseidon.rs similarity index 100% rename from src/util/hash/poseidon.rs rename to snark-verifier/src/util/hash/poseidon.rs diff --git a/src/util/msm.rs b/snark-verifier/src/util/msm.rs similarity index 100% rename from src/util/msm.rs rename to snark-verifier/src/util/msm.rs diff --git a/src/util/poly.rs b/snark-verifier/src/util/poly.rs similarity index 100% rename from src/util/poly.rs rename to snark-verifier/src/util/poly.rs diff --git a/src/util/protocol.rs b/snark-verifier/src/util/protocol.rs similarity index 90% rename from src/util/protocol.rs rename to snark-verifier/src/util/protocol.rs index 2eaf604e..6ae361db 100644 --- a/src/util/protocol.rs +++ b/snark-verifier/src/util/protocol.rs @@ -4,7 +4,6 @@ use crate::{ arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, Itertools, }, - Protocol, }; use num_integer::Integer; use num_traits::One; @@ -16,37 +15,6 @@ use std::{ ops::{Add, Mul, Neg, Sub}, }; -impl Protocol -where - C: CurveAffine, -{ - pub fn loaded>(&self, loader: &L) -> Protocol { - let preprocessed = self - .preprocessed - .iter() - .map(|preprocessed| loader.ec_point_load_const(preprocessed)) - .collect(); - let transcript_initial_state = self - .transcript_initial_state - .as_ref() - .map(|transcript_initial_state| loader.load_const(transcript_initial_state)); - Protocol { - domain: self.domain.clone(), - preprocessed, - num_instance: self.num_instance.clone(), - num_witness: self.num_witness.clone(), - num_challenge: self.num_challenge.clone(), - evaluations: self.evaluations.clone(), - queries: self.queries.clone(), - quotient: self.quotient.clone(), - transcript_initial_state, - instance_committing_key: self.instance_committing_key.clone(), - linearization: self.linearization, - accumulator_indices: self.accumulator_indices.clone(), - } - } -} - #[derive(Clone, Copy, Debug)] pub enum CommonPolynomial { Identity, diff --git a/src/util/transcript.rs b/snark-verifier/src/util/transcript.rs similarity index 100% rename from src/util/transcript.rs rename to snark-verifier/src/util/transcript.rs diff --git a/snark-verifier/src/verifier.rs b/snark-verifier/src/verifier.rs new file mode 100644 index 00000000..c492fe55 --- /dev/null +++ b/snark-verifier/src/verifier.rs @@ -0,0 +1,35 @@ +use crate::{ + loader::Loader, + util::{arithmetic::CurveAffine, transcript::TranscriptRead}, + Error, +}; +use std::fmt::Debug; + +pub mod plonk; + +pub trait SnarkVerifier +where + C: CurveAffine, + L: Loader, +{ + type VerifyingKey: Clone + Debug; + type Protocol: Clone + Debug; + type Proof: Clone + Debug; + type Output: Clone + Debug; + + fn read_proof( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead; + + fn verify( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result; +} diff --git a/snark-verifier/src/verifier/plonk.rs b/snark-verifier/src/verifier/plonk.rs new file mode 100644 index 00000000..08bf5dc9 --- /dev/null +++ b/snark-verifier/src/verifier/plonk.rs @@ -0,0 +1,173 @@ +use crate::{ + cost::{Cost, CostEstimation}, + loader::Loader, + pcs::{ + AccumulationDecider, AccumulationScheme, AccumulatorEncoding, PolynomialCommitmentScheme, + Query, + }, + util::{arithmetic::CurveAffine, transcript::TranscriptRead}, + verifier::{plonk::protocol::CommonPolynomialEvaluation, SnarkVerifier}, + Error, +}; +use std::{iter, marker::PhantomData}; + +mod proof; +pub(crate) mod protocol; + +pub use proof::PlonkProof; +pub use protocol::PlonkProtocol; + +pub struct PlonkSuccinctVerifier>(PhantomData<(AS, AE)>); + +impl SnarkVerifier for PlonkSuccinctVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationScheme + PolynomialCommitmentScheme, + AE: AccumulatorEncoding, +{ + type VerifyingKey = >::VerifyingKey; + type Protocol = PlonkProtocol; + type Proof = PlonkProof; + type Output = Vec; + + fn read_proof( + svk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + PlonkProof::read::(svk, protocol, instances, transcript) + } + + fn verify( + svk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result { + let common_poly_eval = { + let mut common_poly_eval = + CommonPolynomialEvaluation::new(&protocol.domain, protocol.langranges(), &proof.z); + + L::batch_invert(common_poly_eval.denoms()); + common_poly_eval.evaluate(); + + common_poly_eval + }; + + let mut evaluations = proof.evaluations(protocol, instances, &common_poly_eval)?; + let commitments = proof.commitments(protocol, &common_poly_eval, &mut evaluations)?; + let queries = proof.queries(protocol, evaluations); + + let accumulator = >::verify( + svk, + &commitments, + &proof.z, + &queries, + &proof.pcs, + )?; + + let accumulators = iter::empty() + .chain(Some(accumulator)) + .chain(proof.old_accumulators.iter().cloned()) + .collect(); + + Ok(accumulators) + } +} + +pub struct PlonkVerifier>(PhantomData<(AS, AE)>); + +impl SnarkVerifier for PlonkVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationDecider + PolynomialCommitmentScheme, + AS::DecidingKey: AsRef<>::VerifyingKey>, + AE: AccumulatorEncoding, +{ + type VerifyingKey = AS::DecidingKey; + type Protocol = PlonkProtocol; + type Proof = PlonkProof; + type Output = (); + + fn read_proof( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + PlonkProof::read::(vk.as_ref(), protocol, instances, transcript) + } + + fn verify( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result { + let accumulators = + PlonkSuccinctVerifier::::verify(vk.as_ref(), protocol, instances, proof)?; + AS::decide_all(vk, accumulators) + } +} + +impl CostEstimation<(C, L)> for PlonkSuccinctVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationScheme + + PolynomialCommitmentScheme + + CostEstimation>>, +{ + type Input = PlonkProtocol; + + fn estimate_cost(protocol: &PlonkProtocol) -> Cost { + let plonk_cost = { + let num_accumulator = protocol.accumulator_indices.len(); + let num_instance = protocol.num_instance.iter().sum(); + let num_commitment = + protocol.num_witness.iter().sum::() + protocol.quotient.num_chunk(); + let num_evaluation = protocol.evaluations.len(); + let num_msm = protocol.preprocessed.len() + num_commitment + 1 + 2 * num_accumulator; + Cost { + num_instance, + num_commitment, + num_evaluation, + num_msm, + ..Default::default() + } + }; + let pcs_cost = { + let queries = PlonkProof::::empty_queries(protocol); + AS::estimate_cost(&queries) + }; + plonk_cost + pcs_cost + } +} + +impl CostEstimation<(C, L)> for PlonkVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationScheme + + PolynomialCommitmentScheme + + CostEstimation>>, +{ + type Input = PlonkProtocol; + + fn estimate_cost(protocol: &PlonkProtocol) -> Cost { + PlonkSuccinctVerifier::::estimate_cost(protocol) + + Cost { + num_pairing: 2, + ..Default::default() + } + } +} diff --git a/src/verifier/plonk.rs b/snark-verifier/src/verifier/plonk/proof.rs similarity index 65% rename from src/verifier/plonk.rs rename to snark-verifier/src/verifier/plonk/proof.rs index e29410d3..fb12aed6 100644 --- a/src/verifier/plonk.rs +++ b/snark-verifier/src/verifier/plonk/proof.rs @@ -1,84 +1,26 @@ use crate::{ - cost::{Cost, CostEstimation}, loader::{LoadedScalar, Loader}, - pcs::{self, AccumulatorEncoding, MultiOpenScheme}, + pcs::{self, AccumulationScheme, AccumulatorEncoding, PolynomialCommitmentScheme}, util::{ arithmetic::{CurveAffine, Field, Rotation}, msm::Msm, - protocol::{ - CommonPolynomial::Lagrange, CommonPolynomialEvaluation, LinearizationStrategy, Query, - }, transcript::TranscriptRead, Itertools, }, - verifier::PlonkVerifier, - Error, Protocol, + verifier::plonk::protocol::{ + CommonPolynomial::Lagrange, CommonPolynomialEvaluation, LinearizationStrategy, + PlonkProtocol, Query, + }, + Error, }; -use std::{collections::HashMap, iter, marker::PhantomData}; - -pub struct Plonk(PhantomData<(MOS, AE)>); - -impl PlonkVerifier for Plonk -where - C: CurveAffine, - L: Loader, - MOS: MultiOpenScheme, - AE: AccumulatorEncoding, -{ - type Proof = PlonkProof; - - fn read_proof( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - transcript: &mut T, - ) -> Result - where - T: TranscriptRead, - { - PlonkProof::read::(svk, protocol, instances, transcript) - } - - fn succinct_verify( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - proof: &Self::Proof, - ) -> Result, Error> { - let common_poly_eval = { - let mut common_poly_eval = CommonPolynomialEvaluation::new( - &protocol.domain, - langranges(protocol, instances), - &proof.z, - ); - - L::batch_invert(common_poly_eval.denoms()); - common_poly_eval.evaluate(); - - common_poly_eval - }; - - let mut evaluations = proof.evaluations(protocol, instances, &common_poly_eval)?; - let commitments = proof.commitments(protocol, &common_poly_eval, &mut evaluations)?; - let queries = proof.queries(protocol, evaluations); - - let accumulator = MOS::succinct_verify(svk, &commitments, &proof.z, &queries, &proof.pcs)?; - - let accumulators = iter::empty() - .chain(Some(accumulator)) - .chain(proof.old_accumulators.iter().cloned()) - .collect(); - - Ok(accumulators) - } -} +use std::{collections::HashMap, iter}; #[derive(Clone, Debug)] -pub struct PlonkProof +pub struct PlonkProof where C: CurveAffine, L: Loader, - MOS: MultiOpenScheme, + AS: AccumulationScheme + PolynomialCommitmentScheme, { pub committed_instances: Option>, pub witnesses: Vec, @@ -86,25 +28,25 @@ where pub quotients: Vec, pub z: L::LoadedScalar, pub evaluations: Vec, - pub pcs: MOS::Proof, - pub old_accumulators: Vec, + pub pcs: >::Proof, + pub old_accumulators: Vec, } -impl PlonkProof +impl PlonkProof where C: CurveAffine, L: Loader, - MOS: MultiOpenScheme, + AS: AccumulationScheme + PolynomialCommitmentScheme, { pub fn read( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, + svk: &>::VerifyingKey, + protocol: &PlonkProtocol, instances: &[Vec], transcript: &mut T, ) -> Result where T: TranscriptRead, - AE: AccumulatorEncoding, + AE: AccumulatorEncoding, { if let Some(transcript_initial_state) = &protocol.transcript_initial_state { transcript.common_scalar(transcript_initial_state)?; @@ -184,7 +126,11 @@ where let z = transcript.squeeze_challenge(); let evaluations = transcript.read_n_scalars(protocol.evaluations.len())?; - let pcs = MOS::read_proof(svk, &Self::empty_queries(protocol), transcript)?; + let pcs = >::read_proof( + svk, + &Self::empty_queries(protocol), + transcript, + )?; let old_accumulators = protocol .accumulator_indices @@ -211,7 +157,7 @@ where }) } - pub fn empty_queries(protocol: &Protocol) -> Vec> { + pub fn empty_queries(protocol: &PlonkProtocol) -> Vec> { protocol .queries .iter() @@ -225,9 +171,9 @@ where .collect() } - fn queries( + pub(super) fn queries( &self, - protocol: &Protocol, + protocol: &PlonkProtocol, mut evaluations: HashMap, ) -> Vec> { Self::empty_queries(protocol) @@ -242,9 +188,9 @@ where .collect() } - fn commitments<'a>( + pub(super) fn commitments<'a>( &'a self, - protocol: &'a Protocol, + protocol: &'a PlonkProtocol, common_poly_eval: &CommonPolynomialEvaluation, evaluations: &mut HashMap, ) -> Result>, Error> { @@ -279,14 +225,14 @@ where .then(|| commitments.get(query.poly).cloned()) .flatten() }) - .ok_or(Error::InvalidQuery(query)) + .ok_or_else(|| Error::InvalidProtocol(format!("Missing query {query:?}"))) }, &|index| { self.challenges .get(index) .cloned() .map(Msm::constant) - .ok_or(Error::InvalidChallenge(index)) + .ok_or_else(|| Error::InvalidProtocol(format!("Missing challenge {index}"))) }, &|a| Ok(-a?), &|a, b| Ok(a? + b?), @@ -295,7 +241,7 @@ where match (a.size(), b.size()) { (0, _) => Ok(b * &a.try_into_constant().unwrap()), (_, 0) => Ok(a * &b.try_into_constant().unwrap()), - (_, _) => Err(Error::InvalidLinearization), + (_, _) => Err(Error::InvalidProtocol("Invalid linearization".to_string())), } }, &|a, scalar| Ok(a? * &loader.load_const(&scalar)), @@ -339,10 +285,9 @@ where commitments.push(quotient); evaluations.insert( quotient_query, - numerator - .try_into_constant() - .ok_or(Error::InvalidLinearization)? - * common_poly_eval.zn_minus_one_inv(), + numerator.try_into_constant().ok_or_else(|| { + Error::InvalidProtocol("Invalid linearization".to_string()) + })? * common_poly_eval.zn_minus_one_inv(), ); } } @@ -350,9 +295,9 @@ where Ok(commitments) } - fn evaluations( + pub(super) fn evaluations( &self, - protocol: &Protocol, + protocol: &PlonkProtocol, instances: &[Vec], common_poly_eval: &CommonPolynomialEvaluation, ) -> Result, Error> { @@ -393,72 +338,3 @@ where Ok(evals) } } - -impl CostEstimation<(C, L)> for Plonk -where - C: CurveAffine, - L: Loader, - MOS: MultiOpenScheme + CostEstimation>>, -{ - type Input = Protocol; - - fn estimate_cost(protocol: &Protocol) -> Cost { - let plonk_cost = { - let num_accumulator = protocol.accumulator_indices.len(); - let num_instance = protocol.num_instance.iter().sum(); - let num_commitment = - protocol.num_witness.iter().sum::() + protocol.quotient.num_chunk(); - let num_evaluation = protocol.evaluations.len(); - let num_msm = protocol.preprocessed.len() + num_commitment + 1 + 2 * num_accumulator; - Cost::new(num_instance, num_commitment, num_evaluation, num_msm) - }; - let pcs_cost = { - let queries = PlonkProof::::empty_queries(protocol); - MOS::estimate_cost(&queries) - }; - plonk_cost + pcs_cost - } -} - -fn langranges( - protocol: &Protocol, - instances: &[Vec], -) -> impl IntoIterator -where - C: CurveAffine, - L: Loader, -{ - let instance_eval_lagrange = protocol.instance_committing_key.is_none().then(|| { - let queries = { - let offset = protocol.preprocessed.len(); - let range = offset..offset + protocol.num_instance.len(); - protocol - .quotient - .numerator - .used_query() - .into_iter() - .filter(move |query| range.contains(&query.poly)) - }; - let (min_rotation, max_rotation) = queries.fold((0, 0), |(min, max), query| { - if query.rotation.0 < min { - (query.rotation.0, max) - } else if query.rotation.0 > max { - (min, query.rotation.0) - } else { - (min, max) - } - }); - let max_instance_len = instances - .iter() - .map(|instance| instance.len()) - .max() - .unwrap_or_default(); - -max_rotation..max_instance_len as i32 + min_rotation.abs() - }); - protocol - .quotient - .numerator - .used_langrange() - .into_iter() - .chain(instance_eval_lagrange.into_iter().flatten()) -} diff --git a/snark-verifier/src/verifier/plonk/protocol.rs b/snark-verifier/src/verifier/plonk/protocol.rs new file mode 100644 index 00000000..daaa58a9 --- /dev/null +++ b/snark-verifier/src/verifier/plonk/protocol.rs @@ -0,0 +1,503 @@ +use crate::{ + loader::{native::NativeLoader, LoadedScalar, Loader}, + util::{ + arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, + Itertools, + }, +}; +use num_integer::Integer; +use num_traits::One; +use std::{ + cmp::max, + collections::{BTreeMap, BTreeSet}, + fmt::Debug, + iter::{self, Sum}, + ops::{Add, Mul, Neg, Sub}, +}; + +#[derive(Clone, Debug)] +pub struct PlonkProtocol +where + C: CurveAffine, + L: Loader, +{ + // Common description + pub domain: Domain, + pub preprocessed: Vec, + pub num_instance: Vec, + pub num_witness: Vec, + pub num_challenge: Vec, + pub evaluations: Vec, + pub queries: Vec, + pub quotient: QuotientPolynomial, + // Minor customization + pub transcript_initial_state: Option, + pub instance_committing_key: Option>, + pub linearization: Option, + pub accumulator_indices: Vec>, +} + +impl PlonkProtocol +where + C: CurveAffine, + L: Loader, +{ + pub(super) fn langranges(&self) -> impl IntoIterator { + let instance_eval_lagrange = self.instance_committing_key.is_none().then(|| { + let queries = { + let offset = self.preprocessed.len(); + let range = offset..offset + self.num_instance.len(); + self.quotient + .numerator + .used_query() + .into_iter() + .filter(move |query| range.contains(&query.poly)) + }; + let (min_rotation, max_rotation) = queries.fold((0, 0), |(min, max), query| { + if query.rotation.0 < min { + (query.rotation.0, max) + } else if query.rotation.0 > max { + (min, query.rotation.0) + } else { + (min, max) + } + }); + let max_instance_len = self.num_instance.iter().max().copied().unwrap_or_default(); + -max_rotation..max_instance_len as i32 + min_rotation.abs() + }); + self.quotient + .numerator + .used_langrange() + .into_iter() + .chain(instance_eval_lagrange.into_iter().flatten()) + } +} +impl PlonkProtocol +where + C: CurveAffine, +{ + pub fn loaded>(&self, loader: &L) -> PlonkProtocol { + let preprocessed = self + .preprocessed + .iter() + .map(|preprocessed| loader.ec_point_load_const(preprocessed)) + .collect(); + let transcript_initial_state = self + .transcript_initial_state + .as_ref() + .map(|transcript_initial_state| loader.load_const(transcript_initial_state)); + PlonkProtocol { + domain: self.domain.clone(), + preprocessed, + num_instance: self.num_instance.clone(), + num_witness: self.num_witness.clone(), + num_challenge: self.num_challenge.clone(), + evaluations: self.evaluations.clone(), + queries: self.queries.clone(), + quotient: self.quotient.clone(), + transcript_initial_state, + instance_committing_key: self.instance_committing_key.clone(), + linearization: self.linearization, + accumulator_indices: self.accumulator_indices.clone(), + } + } +} + +#[cfg(feature = "loader_halo2")] +mod halo2 { + use crate::{ + loader::halo2::{EccInstructions, Halo2Loader}, + util::arithmetic::CurveAffine, + verifier::plonk::PlonkProtocol, + }; + use halo2_proofs::circuit; + use std::rc::Rc; + + impl PlonkProtocol + where + C: CurveAffine, + { + pub fn loaded_preprocessed_as_witness<'a, EccChip: EccInstructions<'a, C>>( + &self, + loader: &Rc>, + ) -> PlonkProtocol>> { + let preprocessed = self + .preprocessed + .iter() + .map(|preprocessed| loader.assign_ec_point(circuit::Value::known(*preprocessed))) + .collect(); + let transcript_initial_state = + self.transcript_initial_state + .as_ref() + .map(|transcript_initial_state| { + loader.assign_scalar(circuit::Value::known(*transcript_initial_state)) + }); + PlonkProtocol { + domain: self.domain.clone(), + preprocessed, + num_instance: self.num_instance.clone(), + num_witness: self.num_witness.clone(), + num_challenge: self.num_challenge.clone(), + evaluations: self.evaluations.clone(), + queries: self.queries.clone(), + quotient: self.quotient.clone(), + transcript_initial_state, + instance_committing_key: self.instance_committing_key.clone(), + linearization: self.linearization, + accumulator_indices: self.accumulator_indices.clone(), + } + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum CommonPolynomial { + Identity, + Lagrange(i32), +} + +#[derive(Clone, Debug)] +pub struct CommonPolynomialEvaluation +where + C: CurveAffine, + L: Loader, +{ + zn: L::LoadedScalar, + zn_minus_one: L::LoadedScalar, + zn_minus_one_inv: Fraction, + identity: L::LoadedScalar, + lagrange: BTreeMap>, +} + +impl CommonPolynomialEvaluation +where + C: CurveAffine, + L: Loader, +{ + pub fn new( + domain: &Domain, + langranges: impl IntoIterator, + z: &L::LoadedScalar, + ) -> Self { + let loader = z.loader(); + + let zn = z.pow_const(domain.n as u64); + let langranges = langranges.into_iter().sorted().dedup().collect_vec(); + + let one = loader.load_one(); + let zn_minus_one = zn.clone() - &one; + let zn_minus_one_inv = Fraction::one_over(zn_minus_one.clone()); + + let n_inv = loader.load_const(&domain.n_inv); + let numer = zn_minus_one.clone() * &n_inv; + let omegas = langranges + .iter() + .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::one(), Rotation(i)))) + .collect_vec(); + let lagrange_evals = omegas + .iter() + .map(|omega| Fraction::new(numer.clone() * omega, z.clone() - omega)) + .collect_vec(); + + Self { + zn, + zn_minus_one, + zn_minus_one_inv, + identity: z.clone(), + lagrange: langranges.into_iter().zip(lagrange_evals).collect(), + } + } + + pub fn zn(&self) -> &L::LoadedScalar { + &self.zn + } + + pub fn zn_minus_one(&self) -> &L::LoadedScalar { + &self.zn_minus_one + } + + pub fn zn_minus_one_inv(&self) -> &L::LoadedScalar { + self.zn_minus_one_inv.evaluated() + } + + pub fn get(&self, poly: CommonPolynomial) -> &L::LoadedScalar { + match poly { + CommonPolynomial::Identity => &self.identity, + CommonPolynomial::Lagrange(i) => self.lagrange.get(&i).unwrap().evaluated(), + } + } + + pub fn denoms(&mut self) -> impl IntoIterator { + self.lagrange + .iter_mut() + .map(|(_, value)| value.denom_mut()) + .chain(iter::once(self.zn_minus_one_inv.denom_mut())) + .flatten() + } + + pub fn evaluate(&mut self) { + self.lagrange + .iter_mut() + .map(|(_, value)| value) + .chain(iter::once(&mut self.zn_minus_one_inv)) + .for_each(Fraction::evaluate) + } +} + +#[derive(Clone, Debug)] +pub struct QuotientPolynomial { + pub chunk_degree: usize, + pub numerator: Expression, +} + +impl QuotientPolynomial { + pub fn num_chunk(&self) -> usize { + Integer::div_ceil( + &(self.numerator.degree().checked_sub(1).unwrap_or_default()), + &self.chunk_degree, + ) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Query { + pub poly: usize, + pub rotation: Rotation, +} + +impl Query { + pub fn new>(poly: usize, rotation: R) -> Self { + Self { + poly, + rotation: rotation.into(), + } + } +} + +#[derive(Clone, Debug)] +pub enum Expression { + Constant(F), + CommonPolynomial(CommonPolynomial), + Polynomial(Query), + Challenge(usize), + Negated(Box>), + Sum(Box>, Box>), + Product(Box>, Box>), + Scaled(Box>, F), + DistributePowers(Vec>, Box>), +} + +impl Expression { + pub fn evaluate( + &self, + constant: &impl Fn(F) -> T, + common_poly: &impl Fn(CommonPolynomial) -> T, + poly: &impl Fn(Query) -> T, + challenge: &impl Fn(usize) -> T, + negated: &impl Fn(T) -> T, + sum: &impl Fn(T, T) -> T, + product: &impl Fn(T, T) -> T, + scaled: &impl Fn(T, F) -> T, + ) -> T { + let evaluate = |expr: &Expression| { + expr.evaluate( + constant, + common_poly, + poly, + challenge, + negated, + sum, + product, + scaled, + ) + }; + match self { + Expression::Constant(scalar) => constant(scalar.clone()), + Expression::CommonPolynomial(poly) => common_poly(*poly), + Expression::Polynomial(query) => poly(*query), + Expression::Challenge(index) => challenge(*index), + Expression::Negated(a) => { + let a = evaluate(a); + negated(a) + } + Expression::Sum(a, b) => { + let a = evaluate(a); + let b = evaluate(b); + sum(a, b) + } + Expression::Product(a, b) => { + let a = evaluate(a); + let b = evaluate(b); + product(a, b) + } + Expression::Scaled(a, scalar) => { + let a = evaluate(a); + scaled(a, scalar.clone()) + } + Expression::DistributePowers(exprs, scalar) => { + assert!(!exprs.is_empty()); + if exprs.len() == 1 { + return evaluate(exprs.first().unwrap()); + } + let mut exprs = exprs.iter(); + let first = evaluate(exprs.next().unwrap()); + let scalar = evaluate(scalar); + exprs.fold(first, |acc, expr| { + sum(product(acc, scalar.clone()), evaluate(expr)) + }) + } + } + } + + pub fn degree(&self) -> usize { + match self { + Expression::Constant(_) => 0, + Expression::CommonPolynomial(_) => 1, + Expression::Polynomial { .. } => 1, + Expression::Challenge { .. } => 0, + Expression::Negated(a) => a.degree(), + Expression::Sum(a, b) => max(a.degree(), b.degree()), + Expression::Product(a, b) => a.degree() + b.degree(), + Expression::Scaled(a, _) => a.degree(), + Expression::DistributePowers(a, b) => a + .iter() + .chain(Some(b.as_ref())) + .map(Self::degree) + .max() + .unwrap_or_default(), + } + } + + pub fn used_langrange(&self) -> BTreeSet { + self.evaluate( + &|_| None, + &|poly| match poly { + CommonPolynomial::Lagrange(i) => Some(BTreeSet::from_iter([i])), + _ => None, + }, + &|_| None, + &|_| None, + &|a| a, + &merge_left_right, + &merge_left_right, + &|a, _| a, + ) + .unwrap_or_default() + } + + pub fn used_query(&self) -> BTreeSet { + self.evaluate( + &|_| None, + &|_| None, + &|query| Some(BTreeSet::from_iter([query])), + &|_| None, + &|a| a, + &merge_left_right, + &merge_left_right, + &|a, _| a, + ) + .unwrap_or_default() + } +} + +impl From for Expression { + fn from(query: Query) -> Self { + Self::Polynomial(query) + } +} + +impl From for Expression { + fn from(common_poly: CommonPolynomial) -> Self { + Self::CommonPolynomial(common_poly) + } +} + +macro_rules! impl_expression_ops { + ($trait:ident, $op:ident, $variant:ident, $rhs:ty, $rhs_expr:expr) => { + impl $trait<$rhs> for Expression { + type Output = Expression; + fn $op(self, rhs: $rhs) -> Self::Output { + Expression::$variant((self).into(), $rhs_expr(rhs).into()) + } + } + impl $trait<$rhs> for &Expression { + type Output = Expression; + fn $op(self, rhs: $rhs) -> Self::Output { + Expression::$variant((self.clone()).into(), $rhs_expr(rhs).into()) + } + } + impl $trait<&$rhs> for Expression { + type Output = Expression; + fn $op(self, rhs: &$rhs) -> Self::Output { + Expression::$variant((self).into(), $rhs_expr(rhs.clone()).into()) + } + } + impl $trait<&$rhs> for &Expression { + type Output = Expression; + fn $op(self, rhs: &$rhs) -> Self::Output { + Expression::$variant((self.clone()).into(), $rhs_expr(rhs.clone()).into()) + } + } + }; +} + +impl_expression_ops!(Mul, mul, Product, Expression, std::convert::identity); +impl_expression_ops!(Mul, mul, Scaled, F, std::convert::identity); +impl_expression_ops!(Add, add, Sum, Expression, std::convert::identity); +impl_expression_ops!(Sub, sub, Sum, Expression, Neg::neg); + +impl Neg for Expression { + type Output = Expression; + fn neg(self) -> Self::Output { + Expression::Negated(Box::new(self)) + } +} + +impl Neg for &Expression { + type Output = Expression; + fn neg(self) -> Self::Output { + Expression::Negated(Box::new(self.clone())) + } +} + +impl Sum for Expression { + fn sum>(iter: I) -> Self { + iter.reduce(|acc, item| acc + item) + .unwrap_or_else(|| Expression::Constant(F::default())) + } +} + +impl One for Expression { + fn one() -> Self { + Expression::Constant(F::one()) + } +} + +fn merge_left_right(a: Option>, b: Option>) -> Option> { + match (a, b) { + (Some(a), None) | (None, Some(a)) => Some(a), + (Some(mut a), Some(b)) => { + a.extend(b); + Some(a) + } + _ => None, + } +} + +#[derive(Clone, Copy, Debug)] +pub enum LinearizationStrategy { + /// Older linearization strategy of GWC19, which has linearization + /// polynomial that doesn't evaluate to 0, and requires prover to send extra + /// evaluation of it to verifier. + WithoutConstant, + /// Current linearization strategy of GWC19, which has linearization + /// polynomial that evaluate to 0 by subtracting product of vanishing and + /// quotient polynomials. + MinusVanishingTimesQuotient, +} + +#[derive(Clone, Debug, Default)] +pub struct InstanceCommittingKey { + pub bases: Vec, + pub constant: Option, +} diff --git a/src/cost.rs b/src/cost.rs deleted file mode 100644 index b085aed8..00000000 --- a/src/cost.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::ops::Add; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Cost { - pub num_instance: usize, - pub num_commitment: usize, - pub num_evaluation: usize, - pub num_msm: usize, -} - -impl Cost { - pub fn new( - num_instance: usize, - num_commitment: usize, - num_evaluation: usize, - num_msm: usize, - ) -> Self { - Self { - num_instance, - num_commitment, - num_evaluation, - num_msm, - } - } -} - -impl Add for Cost { - type Output = Cost; - - fn add(self, rhs: Cost) -> Self::Output { - Cost::new( - self.num_instance + rhs.num_instance, - self.num_commitment + rhs.num_commitment, - self.num_evaluation + rhs.num_evaluation, - self.num_msm + rhs.num_msm, - ) - } -} - -pub trait CostEstimation { - type Input; - - fn estimate_cost(input: &Self::Input) -> Cost; -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 9749924d..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![allow(clippy::type_complexity)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::upper_case_acronyms)] - -pub mod cost; -pub mod loader; -pub mod pcs; -pub mod system; -pub mod util; -pub mod verifier; - -#[derive(Clone, Debug)] -pub enum Error { - InvalidInstances, - InvalidLinearization, - InvalidQuery(util::protocol::Query), - InvalidChallenge(usize), - AssertionFailure(String), - Transcript(std::io::ErrorKind, String), -} - -#[derive(Clone, Debug)] -pub struct Protocol -where - C: util::arithmetic::CurveAffine, - L: loader::Loader, -{ - // Common description - pub domain: util::arithmetic::Domain, - pub preprocessed: Vec, - pub num_instance: Vec, - pub num_witness: Vec, - pub num_challenge: Vec, - pub evaluations: Vec, - pub queries: Vec, - pub quotient: util::protocol::QuotientPolynomial, - // Minor customization - pub transcript_initial_state: Option, - pub instance_committing_key: Option>, - pub linearization: Option, - pub accumulator_indices: Vec>, -} diff --git a/src/loader/halo2.rs b/src/loader/halo2.rs deleted file mode 100644 index 5b3361fa..00000000 --- a/src/loader/halo2.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::{util::arithmetic::CurveAffine, Protocol}; -use halo2_proofs::circuit; -use std::rc::Rc; - -pub(crate) mod loader; -mod shim; - -#[cfg(test)] -pub(crate) mod test; - -pub use loader::{EcPoint, Halo2Loader, Scalar}; -pub use shim::{Context, EccInstructions, IntegerInstructions}; -pub use util::Valuetools; - -pub use halo2_wrong_ecc; - -mod util { - use halo2_proofs::circuit::Value; - - pub trait Valuetools: Iterator> { - fn fold_zipped(self, init: B, mut f: F) -> Value - where - Self: Sized, - F: FnMut(B, V) -> B, - { - self.fold(Value::known(init), |acc, value| { - acc.zip(value).map(|(acc, value)| f(acc, value)) - }) - } - } - - impl>> Valuetools for I {} -} - -impl Protocol -where - C: CurveAffine, -{ - pub fn loaded_preprocessed_as_witness<'a, EccChip: EccInstructions<'a, C>>( - &self, - loader: &Rc>, - ) -> Protocol>> { - let preprocessed = self - .preprocessed - .iter() - .map(|preprocessed| loader.assign_ec_point(circuit::Value::known(*preprocessed))) - .collect(); - let transcript_initial_state = - self.transcript_initial_state - .as_ref() - .map(|transcript_initial_state| { - loader.assign_scalar(circuit::Value::known(*transcript_initial_state)) - }); - Protocol { - domain: self.domain.clone(), - preprocessed, - num_instance: self.num_instance.clone(), - num_witness: self.num_witness.clone(), - num_challenge: self.num_challenge.clone(), - evaluations: self.evaluations.clone(), - queries: self.queries.clone(), - quotient: self.quotient.clone(), - transcript_initial_state, - instance_committing_key: self.instance_committing_key.clone(), - linearization: self.linearization, - accumulator_indices: self.accumulator_indices.clone(), - } - } -} diff --git a/src/pcs/ipa/decider.rs b/src/pcs/ipa/decider.rs deleted file mode 100644 index 2cf8c6cc..00000000 --- a/src/pcs/ipa/decider.rs +++ /dev/null @@ -1,57 +0,0 @@ -#[derive(Clone, Debug)] -pub struct IpaDecidingKey { - pub g: Vec, -} - -impl IpaDecidingKey { - pub fn new(g: Vec) -> Self { - Self { g } - } -} - -impl From> for IpaDecidingKey { - fn from(g: Vec) -> IpaDecidingKey { - IpaDecidingKey::new(g) - } -} - -mod native { - use crate::{ - loader::native::NativeLoader, - pcs::{ - ipa::{h_coeffs, Ipa, IpaAccumulator, IpaDecidingKey}, - Decider, - }, - util::{ - arithmetic::{Curve, CurveAffine, Field}, - msm::multi_scalar_multiplication, - }, - }; - use std::fmt::Debug; - - impl Decider for Ipa - where - C: CurveAffine, - MOS: Clone + Debug, - { - type DecidingKey = IpaDecidingKey; - type Output = bool; - - fn decide( - dk: &Self::DecidingKey, - IpaAccumulator { u, xi }: IpaAccumulator, - ) -> bool { - let h = h_coeffs(&xi, C::Scalar::one()); - u == multi_scalar_multiplication(&h, &dk.g).to_affine() - } - - fn decide_all( - dk: &Self::DecidingKey, - accumulators: Vec>, - ) -> bool { - !accumulators - .into_iter() - .any(|accumulator| !Self::decide(dk, accumulator)) - } - } -} diff --git a/src/pcs/ipa/multiopen.rs b/src/pcs/ipa/multiopen.rs deleted file mode 100644 index 9f685e76..00000000 --- a/src/pcs/ipa/multiopen.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod bgh19; - -pub use bgh19::{Bgh19, Bgh19Proof, Bgh19SuccinctVerifyingKey}; diff --git a/src/verifier.rs b/src/verifier.rs deleted file mode 100644 index 0eef23d2..00000000 --- a/src/verifier.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::{ - loader::Loader, - pcs::{Decider, MultiOpenScheme}, - util::{arithmetic::CurveAffine, transcript::TranscriptRead}, - Error, Protocol, -}; -use std::fmt::Debug; - -mod plonk; - -pub use plonk::{Plonk, PlonkProof}; - -pub trait PlonkVerifier -where - C: CurveAffine, - L: Loader, - MOS: MultiOpenScheme, -{ - type Proof: Clone + Debug; - - fn read_proof( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - transcript: &mut T, - ) -> Result - where - T: TranscriptRead; - - fn succinct_verify( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - proof: &Self::Proof, - ) -> Result, Error>; - - fn verify( - svk: &MOS::SuccinctVerifyingKey, - dk: &MOS::DecidingKey, - protocol: &Protocol, - instances: &[Vec], - proof: &Self::Proof, - ) -> Result - where - MOS: Decider, - { - let accumulators = Self::succinct_verify(svk, protocol, instances, proof)?; - let output = MOS::decide_all(dk, accumulators); - Ok(output) - } -}