diff --git a/Cargo.toml b/Cargo.toml index d3f46e35..ac383b4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ unroll = "0.1.5" anyhow = "1.0.40" serde = { version = "1.0", features = ["derive"] } serde_cbor = "0.11.1" +keccak-hash = "0.8.0" static_assertions = "1.1.0" [target.'cfg(not(target_env = "msvc"))'.dependencies] diff --git a/benches/hashing.rs b/benches/hashing.rs index 583c36b6..b1193516 100644 --- a/benches/hashing.rs +++ b/benches/hashing.rs @@ -3,6 +3,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::hash::gmimc::GMiMC; +use plonky2::hash::hashing::SPONGE_WIDTH; use plonky2::hash::poseidon::Poseidon; use tynm::type_name; @@ -16,22 +17,22 @@ pub(crate) fn bench_gmimc, const WIDTH: usize>(c: &mut Criterion }); } -pub(crate) fn bench_poseidon, const WIDTH: usize>(c: &mut Criterion) -where - [(); WIDTH - 1]:, -{ - c.bench_function(&format!("poseidon<{}, {}>", type_name::(), WIDTH), |b| { - b.iter_batched( - || F::rand_arr::(), - |state| F::poseidon(state), - BatchSize::SmallInput, - ) - }); +pub(crate) fn bench_poseidon(c: &mut Criterion) { + c.bench_function( + &format!("poseidon<{}, {}>", type_name::(), SPONGE_WIDTH), + |b| { + b.iter_batched( + || F::rand_arr::(), + |state| F::poseidon(state), + BatchSize::SmallInput, + ) + }, + ); } fn criterion_benchmark(c: &mut Criterion) { bench_gmimc::(c); - bench_poseidon::(c); + bench_poseidon::(c); } criterion_group!(benches, criterion_benchmark); diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index fc1ad37e..e75ea135 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -1,15 +1,13 @@ use anyhow::Result; use env_logger::Env; use log::info; -use plonky2::field::extension_field::Extendable; -use plonky2::field::field_types::RichField; -use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::fri::reduction_strategies::FriReductionStrategy; use plonky2::fri::FriConfig; use plonky2::hash::hashing::SPONGE_WIDTH; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; fn main() -> Result<()> { // Set the default log filter. This can be overridden using the `RUST_LOG` environment variable, @@ -18,10 +16,10 @@ fn main() -> Result<()> { // change this to info or warn later. env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init(); - bench_prove::() + bench_prove::() } -fn bench_prove, const D: usize>() -> Result<()> { +fn bench_prove, const D: usize>() -> Result<()> { let config = CircuitConfig { num_wires: 126, num_routed_wires: 33, @@ -40,21 +38,21 @@ fn bench_prove, const D: usize>() -> Result<()> { }; let inputs = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let zero = builder.zero(); let zero_ext = builder.zero_extension(); let mut state = [zero; SPONGE_WIDTH]; for _ in 0..10000 { - state = builder.permute(state); + state = builder.permute::<>::InnerHasher>(state); } // Random other gates. builder.add(zero, zero); builder.add_extension(zero_ext, zero_ext); - let circuit = builder.build(); + let circuit = builder.build::(); let proof_with_pis = circuit.prove(inputs)?; let proof_bytes = serde_cbor::to_vec(&proof_with_pis).unwrap(); info!("Proof length: {} bytes", proof_bytes.len()); diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 611c5671..f8322e6d 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -1,4 +1,6 @@ -use crate::field::field_types::{Field, PrimeField}; +use std::convert::TryInto; + +use crate::field::field_types::{Field, RichField}; pub mod algebra; pub mod quadratic; @@ -59,7 +61,7 @@ pub trait Frobenius: OEF { } } -pub trait Extendable: PrimeField + Sized { +pub trait Extendable: RichField + Sized { type Extension: Field + OEF + Frobenius + From; const W: Self; @@ -74,7 +76,7 @@ pub trait Extendable: PrimeField + Sized { const EXT_POWER_OF_TWO_GENERATOR: [Self; D]; } -impl + FieldExtension<1, BaseField = F>> Extendable<1> for F { +impl + FieldExtension<1, BaseField = F>> Extendable<1> for F { type Extension = F; const W: Self = F::ZERO; const DTH_ROOT: Self = F::ZERO; diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 97e926b4..5517779b 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -2,7 +2,7 @@ use std::ops::Range; use crate::field::extension_field::algebra::ExtensionAlgebra; use crate::field::extension_field::{Extendable, FieldExtension, OEF}; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; @@ -15,14 +15,11 @@ impl ExtensionTarget { self.0 } - pub fn frobenius>( - &self, - builder: &mut CircuitBuilder, - ) -> Self { + pub fn frobenius>(&self, builder: &mut CircuitBuilder) -> Self { self.repeated_frobenius(1, builder) } - pub fn repeated_frobenius>( + pub fn repeated_frobenius>( &self, count: usize, builder: &mut CircuitBuilder, @@ -74,7 +71,7 @@ impl ExtensionAlgebraTarget { } } -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { pub fn constant_extension(&mut self, c: F::Extension) -> ExtensionTarget { let c_parts = c.to_basefield_array(); let mut parts = [self.zero(); D]; diff --git a/src/field/field_types.rs b/src/field/field_types.rs index 595a9a5c..68c42dc5 100644 --- a/src/field/field_types.rs +++ b/src/field/field_types.rs @@ -15,7 +15,7 @@ use crate::hash::poseidon::Poseidon; use crate::util::bits_u64; /// A prime order field with the features we need to use it as a base field in our argument system. -pub trait RichField: PrimeField + GMiMC<12> + Poseidon<12> {} +pub trait RichField: PrimeField + GMiMC<12> + Poseidon {} /// A finite field. pub trait Field: diff --git a/src/fri/commitment.rs b/src/fri/commitment.rs index c8506356..54a2ebbc 100644 --- a/src/fri/commitment.rs +++ b/src/fri/commitment.rs @@ -2,12 +2,13 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::fft::FftRootTable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::fri::proof::FriProof; use crate::fri::prover::fri_proof; use crate::hash::merkle_tree::MerkleTree; use crate::iop::challenger::Challenger; use crate::plonk::circuit_data::CommonCircuitData; +use crate::plonk::config::GenericConfig; use crate::plonk::plonk_common::PlonkPolynomials; use crate::plonk::proof::OpeningSet; use crate::polynomial::{PolynomialCoeffs, PolynomialValues}; @@ -20,15 +21,17 @@ use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place, transp pub const SALT_SIZE: usize = 4; /// Represents a batch FRI based commitment to a list of polynomials. -pub struct PolynomialBatchCommitment { +pub struct PolynomialBatchCommitment, C: GenericConfig, const D: usize> { pub polynomials: Vec>, - pub merkle_tree: MerkleTree, + pub merkle_tree: MerkleTree, pub degree_log: usize, pub rate_bits: usize, pub blinding: bool, } -impl PolynomialBatchCommitment { +impl, C: GenericConfig, const D: usize> + PolynomialBatchCommitment +{ /// Creates a list polynomial commitment for the polynomials interpolating the values in `values`. pub(crate) fn from_values( values: Vec>, @@ -122,16 +125,13 @@ impl PolynomialBatchCommitment { /// Takes the commitments to the constants - sigmas - wires - zs - quotient — polynomials, /// and an opening point `zeta` and produces a batched opening proof + opening set. - pub(crate) fn open_plonk( + pub(crate) fn open_plonk( commitments: &[&Self; 4], zeta: F::Extension, - challenger: &mut Challenger, - common_data: &CommonCircuitData, + challenger: &mut Challenger, + common_data: &CommonCircuitData, timing: &mut TimingTree, - ) -> (FriProof, OpeningSet) - where - F: RichField + Extendable, - { + ) -> (FriProof, OpeningSet) { let config = &common_data.config; assert!(D > 1, "Not implemented for D=1."); let degree_log = commitments[0].degree_log; @@ -159,7 +159,7 @@ impl PolynomialBatchCommitment { ); challenger.observe_opening_set(&os); - let alpha = challenger.get_extension_challenge(); + let alpha = challenger.get_extension_challenge::(); let mut alpha = ReducingFactor::new(alpha); // Final low-degree polynomial that goes into FRI. @@ -225,13 +225,10 @@ impl PolynomialBatchCommitment { /// Given `points=(x_i)`, `evals=(y_i)` and `poly=P` with `P(x_i)=y_i`, computes the polynomial /// `Q=(P-I)/Z` where `I` interpolates `(x_i, y_i)` and `Z` is the vanishing polynomial on `(x_i)`. - fn compute_quotient( + fn compute_quotient( points: [F::Extension; N], poly: PolynomialCoeffs, - ) -> PolynomialCoeffs - where - F: Extendable, - { + ) -> PolynomialCoeffs { let quotient = if N == 1 { poly.divide_by_linear(points[0]).0 } else if N == 2 { diff --git a/src/fri/proof.rs b/src/fri/proof.rs index 72cf594a..ccd80a37 100644 --- a/src/fri/proof.rs +++ b/src/fri/proof.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{flatten, unflatten, Extendable}; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::RichField; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::hash::hash_types::MerkleCapTarget; use crate::hash::merkle_proofs::{MerkleProof, MerkleProofTarget}; @@ -13,6 +13,7 @@ use crate::hash::merkle_tree::MerkleCap; use crate::hash::path_compression::{compress_merkle_proofs, decompress_merkle_proofs}; use crate::iop::target::Target; use crate::plonk::circuit_data::CommonCircuitData; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::plonk_common::PolynomialsIndexBlinding; use crate::plonk::proof::{FriInferredElements, ProofChallenges}; use crate::polynomial::PolynomialCoeffs; @@ -20,9 +21,9 @@ use crate::polynomial::PolynomialCoeffs; /// Evaluations and Merkle proof produced by the prover in a FRI query step. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriQueryStep, const D: usize> { +pub struct FriQueryStep, H: Hasher, const D: usize> { pub evals: Vec, - pub merkle_proof: MerkleProof, + pub merkle_proof: MerkleProof, } #[derive(Clone)] @@ -35,11 +36,11 @@ pub struct FriQueryStepTarget { /// before they are combined into a composition polynomial. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriInitialTreeProof { - pub evals_proofs: Vec<(Vec, MerkleProof)>, +pub struct FriInitialTreeProof> { + pub evals_proofs: Vec<(Vec, MerkleProof)>, } -impl FriInitialTreeProof { +impl> FriInitialTreeProof { pub(crate) fn unsalted_evals( &self, polynomials: PolynomialsIndexBlinding, @@ -69,9 +70,9 @@ impl FriInitialTreeProofTarget { /// Proof for a FRI query round. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriQueryRound, const D: usize> { - pub initial_trees_proof: FriInitialTreeProof, - pub steps: Vec>, +pub struct FriQueryRound, H: Hasher, const D: usize> { + pub initial_trees_proof: FriInitialTreeProof, + pub steps: Vec>, } #[derive(Clone)] @@ -83,22 +84,22 @@ pub struct FriQueryRoundTarget { /// Compressed proof of the FRI query rounds. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedFriQueryRounds, const D: usize> { +pub struct CompressedFriQueryRounds, H: Hasher, const D: usize> { /// Query indices. pub indices: Vec, /// Map from initial indices `i` to the `FriInitialProof` for the `i`th leaf. - pub initial_trees_proofs: HashMap>, + pub initial_trees_proofs: HashMap>, /// For each FRI query step, a map from indices `i` to the `FriQueryStep` for the `i`th leaf. - pub steps: Vec>>, + pub steps: Vec>>, } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriProof, const D: usize> { +pub struct FriProof, H: Hasher, const D: usize> { /// A Merkle cap for each reduced polynomial in the commit phase. - pub commit_phase_merkle_caps: Vec>, + pub commit_phase_merkle_caps: Vec>, /// Query rounds proofs - pub query_round_proofs: Vec>, + pub query_round_proofs: Vec>, /// The final polynomial in coefficient form. pub final_poly: PolynomialCoeffs, /// Witness showing that the prover did PoW. @@ -114,24 +115,24 @@ pub struct FriProofTarget { #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedFriProof, const D: usize> { +pub struct CompressedFriProof, H: Hasher, const D: usize> { /// A Merkle cap for each reduced polynomial in the commit phase. - pub commit_phase_merkle_caps: Vec>, + pub commit_phase_merkle_caps: Vec>, /// Compressed query rounds proof. - pub query_round_proofs: CompressedFriQueryRounds, + pub query_round_proofs: CompressedFriQueryRounds, /// The final polynomial in coefficient form. pub final_poly: PolynomialCoeffs, /// Witness showing that the prover did PoW. pub pow_witness: F, } -impl, const D: usize> FriProof { +impl, H: Hasher, const D: usize> FriProof { /// Compress all the Merkle paths in the FRI proof and remove duplicate indices. - pub fn compress( + pub fn compress>( self, indices: &[usize], - common_data: &CommonCircuitData, - ) -> CompressedFriProof { + common_data: &CommonCircuitData, + ) -> CompressedFriProof { let FriProof { commit_phase_merkle_caps, query_round_proofs, @@ -231,14 +232,14 @@ impl, const D: usize> FriProof { } } -impl, const D: usize> CompressedFriProof { +impl, H: Hasher, const D: usize> CompressedFriProof { /// Decompress all the Merkle paths in the FRI proof and reinsert duplicate indices. - pub(crate) fn decompress( + pub(crate) fn decompress>( self, challenges: &ProofChallenges, fri_inferred_elements: FriInferredElements, - common_data: &CommonCircuitData, - ) -> FriProof { + common_data: &CommonCircuitData, + ) -> FriProof { let CompressedFriProof { commit_phase_merkle_caps, query_round_proofs, diff --git a/src/fri/prover.rs b/src/fri/prover.rs index 90ef8cfe..e902986b 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -1,14 +1,13 @@ use rayon::prelude::*; use crate::field::extension_field::{flatten, unflatten, Extendable}; -use crate::field::field_types::RichField; use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep}; use crate::fri::FriConfig; use crate::hash::hash_types::HashOut; -use crate::hash::hashing::hash_n_to_1; use crate::hash::merkle_tree::MerkleTree; use crate::iop::challenger::Challenger; use crate::plonk::circuit_data::CommonCircuitData; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::plonk_common::reduce_with_powers; use crate::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::timed; @@ -16,16 +15,16 @@ use crate::util::reverse_index_bits_in_place; use crate::util::timing::TimingTree; /// Builds a FRI proof. -pub fn fri_proof, const D: usize>( - initial_merkle_trees: &[&MerkleTree], +pub fn fri_proof, C: GenericConfig, const D: usize>( + initial_merkle_trees: &[&MerkleTree], // Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero. lde_polynomial_coeffs: PolynomialCoeffs, // Evaluation of the polynomial on the large domain. lde_polynomial_values: PolynomialValues, - challenger: &mut Challenger, - common_data: &CommonCircuitData, + challenger: &mut Challenger, + common_data: &CommonCircuitData, timing: &mut TimingTree, -) -> FriProof { +) -> FriProof { let n = lde_polynomial_values.values.len(); assert_eq!(lde_polynomial_coeffs.coeffs.len(), n); @@ -46,7 +45,7 @@ pub fn fri_proof, const D: usize>( let pow_witness = timed!( timing, "find proof-of-work witness", - fri_proof_of_work(current_hash, &common_data.config.fri_config) + fri_proof_of_work::(current_hash, &common_data.config.fri_config) ); // Query phase @@ -61,12 +60,15 @@ pub fn fri_proof, const D: usize>( } } -fn fri_committed_trees, const D: usize>( +fn fri_committed_trees, C: GenericConfig, const D: usize>( mut coeffs: PolynomialCoeffs, mut values: PolynomialValues, - challenger: &mut Challenger, - common_data: &CommonCircuitData, -) -> (Vec>, PolynomialCoeffs) { + challenger: &mut Challenger, + common_data: &CommonCircuitData, +) -> ( + Vec>, + PolynomialCoeffs, +) { let config = &common_data.config; let mut trees = Vec::new(); @@ -81,12 +83,12 @@ fn fri_committed_trees, const D: usize>( .par_chunks(arity) .map(|chunk: &[F::Extension]| flatten(chunk)) .collect(); - let tree = MerkleTree::new(chunked_values, config.cap_height); + let tree = MerkleTree::::new(chunked_values, config.cap_height); challenger.observe_cap(&tree.cap); trees.push(tree); - let beta = challenger.get_extension_challenge(); + let beta = challenger.get_extension_challenge::(); // P(x) = sum_{i, const D: usize>( (trees, coeffs) } -fn fri_proof_of_work(current_hash: HashOut, config: &FriConfig) -> F { +fn fri_proof_of_work, C: GenericConfig, const D: usize>( + current_hash: HashOut, + config: &FriConfig, +) -> F { (0..=F::NEG_ONE.to_canonical_u64()) .into_par_iter() .find_any(|&i| { - hash_n_to_1( + C::InnerHasher::hash( current_hash .elements .iter() @@ -119,33 +124,34 @@ fn fri_proof_of_work(current_hash: HashOut, config: &FriConfig) .collect(), false, ) - .to_canonical_u64() - .leading_zeros() + .elements[0] + .to_canonical_u64() + .leading_zeros() >= config.proof_of_work_bits + (64 - F::order().bits()) as u32 }) .map(F::from_canonical_u64) .expect("Proof of work failed. This is highly unlikely!") } -fn fri_prover_query_rounds, const D: usize>( - initial_merkle_trees: &[&MerkleTree], - trees: &[MerkleTree], - challenger: &mut Challenger, +fn fri_prover_query_rounds, C: GenericConfig, const D: usize>( + initial_merkle_trees: &[&MerkleTree], + trees: &[MerkleTree], + challenger: &mut Challenger, n: usize, - common_data: &CommonCircuitData, -) -> Vec> { + common_data: &CommonCircuitData, +) -> Vec> { (0..common_data.config.fri_config.num_query_rounds) .map(|_| fri_prover_query_round(initial_merkle_trees, trees, challenger, n, common_data)) .collect() } -fn fri_prover_query_round, const D: usize>( - initial_merkle_trees: &[&MerkleTree], - trees: &[MerkleTree], - challenger: &mut Challenger, +fn fri_prover_query_round, C: GenericConfig, const D: usize>( + initial_merkle_trees: &[&MerkleTree], + trees: &[MerkleTree], + challenger: &mut Challenger, n: usize, - common_data: &CommonCircuitData, -) -> FriQueryRound { + common_data: &CommonCircuitData, +) -> FriQueryRound { let mut query_steps = Vec::new(); let x = challenger.get_challenge(); let mut x_index = x.to_canonical_u64() as usize % n; diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index dc4214b5..0423e8c8 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -13,23 +13,24 @@ use crate::iop::challenger::RecursiveChallenger; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; +use crate::plonk::config::{AlgebraicConfig, AlgebraicHasher, GenericConfig}; use crate::plonk::plonk_common::PlonkPolynomials; use crate::plonk::proof::OpeningSetTarget; use crate::util::reducing::ReducingFactorTarget; use crate::util::{log2_strict, reverse_index_bits_in_place}; use crate::with_context; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Computes P'(x^arity) from {P(x*g^i)}_(i=0..arity), where g is a `arity`-th root of unity /// and P' is the FRI reduced polynomial. - fn compute_evaluation( + fn compute_evaluation>( &mut self, x: Target, x_index_within_coset_bits: &[BoolTarget], arity_bits: usize, evals: &[ExtensionTarget], beta: ExtensionTarget, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> ExtensionTarget { let arity = 1 << arity_bits; debug_assert_eq!(evals.len(), arity); @@ -68,10 +69,10 @@ impl, const D: usize> CircuitBuilder { /// Make sure we have enough wires and routed wires to do the FRI checks efficiently. This check /// isn't required -- without it we'd get errors elsewhere in the stack -- but just gives more /// helpful errors. - fn check_recursion_config( + fn check_recursion_config>( &self, max_fri_arity_bits: usize, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) { let random_access = RandomAccessGate::::new_from_config( &self.config, @@ -106,23 +107,23 @@ impl, const D: usize> CircuitBuilder { ); } - fn fri_verify_proof_of_work( + fn fri_verify_proof_of_work>( &mut self, proof: &FriProofTarget, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, config: &FriConfig, ) { let mut inputs = challenger.get_hash(self).elements.to_vec(); inputs.push(proof.pow_witness); - let hash = self.hash_n_to_m(inputs, 1, false)[0]; + let hash = self.hash_n_to_m::(inputs, 1, false)[0]; self.assert_leading_zeros( hash, config.proof_of_work_bits + (64 - F::order().bits()) as u32, ); } - pub fn verify_fri_proof( + pub fn verify_fri_proof>( &mut self, // Openings of the PLONK polynomials. os: &OpeningSetTarget, @@ -130,8 +131,8 @@ impl, const D: usize> CircuitBuilder { zeta: ExtensionTarget, initial_merkle_caps: &[MerkleCapTarget], proof: &FriProofTarget, - challenger: &mut RecursiveChallenger, - common_data: &CommonCircuitData, + challenger: &mut RecursiveChallenger, + common_data: &CommonCircuitData, ) { let config = &common_data.config; @@ -170,7 +171,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "check PoW", - self.fri_verify_proof_of_work(proof, challenger, &config.fri_config) + self.fri_verify_proof_of_work::(proof, challenger, &config.fri_config) ); // Check that parameters are coherent. @@ -223,7 +224,7 @@ impl, const D: usize> CircuitBuilder { } } - fn fri_verify_initial_proof( + fn fri_verify_initial_proof>( &mut self, x_index_bits: &[BoolTarget], proof: &FriInitialTreeProofTarget, @@ -239,7 +240,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, &format!("verify {}'th initial Merkle proof", i), - self.verify_merkle_proof_with_cap_index( + self.verify_merkle_proof_with_cap_index::( evals.clone(), x_index_bits, cap_index, @@ -250,14 +251,14 @@ impl, const D: usize> CircuitBuilder { } } - fn fri_combine_initial( + fn fri_combine_initial>( &mut self, proof: &FriInitialTreeProofTarget, alpha: ExtensionTarget, subgroup_x: Target, vanish_zeta: ExtensionTarget, precomputed_reduced_evals: PrecomputedReducedEvalsTarget, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> ExtensionTarget { assert!(D > 1, "Not implemented for D=1."); let config = &common_data.config; @@ -319,18 +320,18 @@ impl, const D: usize> CircuitBuilder { sum } - fn fri_verifier_query_round( + fn fri_verifier_query_round>( &mut self, zeta: ExtensionTarget, alpha: ExtensionTarget, precomputed_reduced_evals: PrecomputedReducedEvalsTarget, initial_merkle_caps: &[MerkleCapTarget], proof: &FriProofTarget, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, n: usize, betas: &[ExtensionTarget], round_proof: &FriQueryRoundTarget, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) { let n_log = log2_strict(n); @@ -345,7 +346,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "check FRI initial proof", - self.fri_verify_initial_proof( + self.fri_verify_initial_proof::( &x_index_bits, &round_proof.initial_trees_proof, initial_merkle_caps, @@ -414,7 +415,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "verify FRI round Merkle proof.", - self.verify_merkle_proof_with_cap_index( + self.verify_merkle_proof_with_cap_index::( flatten_target(evals), &coset_index_bits, cap_index, diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index add03a9d..1b067a42 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -8,6 +8,7 @@ use crate::fri::FriConfig; use crate::hash::merkle_proofs::verify_merkle_proof; use crate::hash::merkle_tree::MerkleCap; use crate::plonk::circuit_data::CommonCircuitData; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::plonk_common::PlonkPolynomials; use crate::plonk::proof::{OpeningSet, ProofChallenges}; use crate::util::reducing::ReducingFactor; @@ -55,13 +56,17 @@ pub(crate) fn fri_verify_proof_of_work, const D: us Ok(()) } -pub(crate) fn verify_fri_proof, const D: usize>( +pub(crate) fn verify_fri_proof< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +>( // Openings of the PLONK polynomials. os: &OpeningSet, challenges: &ProofChallenges, - initial_merkle_caps: &[MerkleCap], - proof: &FriProof, - common_data: &CommonCircuitData, + initial_merkle_caps: &[MerkleCap], + proof: &FriProof, + common_data: &CommonCircuitData, ) -> Result<()> { let config = &common_data.config; ensure!( @@ -88,7 +93,7 @@ pub(crate) fn verify_fri_proof, const D: usize>( .iter() .zip(&proof.query_round_proofs) { - fri_verifier_query_round( + fri_verifier_query_round::( challenges, precomputed_reduced_evals, initial_merkle_caps, @@ -103,13 +108,13 @@ pub(crate) fn verify_fri_proof, const D: usize>( Ok(()) } -fn fri_verify_initial_proof( +fn fri_verify_initial_proof>( x_index: usize, - proof: &FriInitialTreeProof, - initial_merkle_caps: &[MerkleCap], + proof: &FriInitialTreeProof, + initial_merkle_caps: &[MerkleCap], ) -> Result<()> { for ((evals, merkle_proof), cap) in proof.evals_proofs.iter().zip(initial_merkle_caps) { - verify_merkle_proof(evals.clone(), x_index, cap, merkle_proof)?; + verify_merkle_proof::(evals.clone(), x_index, cap, merkle_proof)?; } Ok(()) @@ -146,13 +151,13 @@ impl, const D: usize> PrecomputedReducedEvals { } } -pub(crate) fn fri_combine_initial, const D: usize>( - proof: &FriInitialTreeProof, +pub(crate) fn fri_combine_initial, C: GenericConfig, const D: usize>( + proof: &FriInitialTreeProof, alpha: F::Extension, zeta: F::Extension, subgroup_x: F, precomputed_reduced_evals: PrecomputedReducedEvals, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> F::Extension { let config = &common_data.config; assert!(D > 1, "Not implemented for D=1."); @@ -207,17 +212,17 @@ pub(crate) fn fri_combine_initial, const D: usize>( sum } -fn fri_verifier_query_round, const D: usize>( +fn fri_verifier_query_round, C: GenericConfig, const D: usize>( challenges: &ProofChallenges, precomputed_reduced_evals: PrecomputedReducedEvals, - initial_merkle_caps: &[MerkleCap], - proof: &FriProof, + initial_merkle_caps: &[MerkleCap], + proof: &FriProof, mut x_index: usize, n: usize, - round_proof: &FriQueryRound, - common_data: &CommonCircuitData, + round_proof: &FriQueryRound, + common_data: &CommonCircuitData, ) -> Result<()> { - fri_verify_initial_proof( + fri_verify_initial_proof::( x_index, &round_proof.initial_trees_proof, initial_merkle_caps, @@ -263,7 +268,7 @@ fn fri_verifier_query_round, const D: usize>( challenges.fri_betas[i], ); - verify_merkle_proof( + verify_merkle_proof::( flatten(evals), coset_index, &proof.commit_phase_merkle_caps[i], diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 6a516399..1ea2f769 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -1,13 +1,13 @@ use std::borrow::Borrow; use crate::field::extension_field::Extendable; -use crate::field::field_types::{PrimeField, RichField}; +use crate::field::field_types::PrimeField; use crate::gates::arithmetic_base::ArithmeticGate; use crate::gates::exponentiation::ExponentiationGate; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Computes `-x`. pub fn neg(&mut self, x: Target) -> Target { let neg_one = self.neg_one(); diff --git a/src/gadgets/arithmetic_extension.rs b/src/gadgets/arithmetic_extension.rs index 7c73a09b..32c80bc4 100644 --- a/src/gadgets/arithmetic_extension.rs +++ b/src/gadgets/arithmetic_extension.rs @@ -1,7 +1,7 @@ use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget}; use crate::field::extension_field::FieldExtension; use crate::field::extension_field::{Extendable, OEF}; -use crate::field::field_types::{Field, PrimeField, RichField}; +use crate::field::field_types::{Field, PrimeField}; use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::multiplication_extension::MulExtensionGate; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; @@ -10,7 +10,7 @@ use crate::iop::witness::{PartitionWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::util::bits_u64; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { pub fn arithmetic_extension( &mut self, const_0: F, @@ -484,9 +484,7 @@ struct QuotientGeneratorExtension { quotient: ExtensionTarget, } -impl, const D: usize> SimpleGenerator - for QuotientGeneratorExtension -{ +impl, const D: usize> SimpleGenerator for QuotientGeneratorExtension { fn dependencies(&self) -> Vec { let mut deps = self.numerator.to_target_array().to_vec(); deps.extend(&self.denominator.to_target_array()); @@ -509,7 +507,7 @@ pub struct PowersTarget { } impl PowersTarget { - pub fn next>( + pub fn next>( &mut self, builder: &mut CircuitBuilder, ) -> ExtensionTarget { @@ -518,7 +516,7 @@ impl PowersTarget { result } - pub fn repeated_frobenius>( + pub fn repeated_frobenius>( self, k: usize, builder: &mut CircuitBuilder, @@ -531,7 +529,7 @@ impl PowersTarget { } } -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { pub fn powers(&mut self, base: ExtensionTarget) -> PowersTarget { PowersTarget { base, @@ -555,20 +553,20 @@ mod tests { use anyhow::Result; use crate::field::extension_field::algebra::ExtensionAlgebra; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::extension_field::target::ExtensionAlgebraTarget; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, KeccakGoldilocksConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_mul_many() -> Result<()> { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -593,7 +591,7 @@ mod tests { builder.connect_extension(mul0, mul1); builder.connect_extension(mul1, mul2); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -601,9 +599,10 @@ mod tests { #[test] fn test_div_extension() -> Result<()> { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_zk_config(); @@ -619,7 +618,7 @@ mod tests { let comp_zt = builder.div_extension(xt, yt); builder.connect_extension(zt, comp_zt); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -627,9 +626,10 @@ mod tests { #[test] fn test_mul_algebra() -> Result<()> { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = KeccakGoldilocksConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -656,7 +656,7 @@ mod tests { pw.set_extension_target(zt.0[i], z.0[i]); } - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/src/gadgets/biguint.rs b/src/gadgets/biguint.rs index e037c402..ec70ec3f 100644 --- a/src/gadgets/biguint.rs +++ b/src/gadgets/biguint.rs @@ -248,24 +248,26 @@ mod tests { use rand::Rng; use crate::iop::witness::Witness; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::{ - field::goldilocks_field::GoldilocksField, iop::witness::PartialWitness, plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, verifier::verify}, }; #[test] fn test_biguint_add() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let mut rng = rand::thread_rng(); let x_value = BigUint::from_u128(rng.gen()).unwrap(); let y_value = BigUint::from_u128(rng.gen()).unwrap(); let expected_z_value = &x_value + &y_value; - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.add_virtual_biguint_target(x_value.to_u32_digits().len()); let y = builder.add_virtual_biguint_target(y_value.to_u32_digits().len()); @@ -277,13 +279,16 @@ mod tests { pw.set_biguint_target(&y, &y_value); pw.set_biguint_target(&expected_z, &expected_z_value); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } #[test] fn test_biguint_sub() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let mut rng = rand::thread_rng(); let mut x_value = BigUint::from_u128(rng.gen()).unwrap(); @@ -293,10 +298,9 @@ mod tests { } let expected_z_value = &x_value - &y_value; - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_biguint(&x_value); let y = builder.constant_biguint(&y_value); @@ -305,23 +309,25 @@ mod tests { builder.connect_biguint(&z, &expected_z); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } #[test] fn test_biguint_mul() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let mut rng = rand::thread_rng(); let x_value = BigUint::from_u128(rng.gen()).unwrap(); let y_value = BigUint::from_u128(rng.gen()).unwrap(); let expected_z_value = &x_value * &y_value; - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.add_virtual_biguint_target(x_value.to_u32_digits().len()); let y = builder.add_virtual_biguint_target(y_value.to_u32_digits().len()); @@ -333,22 +339,24 @@ mod tests { pw.set_biguint_target(&y, &y_value); pw.set_biguint_target(&expected_z, &expected_z_value); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } #[test] fn test_biguint_cmp() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let mut rng = rand::thread_rng(); let x_value = BigUint::from_u128(rng.gen()).unwrap(); let y_value = BigUint::from_u128(rng.gen()).unwrap(); - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_biguint(&x_value); let y = builder.constant_biguint(&y_value); @@ -357,13 +365,16 @@ mod tests { builder.connect(cmp.target, expected_cmp.target); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } #[test] fn test_biguint_div_rem() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let mut rng = rand::thread_rng(); let mut x_value = BigUint::from_u128(rng.gen()).unwrap(); @@ -373,10 +384,9 @@ mod tests { } let (expected_div_value, expected_rem_value) = x_value.div_rem(&y_value); - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_biguint(&x_value); let y = builder.constant_biguint(&y_value); @@ -388,7 +398,7 @@ mod tests { builder.connect_biguint(&div, &expected_div); builder.connect_biguint(&rem, &expected_rem); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } diff --git a/src/gadgets/curve.rs b/src/gadgets/curve.rs index c86c3c0d..6ffe7ec4 100644 --- a/src/gadgets/curve.rs +++ b/src/gadgets/curve.rs @@ -180,18 +180,19 @@ mod tests { use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; use crate::curve::secp256k1::Secp256K1; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::field::secp256k1_base::Secp256K1Base; use crate::field::secp256k1_scalar::Secp256K1Scalar; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_curve_point_is_valid() -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -205,7 +206,7 @@ mod tests { builder.curve_assert_valid(&g_target); builder.curve_assert_valid(&neg_g_target); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) @@ -214,8 +215,9 @@ mod tests { #[test] #[should_panic] fn test_curve_point_is_not_valid() { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -232,7 +234,7 @@ mod tests { builder.curve_assert_valid(¬_g_target); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common).unwrap(); @@ -240,8 +242,9 @@ mod tests { #[test] fn test_curve_double() -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -268,7 +271,7 @@ mod tests { builder.connect_affine_point(&double_g_expected, &double_g_actual); builder.connect_affine_point(&double_neg_g_expected, &double_neg_g_actual); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) @@ -276,8 +279,9 @@ mod tests { #[test] fn test_curve_add() -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -297,7 +301,7 @@ mod tests { builder.connect_affine_point(&g_plus_2g_expected, &g_plus_2g_actual); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) @@ -306,8 +310,9 @@ mod tests { #[test] #[ignore] fn test_curve_mul() -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig { num_routed_wires: 33, @@ -331,7 +336,7 @@ mod tests { builder.connect_affine_point(&five_g_expected, &five_g_actual); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) @@ -340,8 +345,9 @@ mod tests { #[test] #[ignore] fn test_curve_random() -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig { num_routed_wires: 33, @@ -360,7 +366,7 @@ mod tests { let randot_times_two = builder.curve_scalar_mul(&randot, &two_target); builder.connect_affine_point(&randot_doubled, &randot_times_two); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) diff --git a/src/gadgets/hash.rs b/src/gadgets/hash.rs index 2eb93da7..5ec47323 100644 --- a/src/gadgets/hash.rs +++ b/src/gadgets/hash.rs @@ -1,112 +1,27 @@ use crate::field::extension_field::Extendable; use crate::field::field_types::RichField; -use crate::gates::gmimc::GMiMCGate; -use crate::gates::poseidon::PoseidonGate; -use crate::hash::gmimc::GMiMC; -use crate::hash::hashing::{HashFamily, HASH_FAMILY}; -use crate::hash::poseidon::Poseidon; +use crate::hash::hashing::SPONGE_WIDTH; use crate::iop::target::{BoolTarget, Target}; -use crate::iop::wire::Wire; use crate::plonk::circuit_builder::CircuitBuilder; +use crate::plonk::config::AlgebraicHasher; impl, const D: usize> CircuitBuilder { - pub fn permute(&mut self, inputs: [Target; W]) -> [Target; W] - where - F: GMiMC + Poseidon, - [(); W - 1]:, - { + pub fn permute>( + &mut self, + inputs: [Target; SPONGE_WIDTH], + ) -> [Target; SPONGE_WIDTH] { // We don't want to swap any inputs, so set that wire to 0. let _false = self._false(); - self.permute_swapped(inputs, _false) + self.permute_swapped::(inputs, _false) } /// Conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), then apply /// a cryptographic permutation. - pub(crate) fn permute_swapped( + pub(crate) fn permute_swapped>( &mut self, - inputs: [Target; W], + inputs: [Target; SPONGE_WIDTH], swap: BoolTarget, - ) -> [Target; W] - where - F: GMiMC + Poseidon, - [(); W - 1]:, - { - match HASH_FAMILY { - HashFamily::GMiMC => self.gmimc_permute_swapped(inputs, swap), - HashFamily::Poseidon => self.poseidon_permute_swapped(inputs, swap), - } - } - - /// Conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), then apply - /// the GMiMC permutation. - pub(crate) fn gmimc_permute_swapped( - &mut self, - inputs: [Target; W], - swap: BoolTarget, - ) -> [Target; W] - where - F: GMiMC, - { - let gate_type = GMiMCGate::::new(); - let gate = self.add_gate(gate_type, vec![]); - - let swap_wire = GMiMCGate::::WIRE_SWAP; - let swap_wire = Target::wire(gate, swap_wire); - self.connect(swap.target, swap_wire); - - // Route input wires. - for i in 0..W { - let in_wire = GMiMCGate::::wire_input(i); - let in_wire = Target::Wire(Wire { - gate, - input: in_wire, - }); - self.connect(inputs[i], in_wire); - } - - // Collect output wires. - (0..W) - .map(|i| { - Target::Wire(Wire { - gate, - input: GMiMCGate::::wire_output(i), - }) - }) - .collect::>() - .try_into() - .unwrap() - } - - /// Conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), then apply - /// the Poseidon permutation. - pub(crate) fn poseidon_permute_swapped( - &mut self, - inputs: [Target; W], - swap: BoolTarget, - ) -> [Target; W] - where - F: Poseidon, - [(); W - 1]:, - { - let gate_type = PoseidonGate::::new(); - let gate = self.add_gate(gate_type, vec![]); - - let swap_wire = PoseidonGate::::WIRE_SWAP; - let swap_wire = Target::wire(gate, swap_wire); - self.connect(swap.target, swap_wire); - - // Route input wires. - for i in 0..W { - let in_wire = PoseidonGate::::wire_input(i); - let in_wire = Target::wire(gate, in_wire); - self.connect(inputs[i], in_wire); - } - - // Collect output wires. - (0..W) - .map(|i| Target::wire(gate, PoseidonGate::::wire_output(i))) - .collect::>() - .try_into() - .unwrap() + ) -> [Target; SPONGE_WIDTH] { + H::permute_swapped(inputs, swap, self) } } diff --git a/src/gadgets/insert.rs b/src/gadgets/insert.rs index c6b463ea..5fc5fd48 100644 --- a/src/gadgets/insert.rs +++ b/src/gadgets/insert.rs @@ -43,11 +43,10 @@ mod tests { use anyhow::Result; use super::*; - use crate::field::extension_field::quadratic::QuadraticExtension; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn real_insert( @@ -61,12 +60,14 @@ mod tests { } fn test_insert_given_len(len_log: usize) -> Result<()> { - type F = GoldilocksField; - type FF = QuadraticExtension; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let len = 1 << len_log; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let v = (0..len - 1) .map(|_| builder.constant_extension(FF::rand())) .collect::>(); @@ -84,7 +85,7 @@ mod tests { } } - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/src/gadgets/interpolation.rs b/src/gadgets/interpolation.rs index 7f6f98f3..1d092631 100644 --- a/src/gadgets/interpolation.rs +++ b/src/gadgets/interpolation.rs @@ -10,7 +10,7 @@ use crate::plonk::circuit_builder::CircuitBuilder; /// Trait for gates which interpolate a polynomial, whose points are a (base field) coset of the multiplicative subgroup /// with the given size, and whose values are extension field elements, given by input wires. /// Outputs the evaluation of the interpolant at a given (extension field) evaluation point. -pub(crate) trait InterpolationGate, const D: usize>: +pub(crate) trait InterpolationGate, const D: usize>: Gate + Copy { fn new(subgroup_bits: usize) -> Self; @@ -108,23 +108,23 @@ impl, const D: usize> CircuitBuilder { mod tests { use anyhow::Result; - use crate::field::extension_field::quadratic::QuadraticExtension; use crate::field::extension_field::FieldExtension; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::field::interpolation::interpolant; use crate::gates::interpolation::HighDegreeInterpolationGate; use crate::gates::low_degree_interpolation::LowDegreeInterpolationGate; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_interpolate() -> Result<()> { - type F = GoldilocksField; const D: usize = 2; - type FF = QuadraticExtension; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -172,7 +172,7 @@ mod tests { builder.connect_extension(eval_hd, true_eval_target); builder.connect_extension(eval_ld, true_eval_target); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/src/gadgets/multiple_comparison.rs b/src/gadgets/multiple_comparison.rs index 3a5f2421..cd66720c 100644 --- a/src/gadgets/multiple_comparison.rs +++ b/src/gadgets/multiple_comparison.rs @@ -72,17 +72,19 @@ mod tests { use rand::Rng; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn test_list_le(size: usize, num_bits: usize) -> Result<()> { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let mut rng = rand::thread_rng(); @@ -120,7 +122,7 @@ mod tests { let expected_result = builder.constant_bool(a_biguint <= b_biguint); builder.connect(result.target, expected_result.target); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } diff --git a/src/gadgets/nonnative.rs b/src/gadgets/nonnative.rs index 56d717e3..d5a01961 100644 --- a/src/gadgets/nonnative.rs +++ b/src/gadgets/nonnative.rs @@ -214,24 +214,26 @@ mod tests { use anyhow::Result; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::field::secp256k1_base::Secp256K1Base; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_nonnative_add() -> Result<()> { type FF = Secp256K1Base; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let x_ff = FF::rand(); let y_ff = FF::rand(); let sum_ff = x_ff + y_ff; - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_nonnative(x_ff); let y = builder.constant_nonnative(y_ff); @@ -240,7 +242,7 @@ mod tests { let sum_expected = builder.constant_nonnative(sum_ff); builder.connect_nonnative(&sum, &sum_expected); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } @@ -248,6 +250,9 @@ mod tests { #[test] fn test_nonnative_sub() -> Result<()> { type FF = Secp256K1Base; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let x_ff = FF::rand(); let mut y_ff = FF::rand(); while y_ff.to_biguint() > x_ff.to_biguint() { @@ -255,10 +260,9 @@ mod tests { } let diff_ff = x_ff - y_ff; - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_nonnative(x_ff); let y = builder.constant_nonnative(y_ff); @@ -267,7 +271,7 @@ mod tests { let diff_expected = builder.constant_nonnative(diff_ff); builder.connect_nonnative(&diff, &diff_expected); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } @@ -275,14 +279,16 @@ mod tests { #[test] fn test_nonnative_mul() -> Result<()> { type FF = Secp256K1Base; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let x_ff = FF::rand(); let y_ff = FF::rand(); let product_ff = x_ff * y_ff; - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_nonnative(x_ff); let y = builder.constant_nonnative(y_ff); @@ -291,7 +297,7 @@ mod tests { let product_expected = builder.constant_nonnative(product_ff); builder.connect_nonnative(&product, &product_expected); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } @@ -299,13 +305,15 @@ mod tests { #[test] fn test_nonnative_neg() -> Result<()> { type FF = Secp256K1Base; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let x_ff = FF::rand(); let neg_x_ff = -x_ff; - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_nonnative(x_ff); let neg_x = builder.neg_nonnative(&x); @@ -313,7 +321,7 @@ mod tests { let neg_x_expected = builder.constant_nonnative(neg_x_ff); builder.connect_nonnative(&neg_x, &neg_x_expected); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } @@ -321,13 +329,15 @@ mod tests { #[test] fn test_nonnative_inv() -> Result<()> { type FF = Secp256K1Base; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let x_ff = FF::rand(); let inv_x_ff = x_ff.inverse(); - type F = GoldilocksField; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = builder.constant_nonnative(x_ff); let inv_x = builder.inv_nonnative(&x); @@ -335,7 +345,7 @@ mod tests { let inv_x_expected = builder.constant_nonnative(inv_x_ff); builder.connect_nonnative(&inv_x, &inv_x_expected); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) } diff --git a/src/gadgets/permutation.rs b/src/gadgets/permutation.rs index 2d8c4f22..9ded28ab 100644 --- a/src/gadgets/permutation.rs +++ b/src/gadgets/permutation.rs @@ -1,7 +1,6 @@ use std::collections::BTreeMap; use std::marker::PhantomData; -use crate::field::field_types::RichField; use crate::field::{extension_field::Extendable, field_types::Field}; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; use crate::iop::target::Target; @@ -9,7 +8,7 @@ use crate::iop::witness::{PartitionWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::util::bimap::bimap_from_lists; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Assert that two lists of expressions evaluate to permutations of one another. pub fn assert_permutation(&mut self, a: Vec>, b: Vec>) { assert_eq!( @@ -364,14 +363,15 @@ mod tests { use super::*; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn test_permutation_good(size: usize) -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -388,15 +388,16 @@ mod tests { builder.assert_permutation(a, b); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) } fn test_permutation_duplicates(size: usize) -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -417,15 +418,16 @@ mod tests { builder.assert_permutation(a, b); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) } fn test_permutation_bad(size: usize) -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -445,7 +447,7 @@ mod tests { builder.assert_permutation(a, b); - let data = builder.build(); + let data = builder.build::(); data.prove(pw)?; Ok(()) diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs index ff7fffd7..1008b2ab 100644 --- a/src/gadgets/polynomial.rs +++ b/src/gadgets/polynomial.rs @@ -1,6 +1,5 @@ use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget}; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::util::reducing::ReducingFactorTarget; @@ -12,7 +11,7 @@ impl PolynomialCoeffsExtTarget { self.0.len() } - pub fn eval_scalar>( + pub fn eval_scalar>( &self, builder: &mut CircuitBuilder, point: Target, @@ -22,7 +21,7 @@ impl PolynomialCoeffsExtTarget { point.reduce(&self.0, builder) } - pub fn eval>( + pub fn eval>( &self, builder: &mut CircuitBuilder, point: ExtensionTarget, @@ -41,7 +40,7 @@ impl PolynomialCoeffsExtAlgebraTarget { point: ExtensionTarget, ) -> ExtensionAlgebraTarget where - F: RichField + Extendable, + F: Extendable, { let mut acc = builder.zero_ext_algebra(); for &c in self.0.iter().rev() { @@ -56,7 +55,7 @@ impl PolynomialCoeffsExtAlgebraTarget { point: ExtensionAlgebraTarget, ) -> ExtensionAlgebraTarget where - F: RichField + Extendable, + F: Extendable, { let mut acc = builder.zero_ext_algebra(); for &c in self.0.iter().rev() { @@ -72,7 +71,7 @@ impl PolynomialCoeffsExtAlgebraTarget { powers: &[ExtensionAlgebraTarget], ) -> ExtensionAlgebraTarget where - F: RichField + Extendable, + F: Extendable, { debug_assert_eq!(self.0.len(), powers.len() + 1); let acc = self.0[0]; diff --git a/src/gadgets/random_access.rs b/src/gadgets/random_access.rs index c028fa68..c9f150f8 100644 --- a/src/gadgets/random_access.rs +++ b/src/gadgets/random_access.rs @@ -1,12 +1,11 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::gates::random_access::RandomAccessGate; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::util::log2_strict; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Checks that a `Target` matches a vector at a non-deterministic index. /// Note: `access_index` is not range-checked. pub fn random_access(&mut self, access_index: Target, claimed_element: Target, v: Vec) { @@ -58,20 +57,21 @@ mod tests { use anyhow::Result; use super::*; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn test_random_access_given_len(len_log: usize) -> Result<()> { - type F = GoldilocksField; - type FF = QuarticExtension; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let len = 1 << len_log; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let vec = FF::rand_vec(len); let v: Vec<_> = vec.iter().map(|x| builder.constant_extension(*x)).collect(); @@ -81,7 +81,7 @@ mod tests { builder.random_access_extension(it, elem, v.clone()); } - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/src/gadgets/range_check.rs b/src/gadgets/range_check.rs index 4409b103..8b80bde3 100644 --- a/src/gadgets/range_check.rs +++ b/src/gadgets/range_check.rs @@ -5,7 +5,7 @@ use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::{PartitionWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Checks that `x < 2^n_log` using a `BaseSumGate`. pub fn range_check(&mut self, x: Target, n_log: usize) { self.split_le(x, n_log); diff --git a/src/gadgets/select.rs b/src/gadgets/select.rs index 1db41fb8..80b5073e 100644 --- a/src/gadgets/select.rs +++ b/src/gadgets/select.rs @@ -1,10 +1,9 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Selects `x` or `y` based on `b`, i.e., this returns `if b { x } else { y }`. pub fn select_ext( &mut self, @@ -41,21 +40,22 @@ impl, const D: usize> CircuitBuilder { mod tests { use anyhow::Result; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_select() -> Result<()> { - type F = GoldilocksField; - type FF = QuarticExtension; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let (x, y) = (FF::rand(), FF::rand()); let xt = builder.add_virtual_extension_target(); @@ -72,7 +72,7 @@ mod tests { builder.connect_extension(should_be_x, xt); builder.connect_extension(should_be_y, yt); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/src/gadgets/sorting.rs b/src/gadgets/sorting.rs index c4378ab9..46cfc5b4 100644 --- a/src/gadgets/sorting.rs +++ b/src/gadgets/sorting.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use itertools::izip; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::assert_le::AssertLessThanGate; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; use crate::iop::target::{BoolTarget, Target}; @@ -26,7 +26,7 @@ pub struct MemoryOpTarget { value: Target, } -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { pub fn assert_permutation_memory_ops(&mut self, a: &[MemoryOpTarget], b: &[MemoryOpTarget]) { let a_chunks: Vec> = a .iter() @@ -116,15 +116,13 @@ impl, const D: usize> CircuitBuilder { } #[derive(Debug)] -struct MemoryOpSortGenerator, const D: usize> { +struct MemoryOpSortGenerator, const D: usize> { input_ops: Vec, output_ops: Vec, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator - for MemoryOpSortGenerator -{ +impl, const D: usize> SimpleGenerator for MemoryOpSortGenerator { fn dependencies(&self) -> Vec { self.input_ops .iter() @@ -176,14 +174,15 @@ mod tests { use super::*; use crate::field::field_types::{Field, PrimeField}; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn test_sorting(size: usize, address_bits: usize, timestamp_bits: usize) -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -236,7 +235,7 @@ mod tests { pw.set_target(output_ops[i].value, input_ops_sorted[i].3); } - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw).unwrap(); verify(proof, &data.verifier_only, &data.common) diff --git a/src/gadgets/split_base.rs b/src/gadgets/split_base.rs index 59879e4d..1105710c 100644 --- a/src/gadgets/split_base.rs +++ b/src/gadgets/split_base.rs @@ -3,14 +3,14 @@ use std::borrow::Borrow; use itertools::Itertools; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::base_sum::BaseSumGate; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::{PartitionWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Split the given element into a list of targets, where each one represents a /// base-B limb of the element, with little-endian ordering. pub fn split_le_base(&mut self, x: Target, num_limbs: usize) -> Vec { @@ -107,18 +107,20 @@ mod tests { use rand::{thread_rng, Rng}; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_split_base() -> Result<()> { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let x = F::from_canonical_usize(0b110100000); // 416 = 1532 in base 6. let xt = builder.constant(x); let limbs = builder.split_le_base::<6>(xt, 24); @@ -132,7 +134,7 @@ mod tests { builder.connect(limbs[3], one); builder.assert_leading_zeros(xt, 64 - 9); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; @@ -141,10 +143,12 @@ mod tests { #[test] fn test_base_sum() -> Result<()> { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let n = thread_rng().gen_range(0..(1 << 30)); let x = builder.constant(F::from_canonical_usize(n)); @@ -165,7 +169,7 @@ mod tests { builder.connect(x, y); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; diff --git a/src/gates/arithmetic_base.rs b/src/gates/arithmetic_base.rs index 93a97246..48a40b67 100644 --- a/src/gates/arithmetic_base.rs +++ b/src/gates/arithmetic_base.rs @@ -199,6 +199,7 @@ mod tests { use crate::gates::arithmetic_base::ArithmeticGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -208,7 +209,10 @@ mod tests { #[test] fn eval_fns() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let gate = ArithmeticGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/src/gates/arithmetic_extension.rs b/src/gates/arithmetic_extension.rs index d3f51cc3..c52224a2 100644 --- a/src/gates/arithmetic_extension.rs +++ b/src/gates/arithmetic_extension.rs @@ -3,7 +3,6 @@ use std::ops::Range; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::extension_field::FieldExtension; -use crate::field::field_types::RichField; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -48,7 +47,7 @@ impl ArithmeticExtensionGate { } } -impl, const D: usize> Gate for ArithmeticExtensionGate { +impl, const D: usize> Gate for ArithmeticExtensionGate { fn id(&self) -> String { format!("{:?}", self) } @@ -158,16 +157,14 @@ impl, const D: usize> Gate for ArithmeticExte } #[derive(Clone, Debug)] -struct ArithmeticExtensionGenerator, const D: usize> { +struct ArithmeticExtensionGenerator, const D: usize> { gate_index: usize, const_0: F, const_1: F, i: usize, } -impl, const D: usize> SimpleGenerator - for ArithmeticExtensionGenerator -{ +impl, const D: usize> SimpleGenerator for ArithmeticExtensionGenerator { fn dependencies(&self) -> Vec { ArithmeticExtensionGate::::wires_ith_multiplicand_0(self.i) .chain(ArithmeticExtensionGate::::wires_ith_multiplicand_1( @@ -212,6 +209,7 @@ mod tests { use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -222,8 +220,11 @@ mod tests { #[test] fn eval_fns() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let gate = ArithmeticExtensionGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/src/gates/arithmetic_u32.rs b/src/gates/arithmetic_u32.rs index d42ea320..0dc66ee9 100644 --- a/src/gates/arithmetic_u32.rs +++ b/src/gates/arithmetic_u32.rs @@ -4,7 +4,7 @@ use itertools::unfold; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -17,12 +17,12 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A gate to perform a basic mul-add on 32-bit values (we assume they are range-checked beforehand). #[derive(Copy, Clone, Debug)] -pub struct U32ArithmeticGate, const D: usize> { +pub struct U32ArithmeticGate, const D: usize> { pub num_ops: usize, _phantom: PhantomData, } -impl, const D: usize> U32ArithmeticGate { +impl, const D: usize> U32ArithmeticGate { pub fn new_from_config(config: &CircuitConfig) -> Self { Self { num_ops: Self::num_ops(config), @@ -72,7 +72,7 @@ impl, const D: usize> U32ArithmeticGate { } } -impl, const D: usize> Gate for U32ArithmeticGate { +impl, const D: usize> Gate for U32ArithmeticGate { fn id(&self) -> String { format!("{:?}", self) } @@ -258,16 +258,14 @@ impl, const D: usize> Gate for U32ArithmeticG } #[derive(Clone, Debug)] -struct U32ArithmeticGenerator, const D: usize> { +struct U32ArithmeticGenerator, const D: usize> { gate: U32ArithmeticGate, gate_index: usize, i: usize, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator - for U32ArithmeticGenerator -{ +impl, const D: usize> SimpleGenerator for U32ArithmeticGenerator { fn dependencies(&self) -> Vec { let local_target = |input| Target::wire(self.gate_index, input); @@ -329,13 +327,13 @@ mod tests { use anyhow::Result; use rand::Rng; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::arithmetic_u32::U32ArithmeticGate; use crate::gates::gate::Gate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; #[test] @@ -348,7 +346,10 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(U32ArithmeticGate:: { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(U32ArithmeticGate:: { num_ops: 3, _phantom: PhantomData, }) @@ -356,9 +357,10 @@ mod tests { #[test] fn test_gate_constraint() { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; const NUM_U32_ARITHMETIC_OPS: usize = 3; fn get_wires( diff --git a/src/gates/assert_le.rs b/src/gates/assert_le.rs index 113a5544..687699a2 100644 --- a/src/gates/assert_le.rs +++ b/src/gates/assert_le.rs @@ -440,6 +440,7 @@ mod tests { use crate::gates::gate::Gate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; #[test] @@ -481,12 +482,14 @@ mod tests { #[test] fn eval_fns() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + let num_bits = 20; let num_chunks = 4; - test_eval_fns::(AssertLessThanGate::<_, 4>::new( - num_bits, num_chunks, - )) + test_eval_fns::(AssertLessThanGate::<_, D>::new(num_bits, num_chunks)) } #[test] diff --git a/src/gates/base_sum.rs b/src/gates/base_sum.rs index 5969ae96..de8b7fb3 100644 --- a/src/gates/base_sum.rs +++ b/src/gates/base_sum.rs @@ -38,7 +38,7 @@ impl BaseSumGate { } } -impl, const D: usize, const B: usize> Gate for BaseSumGate { +impl, const D: usize, const B: usize> Gate for BaseSumGate { fn id(&self) -> String { format!("{:?} + Base: {}", self, B) } @@ -180,6 +180,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::base_sum::BaseSumGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -188,6 +189,9 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(BaseSumGate::<6>::new(11)) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(BaseSumGate::<6>::new(11)) } } diff --git a/src/gates/comparison.rs b/src/gates/comparison.rs index 164e77c8..45819cf6 100644 --- a/src/gates/comparison.rs +++ b/src/gates/comparison.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, PrimeField, RichField}; +use crate::field::field_types::{Field, PrimeField}; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -22,7 +22,7 @@ pub struct ComparisonGate, const D: usize> { _phantom: PhantomData, } -impl, const D: usize> ComparisonGate { +impl, const D: usize> ComparisonGate { pub fn new(num_bits: usize, num_chunks: usize) -> Self { debug_assert!(num_bits < bits_u64(F::ORDER)); Self { @@ -83,7 +83,7 @@ impl, const D: usize> ComparisonGate { } } -impl, const D: usize> Gate for ComparisonGate { +impl, const D: usize> Gate for ComparisonGate { fn id(&self) -> String { format!("{:?}", self, D) } @@ -374,14 +374,12 @@ impl, const D: usize> Gate for ComparisonGate } #[derive(Debug)] -struct ComparisonGenerator, const D: usize> { +struct ComparisonGenerator, const D: usize> { gate_index: usize, gate: ComparisonGate, } -impl, const D: usize> SimpleGenerator - for ComparisonGenerator -{ +impl, const D: usize> SimpleGenerator for ComparisonGenerator { fn dependencies(&self) -> Vec { let local_target = |input| Target::wire(self.gate_index, input); @@ -499,13 +497,13 @@ mod tests { use anyhow::Result; use rand::Rng; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::{Field, PrimeField}; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::comparison::ComparisonGate; use crate::gates::gate::Gate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; #[test] @@ -550,15 +548,19 @@ mod tests { fn eval_fns() -> Result<()> { let num_bits = 40; let num_chunks = 5; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; - test_eval_fns::(ComparisonGate::<_, 4>::new(num_bits, num_chunks)) + test_eval_fns::(ComparisonGate::<_, 2>::new(num_bits, num_chunks)) } #[test] fn test_gate_constraint() { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let num_bits = 40; let num_chunks = 5; diff --git a/src/gates/constant.rs b/src/gates/constant.rs index cdf8ba08..3a790ee2 100644 --- a/src/gates/constant.rs +++ b/src/gates/constant.rs @@ -2,7 +2,7 @@ use std::ops::Range; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -28,7 +28,7 @@ impl ConstantGate { } } -impl, const D: usize> Gate for ConstantGate { +impl, const D: usize> Gate for ConstantGate { fn id(&self) -> String { format!("{:?}", self) } @@ -126,6 +126,7 @@ mod tests { use crate::gates::constant::ConstantGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -136,8 +137,11 @@ mod tests { #[test] fn eval_fns() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let num_consts = CircuitConfig::standard_recursion_config().constant_gate_size; let gate = ConstantGate { num_consts }; - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/src/gates/exponentiation.rs b/src/gates/exponentiation.rs index f64b3494..ed4fd4d6 100644 --- a/src/gates/exponentiation.rs +++ b/src/gates/exponentiation.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -15,12 +15,12 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A gate for raising a value to a power. #[derive(Clone, Debug)] -pub(crate) struct ExponentiationGate, const D: usize> { +pub(crate) struct ExponentiationGate, const D: usize> { pub num_power_bits: usize, pub _phantom: PhantomData, } -impl, const D: usize> ExponentiationGate { +impl, const D: usize> ExponentiationGate { pub fn new(num_power_bits: usize) -> Self { Self { num_power_bits, @@ -60,7 +60,7 @@ impl, const D: usize> ExponentiationGate { } } -impl, const D: usize> Gate for ExponentiationGate { +impl, const D: usize> Gate for ExponentiationGate { fn id(&self) -> String { format!("{:?}", self, D) } @@ -206,14 +206,12 @@ impl, const D: usize> Gate for Exponentiation } #[derive(Debug)] -struct ExponentiationGenerator, const D: usize> { +struct ExponentiationGenerator, const D: usize> { gate_index: usize, gate: ExponentiationGate, } -impl, const D: usize> SimpleGenerator - for ExponentiationGenerator -{ +impl, const D: usize> SimpleGenerator for ExponentiationGenerator { fn dependencies(&self) -> Vec { let local_target = |input| Target::wire(self.gate_index, input); @@ -267,7 +265,6 @@ mod tests { use anyhow::Result; use rand::Rng; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::exponentiation::ExponentiationGate; @@ -275,6 +272,7 @@ mod tests { use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; use crate::util::log2_ceil; @@ -308,16 +306,20 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(ExponentiationGate::new_from_config( + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(ExponentiationGate::new_from_config( &CircuitConfig::standard_recursion_config(), )) } #[test] fn test_gate_constraint() { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; /// Returns the local wires for an exponentiation gate given the base, power, and power bit /// values. diff --git a/src/gates/gate.rs b/src/gates/gate.rs index 55b0e9b1..f31a60c2 100644 --- a/src/gates/gate.rs +++ b/src/gates/gate.rs @@ -15,7 +15,7 @@ use crate::plonk::vars::{ }; /// A custom gate. -pub trait Gate, const D: usize>: 'static + Send + Sync { +pub trait Gate, const D: usize>: 'static + Send + Sync { fn id(&self) -> String; fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec; @@ -141,9 +141,9 @@ pub trait Gate, const D: usize>: 'static + Send + S /// A wrapper around an `Rc` which implements `PartialEq`, `Eq` and `Hash` based on gate IDs. #[derive(Clone)] -pub struct GateRef, const D: usize>(pub(crate) Arc>); +pub struct GateRef, const D: usize>(pub(crate) Arc>); -impl, const D: usize> GateRef { +impl, const D: usize> GateRef { pub fn new>(gate: G) -> GateRef { GateRef(Arc::new(gate)) } diff --git a/src/gates/gate_testing.rs b/src/gates/gate_testing.rs index 2a814868..e9e823e1 100644 --- a/src/gates/gate_testing.rs +++ b/src/gates/gate_testing.rs @@ -7,6 +7,7 @@ use crate::hash::hash_types::HashOut; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; +use crate::plonk::config::GenericConfig; use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBaseBatch}; use crate::plonk::verifier::verify; use crate::polynomial::{PolynomialCoeffs, PolynomialValues}; @@ -84,7 +85,12 @@ fn random_low_degree_values(rate_bits: usize) -> Vec { .values } -pub(crate) fn test_eval_fns, G: Gate, const D: usize>( +pub(crate) fn test_eval_fns< + F: Extendable, + C: GenericConfig, + G: Gate, + const D: usize, +>( gate: G, ) -> Result<()> { // Test that `eval_unfiltered` and `eval_unfiltered_base` are coherent. @@ -150,7 +156,7 @@ pub(crate) fn test_eval_fns, G: Gate, const D let evals_t = gate.eval_unfiltered_recursively(&mut builder, vars_t); pw.set_extension_targets(&evals_t, &evals); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) } diff --git a/src/gates/gate_tree.rs b/src/gates/gate_tree.rs index c2a517d0..eb1b5ad7 100644 --- a/src/gates/gate_tree.rs +++ b/src/gates/gate_tree.rs @@ -224,7 +224,6 @@ mod tests { use log::info; use super::*; - use crate::field::goldilocks_field::GoldilocksField; use crate::gadgets::interpolation::InterpolationGate; use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::base_sum::BaseSumGate; @@ -232,12 +231,14 @@ mod tests { use crate::gates::gmimc::GMiMCGate; use crate::gates::interpolation::HighDegreeInterpolationGate; use crate::gates::noop::NoopGate; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn test_prefix_generation() { env_logger::init(); - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let gates = vec![ GateRef::new(NoopGate), diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 79a43623..d09d63dd 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::hash::gmimc; @@ -20,17 +20,11 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// It has a flag which can be used to swap the first four inputs with the next four, for ordering /// sibling digests. #[derive(Debug)] -pub struct GMiMCGate< - F: RichField + Extendable + GMiMC, - const D: usize, - const WIDTH: usize, -> { +pub struct GMiMCGate + GMiMC, const D: usize, const WIDTH: usize> { _phantom: PhantomData, } -impl + GMiMC, const D: usize, const WIDTH: usize> - GMiMCGate -{ +impl + GMiMC, const D: usize, const WIDTH: usize> GMiMCGate { pub fn new() -> Self { GMiMCGate { _phantom: PhantomData, @@ -62,7 +56,7 @@ impl + GMiMC, const D: usize, const WIDTH: u } } -impl + GMiMC, const D: usize, const WIDTH: usize> Gate +impl + GMiMC, const D: usize, const WIDTH: usize> Gate for GMiMCGate { fn id(&self) -> String { @@ -243,17 +237,13 @@ impl + GMiMC, const D: usize, const WIDTH: u } #[derive(Debug)] -struct GMiMCGenerator< - F: RichField + Extendable + GMiMC, - const D: usize, - const WIDTH: usize, -> { +struct GMiMCGenerator + GMiMC, const D: usize, const WIDTH: usize> { gate_index: usize, _phantom: PhantomData, } -impl + GMiMC, const D: usize, const WIDTH: usize> - SimpleGenerator for GMiMCGenerator +impl + GMiMC, const D: usize, const WIDTH: usize> SimpleGenerator + for GMiMCGenerator { fn dependencies(&self) -> Vec { let mut dep_input_indices = Vec::with_capacity(WIDTH + 1); @@ -341,18 +331,21 @@ mod tests { use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn generated_output() { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; const WIDTH: usize = 12; let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::new(config); - type Gate = GMiMCGate; + type Gate = GMiMCGate; let gate = Gate::new(); let gate_index = builder.add_gate(gate, vec![]); - let circuit = builder.build_prover(); + let circuit = builder.build_prover::(); let permutation_inputs = (0..WIDTH).map(F::from_canonical_usize).collect::>(); @@ -397,9 +390,11 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; const WIDTH: usize = 12; - let gate = GMiMCGate::::new(); - test_eval_fns(gate) + let gate = GMiMCGate::::new(); + test_eval_fns::(gate) } } diff --git a/src/gates/insertion.rs b/src/gates/insertion.rs index 14e77558..7f4efaa1 100644 --- a/src/gates/insertion.rs +++ b/src/gates/insertion.rs @@ -15,12 +15,12 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A gate for inserting a value into a list at a non-deterministic location. #[derive(Clone, Debug)] -pub(crate) struct InsertionGate, const D: usize> { +pub(crate) struct InsertionGate, const D: usize> { pub vec_size: usize, _phantom: PhantomData, } -impl, const D: usize> InsertionGate { +impl, const D: usize> InsertionGate { pub fn new(vec_size: usize) -> Self { Self { vec_size, @@ -70,7 +70,7 @@ impl, const D: usize> InsertionGate { } } -impl, const D: usize> Gate for InsertionGate { +impl, const D: usize> Gate for InsertionGate { fn id(&self) -> String { format!("{:?}", self, D) } @@ -324,13 +324,13 @@ mod tests { use anyhow::Result; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate::Gate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::insertion::InsertionGate; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; #[test] @@ -359,14 +359,18 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(InsertionGate::new(4)) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(InsertionGate::new(4)) } #[test] fn test_gate_constraint() { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; /// Returns the local wires for an insertion gate given the original vector, element to /// insert, and index. diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 67e3b76a..61adce4a 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -4,7 +4,6 @@ use std::ops::Range; use crate::field::extension_field::algebra::PolynomialCoeffsAlgebra; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; -use crate::field::field_types::RichField; use crate::field::interpolation::interpolant; use crate::gadgets::interpolation::InterpolationGate; use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget; @@ -21,12 +20,12 @@ use crate::polynomial::PolynomialCoeffs; /// Interpolation gate with constraints of degree at most `1<, const D: usize> { +pub(crate) struct HighDegreeInterpolationGate, const D: usize> { pub subgroup_bits: usize, _phantom: PhantomData, } -impl, const D: usize> InterpolationGate +impl, const D: usize> InterpolationGate for HighDegreeInterpolationGate { fn new(subgroup_bits: usize) -> Self { @@ -41,7 +40,7 @@ impl, const D: usize> InterpolationGate } } -impl, const D: usize> HighDegreeInterpolationGate { +impl, const D: usize> HighDegreeInterpolationGate { /// End of wire indices, exclusive. fn end(&self) -> usize { self.start_coeffs() + self.num_points() * D @@ -80,9 +79,7 @@ impl, const D: usize> HighDegreeInterpolationGate, const D: usize> Gate - for HighDegreeInterpolationGate -{ +impl, const D: usize> Gate for HighDegreeInterpolationGate { fn id(&self) -> String { format!("{:?}", self, D) } @@ -203,15 +200,13 @@ impl, const D: usize> Gate } #[derive(Debug)] -struct InterpolationGenerator, const D: usize> { +struct InterpolationGenerator, const D: usize> { gate_index: usize, gate: HighDegreeInterpolationGate, _phantom: PhantomData, } -impl, const D: usize> SimpleGenerator - for InterpolationGenerator -{ +impl, const D: usize> SimpleGenerator for InterpolationGenerator { fn dependencies(&self) -> Vec { let local_target = |input| { Target::Wire(Wire { @@ -275,7 +270,6 @@ mod tests { use anyhow::Result; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; use crate::gadgets::interpolation::InterpolationGate; @@ -283,6 +277,7 @@ mod tests { use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::interpolation::HighDegreeInterpolationGate; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; use crate::polynomial::PolynomialCoeffs; @@ -312,14 +307,18 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(HighDegreeInterpolationGate::new(2)) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(HighDegreeInterpolationGate::new(2)) } #[test] fn test_gate_constraint() { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; /// Returns the local wires for an interpolation gate for given coeffs, points and eval point. fn get_wires( diff --git a/src/gates/low_degree_interpolation.rs b/src/gates/low_degree_interpolation.rs index b5de7434..1462af3b 100644 --- a/src/gates/low_degree_interpolation.rs +++ b/src/gates/low_degree_interpolation.rs @@ -393,6 +393,7 @@ mod tests { use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::low_degree_interpolation::LowDegreeInterpolationGate; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; use crate::polynomial::PolynomialCoeffs; @@ -403,7 +404,10 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(LowDegreeInterpolationGate::new(4)) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(LowDegreeInterpolationGate::new(4)) } #[test] diff --git a/src/gates/multiplication_extension.rs b/src/gates/multiplication_extension.rs index f8845633..a2041689 100644 --- a/src/gates/multiplication_extension.rs +++ b/src/gates/multiplication_extension.rs @@ -191,6 +191,7 @@ mod tests { use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::multiplication_extension::MulExtensionGate; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -200,7 +201,10 @@ mod tests { #[test] fn eval_fns() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let gate = MulExtensionGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/src/gates/noop.rs b/src/gates/noop.rs index 0e235818..4230e678 100644 --- a/src/gates/noop.rs +++ b/src/gates/noop.rs @@ -1,6 +1,5 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::gates::gate::Gate; use crate::iop::generator::WitnessGenerator; use crate::plonk::circuit_builder::CircuitBuilder; @@ -9,7 +8,7 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBaseBa /// A gate which does nothing. pub struct NoopGate; -impl, const D: usize> Gate for NoopGate { +impl, const D: usize> Gate for NoopGate { fn id(&self) -> String { "NoopGate".into() } @@ -60,6 +59,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::noop::NoopGate; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -68,6 +68,9 @@ mod tests { #[test] fn eval_fns() -> anyhow::Result<()> { - test_eval_fns::(NoopGate) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(NoopGate) } } diff --git a/src/gates/poseidon.rs b/src/gates/poseidon.rs index 59f54707..141983e9 100644 --- a/src/gates/poseidon.rs +++ b/src/gates/poseidon.rs @@ -6,6 +6,7 @@ use crate::field::field_types::{Field, RichField}; use crate::gates::gate::Gate; use crate::gates::poseidon_mds::PoseidonMdsGate; use crate::gates::util::StridedConstraintConsumer; +use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::poseidon; use crate::hash::poseidon::Poseidon; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -21,21 +22,11 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// It has a flag which can be used to swap the first four inputs with the next four, for ordering /// sibling digests. #[derive(Debug)] -pub struct PoseidonGate< - F: RichField + Extendable + Poseidon, - const D: usize, - const WIDTH: usize, -> where - [(); WIDTH - 1]:, -{ +pub struct PoseidonGate, const D: usize> { _phantom: PhantomData, } -impl + Poseidon, const D: usize, const WIDTH: usize> - PoseidonGate -where - [(); WIDTH - 1]:, -{ +impl, const D: usize> PoseidonGate { pub fn new() -> Self { PoseidonGate { _phantom: PhantomData, @@ -49,14 +40,14 @@ where /// The wire index for the `i`th output to the permutation. pub fn wire_output(i: usize) -> usize { - WIDTH + i + SPONGE_WIDTH + i } /// If this is set to 1, the first four inputs will be swapped with the next four inputs. This /// is useful for ordering hashes in Merkle proofs. Otherwise, this should be set to 0. - pub const WIRE_SWAP: usize = 2 * WIDTH; + pub const WIRE_SWAP: usize = 2 * SPONGE_WIDTH; - const START_DELTA: usize = 2 * WIDTH + 1; + const START_DELTA: usize = 2 * SPONGE_WIDTH + 1; /// A wire which stores `swap * (input[i + 4] - input[i])`; used to compute the swapped inputs. fn wire_delta(i: usize) -> usize { @@ -74,11 +65,12 @@ where "First round S-box inputs are not stored as wires" ); debug_assert!(round < poseidon::HALF_N_FULL_ROUNDS); - debug_assert!(i < WIDTH); - Self::START_FULL_0 + WIDTH * (round - 1) + i + debug_assert!(i < SPONGE_WIDTH); + Self::START_FULL_0 + SPONGE_WIDTH * (round - 1) + i } - const START_PARTIAL: usize = Self::START_FULL_0 + WIDTH * (poseidon::HALF_N_FULL_ROUNDS - 1); + const START_PARTIAL: usize = + Self::START_FULL_0 + SPONGE_WIDTH * (poseidon::HALF_N_FULL_ROUNDS - 1); /// A wire which stores the input of the S-box of the `round`-th round of the partial rounds. fn wire_partial_sbox(round: usize) -> usize { @@ -92,23 +84,19 @@ where /// of full rounds. fn wire_full_sbox_1(round: usize, i: usize) -> usize { debug_assert!(round < poseidon::HALF_N_FULL_ROUNDS); - debug_assert!(i < WIDTH); - Self::START_FULL_1 + WIDTH * round + i + debug_assert!(i < SPONGE_WIDTH); + Self::START_FULL_1 + SPONGE_WIDTH * round + i } /// End of wire indices, exclusive. fn end() -> usize { - Self::START_FULL_1 + WIDTH * poseidon::HALF_N_FULL_ROUNDS + Self::START_FULL_1 + SPONGE_WIDTH * poseidon::HALF_N_FULL_ROUNDS } } -impl + Poseidon, const D: usize, const WIDTH: usize> Gate - for PoseidonGate -where - [(); WIDTH - 1]:, -{ +impl, const D: usize> Gate for PoseidonGate { fn id(&self) -> String { - format!("{:?}", self, WIDTH) + format!("{:?}", self, SPONGE_WIDTH) } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { @@ -127,7 +115,7 @@ where } // Compute the possibly-swapped input layer. - let mut state = [F::Extension::ZERO; WIDTH]; + let mut state = [F::Extension::ZERO; SPONGE_WIDTH]; for i in 0..4 { let delta_i = vars.local_wires[Self::wire_delta(i)]; let input_lhs = Self::wire_input(i); @@ -135,7 +123,7 @@ where state[i] = vars.local_wires[input_lhs] + delta_i; state[i + 4] = vars.local_wires[input_rhs] - delta_i; } - for i in 8..WIDTH { + for i in 8..SPONGE_WIDTH { state[i] = vars.local_wires[Self::wire_input(i)]; } @@ -143,54 +131,51 @@ where // First set of full rounds. for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer_field(&mut state, round_ctr); + ::constant_layer_field(&mut state, round_ctr); if r != 0 { - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let sbox_in = vars.local_wires[Self::wire_full_sbox_0(r, i)]; constraints.push(state[i] - sbox_in); state[i] = sbox_in; } } - >::sbox_layer_field(&mut state); - state = >::mds_layer_field(&state); + ::sbox_layer_field(&mut state); + state = ::mds_layer_field(&state); round_ctr += 1; } // Partial rounds. - >::partial_first_constant_layer(&mut state); - state = >::mds_partial_layer_init(&state); + ::partial_first_constant_layer(&mut state); + state = ::mds_partial_layer_init(&state); for r in 0..(poseidon::N_PARTIAL_ROUNDS - 1) { let sbox_in = vars.local_wires[Self::wire_partial_sbox(r)]; constraints.push(state[0] - sbox_in); - state[0] = >::sbox_monomial(sbox_in); - state[0] += F::Extension::from_canonical_u64( - >::FAST_PARTIAL_ROUND_CONSTANTS[r], - ); - state = >::mds_partial_layer_fast_field(&state, r); + state[0] = ::sbox_monomial(sbox_in); + state[0] += + F::Extension::from_canonical_u64(::FAST_PARTIAL_ROUND_CONSTANTS[r]); + state = ::mds_partial_layer_fast_field(&state, r); } let sbox_in = vars.local_wires[Self::wire_partial_sbox(poseidon::N_PARTIAL_ROUNDS - 1)]; constraints.push(state[0] - sbox_in); - state[0] = >::sbox_monomial(sbox_in); - state = >::mds_partial_layer_fast_field( - &state, - poseidon::N_PARTIAL_ROUNDS - 1, - ); + state[0] = ::sbox_monomial(sbox_in); + state = + ::mds_partial_layer_fast_field(&state, poseidon::N_PARTIAL_ROUNDS - 1); round_ctr += poseidon::N_PARTIAL_ROUNDS; // Second set of full rounds. for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer_field(&mut state, round_ctr); - for i in 0..WIDTH { + ::constant_layer_field(&mut state, round_ctr); + for i in 0..SPONGE_WIDTH { let sbox_in = vars.local_wires[Self::wire_full_sbox_1(r, i)]; constraints.push(state[i] - sbox_in); state[i] = sbox_in; } - >::sbox_layer_field(&mut state); - state = >::mds_layer_field(&state); + ::sbox_layer_field(&mut state); + state = ::mds_layer_field(&state); round_ctr += 1; } - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { constraints.push(state[i] - vars.local_wires[Self::wire_output(i)]); } @@ -215,7 +200,7 @@ where } // Compute the possibly-swapped input layer. - let mut state = [F::ZERO; WIDTH]; + let mut state = [F::ZERO; SPONGE_WIDTH]; for i in 0..4 { let delta_i = vars.local_wires[Self::wire_delta(i)]; let input_lhs = Self::wire_input(i); @@ -223,7 +208,7 @@ where state[i] = vars.local_wires[input_lhs] + delta_i; state[i + 4] = vars.local_wires[input_rhs] - delta_i; } - for i in 8..WIDTH { + for i in 8..SPONGE_WIDTH { state[i] = vars.local_wires[Self::wire_input(i)]; } @@ -231,51 +216,49 @@ where // First set of full rounds. for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer(&mut state, round_ctr); + ::constant_layer(&mut state, round_ctr); if r != 0 { - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let sbox_in = vars.local_wires[Self::wire_full_sbox_0(r, i)]; yield_constr.one(state[i] - sbox_in); state[i] = sbox_in; } } - >::sbox_layer(&mut state); - state = >::mds_layer(&state); + ::sbox_layer(&mut state); + state = ::mds_layer(&state); round_ctr += 1; } // Partial rounds. - >::partial_first_constant_layer(&mut state); - state = >::mds_partial_layer_init(&state); + ::partial_first_constant_layer(&mut state); + state = ::mds_partial_layer_init(&state); for r in 0..(poseidon::N_PARTIAL_ROUNDS - 1) { let sbox_in = vars.local_wires[Self::wire_partial_sbox(r)]; yield_constr.one(state[0] - sbox_in); - state[0] = >::sbox_monomial(sbox_in); - state[0] += - F::from_canonical_u64(>::FAST_PARTIAL_ROUND_CONSTANTS[r]); - state = >::mds_partial_layer_fast(&state, r); + state[0] = ::sbox_monomial(sbox_in); + state[0] += F::from_canonical_u64(::FAST_PARTIAL_ROUND_CONSTANTS[r]); + state = ::mds_partial_layer_fast(&state, r); } let sbox_in = vars.local_wires[Self::wire_partial_sbox(poseidon::N_PARTIAL_ROUNDS - 1)]; yield_constr.one(state[0] - sbox_in); - state[0] = >::sbox_monomial(sbox_in); - state = - >::mds_partial_layer_fast(&state, poseidon::N_PARTIAL_ROUNDS - 1); + state[0] = ::sbox_monomial(sbox_in); + state = ::mds_partial_layer_fast(&state, poseidon::N_PARTIAL_ROUNDS - 1); round_ctr += poseidon::N_PARTIAL_ROUNDS; // Second set of full rounds. for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer(&mut state, round_ctr); - for i in 0..WIDTH { + ::constant_layer(&mut state, round_ctr); + for i in 0..SPONGE_WIDTH { let sbox_in = vars.local_wires[Self::wire_full_sbox_1(r, i)]; yield_constr.one(state[i] - sbox_in); state[i] = sbox_in; } - >::sbox_layer(&mut state); - state = >::mds_layer(&state); + ::sbox_layer(&mut state); + state = ::mds_layer(&state); round_ctr += 1; } - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { yield_constr.one(state[i] - vars.local_wires[Self::wire_output(i)]); } } @@ -287,7 +270,7 @@ where ) -> Vec> { // The naive method is more efficient if we have enough routed wires for PoseidonMdsGate. let use_mds_gate = - builder.config.num_routed_wires >= PoseidonMdsGate::::new().num_wires(); + builder.config.num_routed_wires >= PoseidonMdsGate::::new().num_wires(); let mut constraints = Vec::with_capacity(self.num_constraints()); @@ -305,7 +288,7 @@ where } // Compute the possibly-swapped input layer. - let mut state = [builder.zero_extension(); WIDTH]; + let mut state = [builder.zero_extension(); SPONGE_WIDTH]; for i in 0..4 { let delta_i = vars.local_wires[Self::wire_delta(i)]; let input_lhs = vars.local_wires[Self::wire_input(i)]; @@ -313,7 +296,7 @@ where state[i] = builder.add_extension(input_lhs, delta_i); state[i + 4] = builder.sub_extension(input_rhs, delta_i); } - for i in 8..WIDTH { + for i in 8..SPONGE_WIDTH { state[i] = vars.local_wires[Self::wire_input(i)]; } @@ -321,47 +304,46 @@ where // First set of full rounds. for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer_recursive(builder, &mut state, round_ctr); + ::constant_layer_recursive(builder, &mut state, round_ctr); if r != 0 { - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let sbox_in = vars.local_wires[Self::wire_full_sbox_0(r, i)]; constraints.push(builder.sub_extension(state[i], sbox_in)); state[i] = sbox_in; } } - >::sbox_layer_recursive(builder, &mut state); - state = >::mds_layer_recursive(builder, &state); + ::sbox_layer_recursive(builder, &mut state); + state = ::mds_layer_recursive(builder, &state); round_ctr += 1; } // Partial rounds. if use_mds_gate { for r in 0..poseidon::N_PARTIAL_ROUNDS { - >::constant_layer_recursive(builder, &mut state, round_ctr); + ::constant_layer_recursive(builder, &mut state, round_ctr); let sbox_in = vars.local_wires[Self::wire_partial_sbox(r)]; constraints.push(builder.sub_extension(state[0], sbox_in)); - state[0] = >::sbox_monomial_recursive(builder, sbox_in); - state = >::mds_layer_recursive(builder, &state); + state[0] = ::sbox_monomial_recursive(builder, sbox_in); + state = ::mds_layer_recursive(builder, &state); round_ctr += 1; } } else { - >::partial_first_constant_layer_recursive(builder, &mut state); - state = >::mds_partial_layer_init_recursive(builder, &state); + ::partial_first_constant_layer_recursive(builder, &mut state); + state = ::mds_partial_layer_init_recursive(builder, &state); for r in 0..(poseidon::N_PARTIAL_ROUNDS - 1) { let sbox_in = vars.local_wires[Self::wire_partial_sbox(r)]; constraints.push(builder.sub_extension(state[0], sbox_in)); - state[0] = >::sbox_monomial_recursive(builder, sbox_in); - let c = >::FAST_PARTIAL_ROUND_CONSTANTS[r]; + state[0] = ::sbox_monomial_recursive(builder, sbox_in); + let c = ::FAST_PARTIAL_ROUND_CONSTANTS[r]; let c = F::Extension::from_canonical_u64(c); let c = builder.constant_extension(c); state[0] = builder.add_extension(state[0], c); - state = - >::mds_partial_layer_fast_recursive(builder, &state, r); + state = ::mds_partial_layer_fast_recursive(builder, &state, r); } let sbox_in = vars.local_wires[Self::wire_partial_sbox(poseidon::N_PARTIAL_ROUNDS - 1)]; constraints.push(builder.sub_extension(state[0], sbox_in)); - state[0] = >::sbox_monomial_recursive(builder, sbox_in); - state = >::mds_partial_layer_fast_recursive( + state[0] = ::sbox_monomial_recursive(builder, sbox_in); + state = ::mds_partial_layer_fast_recursive( builder, &state, poseidon::N_PARTIAL_ROUNDS - 1, @@ -371,18 +353,18 @@ where // Second set of full rounds. for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer_recursive(builder, &mut state, round_ctr); - for i in 0..WIDTH { + ::constant_layer_recursive(builder, &mut state, round_ctr); + for i in 0..SPONGE_WIDTH { let sbox_in = vars.local_wires[Self::wire_full_sbox_1(r, i)]; constraints.push(builder.sub_extension(state[i], sbox_in)); state[i] = sbox_in; } - >::sbox_layer_recursive(builder, &mut state); - state = >::mds_layer_recursive(builder, &state); + ::sbox_layer_recursive(builder, &mut state); + state = ::mds_layer_recursive(builder, &state); round_ctr += 1; } - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { constraints .push(builder.sub_extension(state[i], vars.local_wires[Self::wire_output(i)])); } @@ -395,7 +377,7 @@ where gate_index: usize, _local_constants: &[F], ) -> Vec>> { - let gen = PoseidonGenerator:: { + let gen = PoseidonGenerator:: { gate_index, _phantom: PhantomData, }; @@ -415,31 +397,27 @@ where } fn num_constraints(&self) -> usize { - WIDTH * (poseidon::N_FULL_ROUNDS_TOTAL - 1) + poseidon::N_PARTIAL_ROUNDS + WIDTH + 1 + 4 + SPONGE_WIDTH * (poseidon::N_FULL_ROUNDS_TOTAL - 1) + + poseidon::N_PARTIAL_ROUNDS + + SPONGE_WIDTH + + 1 + + 4 } } #[derive(Debug)] -struct PoseidonGenerator< - F: RichField + Extendable + Poseidon, - const D: usize, - const WIDTH: usize, -> where - [(); WIDTH - 1]:, -{ +struct PoseidonGenerator + Poseidon, const D: usize> { gate_index: usize, _phantom: PhantomData, } -impl + Poseidon, const D: usize, const WIDTH: usize> - SimpleGenerator for PoseidonGenerator -where - [(); WIDTH - 1]:, +impl + Poseidon, const D: usize> SimpleGenerator + for PoseidonGenerator { fn dependencies(&self) -> Vec { - (0..WIDTH) - .map(|i| PoseidonGate::::wire_input(i)) - .chain(Some(PoseidonGate::::WIRE_SWAP)) + (0..SPONGE_WIDTH) + .map(|i| PoseidonGate::::wire_input(i)) + .chain(Some(PoseidonGate::::WIRE_SWAP)) .map(|input| Target::wire(self.gate_index, input)) .collect() } @@ -450,19 +428,16 @@ where input, }; - let mut state = (0..WIDTH) - .map(|i| witness.get_wire(local_wire(PoseidonGate::::wire_input(i)))) + let mut state = (0..SPONGE_WIDTH) + .map(|i| witness.get_wire(local_wire(PoseidonGate::::wire_input(i)))) .collect::>(); - let swap_value = witness.get_wire(local_wire(PoseidonGate::::WIRE_SWAP)); + let swap_value = witness.get_wire(local_wire(PoseidonGate::::WIRE_SWAP)); debug_assert!(swap_value == F::ZERO || swap_value == F::ONE); for i in 0..4 { let delta_i = swap_value * (state[i + 4] - state[i]); - out_buffer.set_wire( - local_wire(PoseidonGate::::wire_delta(i)), - delta_i, - ); + out_buffer.set_wire(local_wire(PoseidonGate::::wire_delta(i)), delta_i); } if swap_value == F::ONE { @@ -471,67 +446,61 @@ where } } - let mut state: [F; WIDTH] = state.try_into().unwrap(); + let mut state: [F; SPONGE_WIDTH] = state.try_into().unwrap(); let mut round_ctr = 0; for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer_field(&mut state, round_ctr); + ::constant_layer_field(&mut state, round_ctr); if r != 0 { - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { out_buffer.set_wire( - local_wire(PoseidonGate::::wire_full_sbox_0(r, i)), + local_wire(PoseidonGate::::wire_full_sbox_0(r, i)), state[i], ); } } - >::sbox_layer_field(&mut state); - state = >::mds_layer_field(&state); + ::sbox_layer_field(&mut state); + state = ::mds_layer_field(&state); round_ctr += 1; } - >::partial_first_constant_layer(&mut state); - state = >::mds_partial_layer_init(&state); + ::partial_first_constant_layer(&mut state); + state = ::mds_partial_layer_init(&state); for r in 0..(poseidon::N_PARTIAL_ROUNDS - 1) { out_buffer.set_wire( - local_wire(PoseidonGate::::wire_partial_sbox(r)), + local_wire(PoseidonGate::::wire_partial_sbox(r)), state[0], ); - state[0] = >::sbox_monomial(state[0]); - state[0] += - F::from_canonical_u64(>::FAST_PARTIAL_ROUND_CONSTANTS[r]); - state = >::mds_partial_layer_fast_field(&state, r); + state[0] = ::sbox_monomial(state[0]); + state[0] += F::from_canonical_u64(::FAST_PARTIAL_ROUND_CONSTANTS[r]); + state = ::mds_partial_layer_fast_field(&state, r); } out_buffer.set_wire( - local_wire(PoseidonGate::::wire_partial_sbox( + local_wire(PoseidonGate::::wire_partial_sbox( poseidon::N_PARTIAL_ROUNDS - 1, )), state[0], ); - state[0] = >::sbox_monomial(state[0]); - state = >::mds_partial_layer_fast_field( - &state, - poseidon::N_PARTIAL_ROUNDS - 1, - ); + state[0] = ::sbox_monomial(state[0]); + state = + ::mds_partial_layer_fast_field(&state, poseidon::N_PARTIAL_ROUNDS - 1); round_ctr += poseidon::N_PARTIAL_ROUNDS; for r in 0..poseidon::HALF_N_FULL_ROUNDS { - >::constant_layer_field(&mut state, round_ctr); - for i in 0..WIDTH { + ::constant_layer_field(&mut state, round_ctr); + for i in 0..SPONGE_WIDTH { out_buffer.set_wire( - local_wire(PoseidonGate::::wire_full_sbox_1(r, i)), + local_wire(PoseidonGate::::wire_full_sbox_1(r, i)), state[i], ); } - >::sbox_layer_field(&mut state); - state = >::mds_layer_field(&state); + ::sbox_layer_field(&mut state); + state = ::mds_layer_field(&state); round_ctr += 1; } - for i in 0..WIDTH { - out_buffer.set_wire( - local_wire(PoseidonGate::::wire_output(i)), - state[i], - ); + for i in 0..SPONGE_WIDTH { + out_buffer.set_wire(local_wire(PoseidonGate::::wire_output(i)), state[i]); } } } @@ -551,12 +520,12 @@ mod tests { use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn wire_indices() { type F = GoldilocksField; - const WIDTH: usize = 12; - type Gate = PoseidonGate; + type Gate = PoseidonGate; assert_eq!(Gate::wire_input(0), 0); assert_eq!(Gate::wire_input(11), 11); @@ -577,20 +546,23 @@ mod tests { #[test] fn generated_output() { - type F = GoldilocksField; - const WIDTH: usize = 12; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig { num_wires: 143, ..CircuitConfig::standard_recursion_config() }; let mut builder = CircuitBuilder::new(config); - type Gate = PoseidonGate; + type Gate = PoseidonGate; let gate = Gate::new(); let gate_index = builder.add_gate(gate, vec![]); - let circuit = builder.build_prover(); + let circuit = builder.build_prover::(); - let permutation_inputs = (0..WIDTH).map(F::from_canonical_usize).collect::>(); + let permutation_inputs = (0..SPONGE_WIDTH) + .map(F::from_canonical_usize) + .collect::>(); let mut inputs = PartialWitness::new(); inputs.set_wire( @@ -600,7 +572,7 @@ mod tests { }, F::ZERO, ); - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { inputs.set_wire( Wire { gate: gate_index, @@ -612,8 +584,9 @@ mod tests { let witness = generate_partial_witness(inputs, &circuit.prover_only, &circuit.common); - let expected_outputs: [F; WIDTH] = F::poseidon(permutation_inputs.try_into().unwrap()); - for i in 0..WIDTH { + let expected_outputs: [F; SPONGE_WIDTH] = + F::poseidon(permutation_inputs.try_into().unwrap()); + for i in 0..SPONGE_WIDTH { let out = witness.get_wire(Wire { gate: 0, input: Gate::wire_output(i), @@ -625,14 +598,16 @@ mod tests { #[test] fn low_degree() { type F = GoldilocksField; - let gate = PoseidonGate::::new(); + let gate = PoseidonGate::::new(); test_low_degree(gate) } #[test] fn eval_fns() -> Result<()> { - type F = GoldilocksField; - let gate = PoseidonGate::::new(); - test_eval_fns(gate) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + let gate = PoseidonGate::::new(); + test_eval_fns::(gate) } } diff --git a/src/gates/poseidon_mds.rs b/src/gates/poseidon_mds.rs index 263c347a..da54ab2c 100644 --- a/src/gates/poseidon_mds.rs +++ b/src/gates/poseidon_mds.rs @@ -8,6 +8,7 @@ use crate::field::extension_field::FieldExtension; use crate::field::field_types::{Field, RichField}; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; +use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::poseidon::Poseidon; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::iop::target::Target; @@ -16,21 +17,11 @@ use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; #[derive(Debug)] -pub struct PoseidonMdsGate< - F: RichField + Extendable + Poseidon, - const D: usize, - const WIDTH: usize, -> where - [(); WIDTH - 1]:, -{ +pub struct PoseidonMdsGate + Poseidon, const D: usize> { _phantom: PhantomData, } -impl + Poseidon, const D: usize, const WIDTH: usize> - PoseidonMdsGate -where - [(); WIDTH - 1]:, -{ +impl + Poseidon, const D: usize> PoseidonMdsGate { pub fn new() -> Self { PoseidonMdsGate { _phantom: PhantomData, @@ -38,13 +29,13 @@ where } pub fn wires_input(i: usize) -> Range { - assert!(i < WIDTH); + assert!(i < SPONGE_WIDTH); i * D..(i + 1) * D } pub fn wires_output(i: usize) -> Range { - assert!(i < WIDTH); - (WIDTH + i) * D..(WIDTH + i + 1) * D + assert!(i < SPONGE_WIDTH); + (SPONGE_WIDTH + i) * D..(SPONGE_WIDTH + i + 1) * D } // Following are methods analogous to ones in `Poseidon`, but for extension algebras. @@ -52,15 +43,14 @@ where /// Same as `mds_row_shf` for an extension algebra of `F`. fn mds_row_shf_algebra( r: usize, - v: &[ExtensionAlgebra; WIDTH], + v: &[ExtensionAlgebra; SPONGE_WIDTH], ) -> ExtensionAlgebra { - debug_assert!(r < WIDTH); + debug_assert!(r < SPONGE_WIDTH); let mut res = ExtensionAlgebra::ZERO; - for i in 0..WIDTH { - let coeff = - F::Extension::from_canonical_u64(1 << >::MDS_MATRIX_EXPS[i]); - res += v[(i + r) % WIDTH].scalar_mul(coeff); + for i in 0..SPONGE_WIDTH { + let coeff = F::Extension::from_canonical_u64(1 << ::MDS_MATRIX_EXPS[i]); + res += v[(i + r) % SPONGE_WIDTH].scalar_mul(coeff); } res @@ -70,16 +60,16 @@ where fn mds_row_shf_algebra_recursive( builder: &mut CircuitBuilder, r: usize, - v: &[ExtensionAlgebraTarget; WIDTH], + v: &[ExtensionAlgebraTarget; SPONGE_WIDTH], ) -> ExtensionAlgebraTarget { - debug_assert!(r < WIDTH); + debug_assert!(r < SPONGE_WIDTH); let mut res = builder.zero_ext_algebra(); - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let coeff = builder.constant_extension(F::Extension::from_canonical_u64( - 1 << >::MDS_MATRIX_EXPS[i], + 1 << ::MDS_MATRIX_EXPS[i], )); - res = builder.scalar_mul_add_ext_algebra(coeff, v[(i + r) % WIDTH], res); + res = builder.scalar_mul_add_ext_algebra(coeff, v[(i + r) % SPONGE_WIDTH], res); } res @@ -87,11 +77,11 @@ where /// Same as `mds_layer` for an extension algebra of `F`. fn mds_layer_algebra( - state: &[ExtensionAlgebra; WIDTH], - ) -> [ExtensionAlgebra; WIDTH] { - let mut result = [ExtensionAlgebra::ZERO; WIDTH]; + state: &[ExtensionAlgebra; SPONGE_WIDTH], + ) -> [ExtensionAlgebra; SPONGE_WIDTH] { + let mut result = [ExtensionAlgebra::ZERO; SPONGE_WIDTH]; - for r in 0..WIDTH { + for r in 0..SPONGE_WIDTH { result[r] = Self::mds_row_shf_algebra(r, state); } @@ -101,11 +91,11 @@ where /// Same as `mds_layer_recursive` for an extension algebra of `F`. fn mds_layer_algebra_recursive( builder: &mut CircuitBuilder, - state: &[ExtensionAlgebraTarget; WIDTH], - ) -> [ExtensionAlgebraTarget; WIDTH] { - let mut result = [builder.zero_ext_algebra(); WIDTH]; + state: &[ExtensionAlgebraTarget; SPONGE_WIDTH], + ) -> [ExtensionAlgebraTarget; SPONGE_WIDTH] { + let mut result = [builder.zero_ext_algebra(); SPONGE_WIDTH]; - for r in 0..WIDTH { + for r in 0..SPONGE_WIDTH { result[r] = Self::mds_row_shf_algebra_recursive(builder, r, state); } @@ -113,17 +103,13 @@ where } } -impl + Poseidon, const D: usize, const WIDTH: usize> Gate - for PoseidonMdsGate -where - [(); WIDTH - 1]:, -{ +impl + Poseidon, const D: usize> Gate for PoseidonMdsGate { fn id(&self) -> String { - format!("{:?}", self, WIDTH) + format!("{:?}", self, SPONGE_WIDTH) } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { - let inputs: [_; WIDTH] = (0..WIDTH) + let inputs: [_; SPONGE_WIDTH] = (0..SPONGE_WIDTH) .map(|i| vars.get_local_ext_algebra(Self::wires_input(i))) .collect::>() .try_into() @@ -131,7 +117,7 @@ where let computed_outputs = Self::mds_layer_algebra(&inputs); - (0..WIDTH) + (0..SPONGE_WIDTH) .map(|i| vars.get_local_ext_algebra(Self::wires_output(i))) .zip(computed_outputs) .flat_map(|(out, computed_out)| (out - computed_out).to_basefield_array()) @@ -143,7 +129,7 @@ where vars: EvaluationVarsBase, mut yield_constr: StridedConstraintConsumer, ) { - let inputs: [_; WIDTH] = (0..WIDTH) + let inputs: [_; SPONGE_WIDTH] = (0..SPONGE_WIDTH) .map(|i| vars.get_local_ext(Self::wires_input(i))) .collect::>() .try_into() @@ -152,7 +138,7 @@ where let computed_outputs = F::mds_layer_field(&inputs); yield_constr.many( - (0..WIDTH) + (0..SPONGE_WIDTH) .map(|i| vars.get_local_ext(Self::wires_output(i))) .zip(computed_outputs) .flat_map(|(out, computed_out)| (out - computed_out).to_basefield_array()), @@ -164,7 +150,7 @@ where builder: &mut CircuitBuilder, vars: EvaluationTargets, ) -> Vec> { - let inputs: [_; WIDTH] = (0..WIDTH) + let inputs: [_; SPONGE_WIDTH] = (0..SPONGE_WIDTH) .map(|i| vars.get_local_ext_algebra(Self::wires_input(i))) .collect::>() .try_into() @@ -172,7 +158,7 @@ where let computed_outputs = Self::mds_layer_algebra_recursive(builder, &inputs); - (0..WIDTH) + (0..SPONGE_WIDTH) .map(|i| vars.get_local_ext_algebra(Self::wires_output(i))) .zip(computed_outputs) .flat_map(|(out, computed_out)| { @@ -188,12 +174,12 @@ where gate_index: usize, _local_constants: &[F], ) -> Vec>> { - let gen = PoseidonMdsGenerator:: { gate_index }; + let gen = PoseidonMdsGenerator:: { gate_index }; vec![Box::new(gen.adapter())] } fn num_wires(&self) -> usize { - 2 * D * WIDTH + 2 * D * SPONGE_WIDTH } fn num_constants(&self) -> usize { @@ -205,30 +191,22 @@ where } fn num_constraints(&self) -> usize { - WIDTH * D + SPONGE_WIDTH * D } } #[derive(Clone, Debug)] -struct PoseidonMdsGenerator -where - [(); WIDTH - 1]:, -{ +struct PoseidonMdsGenerator { gate_index: usize, } -impl + Poseidon, const D: usize, const WIDTH: usize> - SimpleGenerator for PoseidonMdsGenerator -where - [(); WIDTH - 1]:, +impl + Poseidon, const D: usize> SimpleGenerator + for PoseidonMdsGenerator { fn dependencies(&self) -> Vec { - (0..WIDTH) + (0..SPONGE_WIDTH) .flat_map(|i| { - Target::wires_from_range( - self.gate_index, - PoseidonMdsGate::::wires_input(i), - ) + Target::wires_from_range(self.gate_index, PoseidonMdsGate::::wires_input(i)) }) .collect() } @@ -239,8 +217,8 @@ where let get_local_ext = |wire_range| witness.get_extension_target(get_local_get_target(wire_range)); - let inputs: [_; WIDTH] = (0..WIDTH) - .map(|i| get_local_ext(PoseidonMdsGate::::wires_input(i))) + let inputs: [_; SPONGE_WIDTH] = (0..SPONGE_WIDTH) + .map(|i| get_local_ext(PoseidonMdsGate::::wires_input(i))) .collect::>() .try_into() .unwrap(); @@ -249,7 +227,7 @@ where for (i, &out) in outputs.iter().enumerate() { out_buffer.set_extension_target( - get_local_get_target(PoseidonMdsGate::::wires_output(i)), + get_local_get_target(PoseidonMdsGate::::wires_output(i)), out, ); } @@ -258,22 +236,25 @@ where #[cfg(test)] mod tests { - use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::poseidon_mds::PoseidonMdsGate; - use crate::hash::hashing::SPONGE_WIDTH; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { - type F = GoldilocksField; - let gate = PoseidonMdsGate::::new(); + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + let gate = PoseidonMdsGate::::new(); test_low_degree(gate) } #[test] fn eval_fns() -> anyhow::Result<()> { - type F = GoldilocksField; - let gate = PoseidonMdsGate::::new(); - test_eval_fns(gate) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + let gate = PoseidonMdsGate::::new(); + test_eval_fns::(gate) } } diff --git a/src/gates/public_input.rs b/src/gates/public_input.rs index e7b422f3..116d8917 100644 --- a/src/gates/public_input.rs +++ b/src/gates/public_input.rs @@ -2,7 +2,6 @@ use std::ops::Range; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::WitnessGenerator; @@ -18,7 +17,7 @@ impl PublicInputGate { } } -impl, const D: usize> Gate for PublicInputGate { +impl, const D: usize> Gate for PublicInputGate { fn id(&self) -> String { "PublicInputGate".into() } @@ -86,6 +85,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::public_input::PublicInputGate; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -94,6 +94,9 @@ mod tests { #[test] fn eval_fns() -> anyhow::Result<()> { - test_eval_fns::(PublicInputGate) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(PublicInputGate) } } diff --git a/src/gates/random_access.rs b/src/gates/random_access.rs index 78fbbf07..06c1274f 100644 --- a/src/gates/random_access.rs +++ b/src/gates/random_access.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; @@ -17,13 +17,13 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A gate for checking that a particular element of a list matches a given value. #[derive(Copy, Clone, Debug)] -pub(crate) struct RandomAccessGate, const D: usize> { +pub(crate) struct RandomAccessGate, const D: usize> { pub bits: usize, pub num_copies: usize, _phantom: PhantomData, } -impl, const D: usize> RandomAccessGate { +impl, const D: usize> RandomAccessGate { fn new(num_copies: usize, bits: usize) -> Self { Self { bits, @@ -79,7 +79,7 @@ impl, const D: usize> RandomAccessGate { } } -impl, const D: usize> Gate for RandomAccessGate { +impl, const D: usize> Gate for RandomAccessGate { fn id(&self) -> String { format!("{:?}", self, D) } @@ -252,15 +252,13 @@ impl, const D: usize> Gate for RandomAccessGa } #[derive(Debug)] -struct RandomAccessGenerator, const D: usize> { +struct RandomAccessGenerator, const D: usize> { gate_index: usize, gate: RandomAccessGate, copy: usize, } -impl, const D: usize> SimpleGenerator - for RandomAccessGenerator -{ +impl, const D: usize> SimpleGenerator for RandomAccessGenerator { fn dependencies(&self) -> Vec { let local_target = |input| Target::wire(self.gate_index, input); @@ -311,13 +309,13 @@ mod tests { use anyhow::Result; use rand::{thread_rng, Rng}; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate::Gate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::random_access::RandomAccessGate; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; #[test] @@ -327,14 +325,18 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(RandomAccessGate::new(4, 4)) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(RandomAccessGate::new(4, 4)) } #[test] fn test_gate_constraint() { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; /// Returns the local wires for a random access gate given the vectors, elements to compare, /// and indices. diff --git a/src/gates/reducing.rs b/src/gates/reducing.rs index b0499d82..5d918781 100644 --- a/src/gates/reducing.rs +++ b/src/gates/reducing.rs @@ -218,6 +218,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::reducing::ReducingGate; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -226,6 +227,9 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(ReducingGate::new(22)) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(ReducingGate::new(22)) } } diff --git a/src/gates/reducing_extension.rs b/src/gates/reducing_extension.rs index 1760ef48..8d06dfbd 100644 --- a/src/gates/reducing_extension.rs +++ b/src/gates/reducing_extension.rs @@ -211,6 +211,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::reducing_extension::ReducingExtensionGate; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -219,6 +220,9 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(ReducingExtensionGate::new(22)) + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(ReducingExtensionGate::new(22)) } } diff --git a/src/gates/subtraction_u32.rs b/src/gates/subtraction_u32.rs index 68f2f996..de884a24 100644 --- a/src/gates/subtraction_u32.rs +++ b/src/gates/subtraction_u32.rs @@ -323,6 +323,7 @@ mod tests { use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::subtraction_u32::U32SubtractionGate; use crate::hash::hash_types::HashOut; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; #[test] @@ -335,7 +336,10 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(U32SubtractionGate:: { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(U32SubtractionGate:: { num_ops: 3, _phantom: PhantomData, }) diff --git a/src/gates/switch.rs b/src/gates/switch.rs index 98e401b3..9026201e 100644 --- a/src/gates/switch.rs +++ b/src/gates/switch.rs @@ -4,7 +4,7 @@ use array_tool::vec::Union; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::iop::generator::{GeneratedValues, WitnessGenerator}; @@ -17,13 +17,13 @@ use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A gate for conditionally swapping input values based on a boolean. #[derive(Clone, Debug)] -pub(crate) struct SwitchGate, const D: usize> { +pub(crate) struct SwitchGate, const D: usize> { pub(crate) chunk_size: usize, pub(crate) num_copies: usize, _phantom: PhantomData, } -impl, const D: usize> SwitchGate { +impl, const D: usize> SwitchGate { pub fn new(num_copies: usize, chunk_size: usize) -> Self { Self { chunk_size, @@ -67,7 +67,7 @@ impl, const D: usize> SwitchGate { } } -impl, const D: usize> Gate for SwitchGate { +impl, const D: usize> Gate for SwitchGate { fn id(&self) -> String { format!("{:?}", self, D) } @@ -195,13 +195,13 @@ impl, const D: usize> Gate for SwitchGate, const D: usize> { +struct SwitchGenerator, const D: usize> { gate_index: usize, gate: SwitchGate, copy: usize, } -impl, const D: usize> SwitchGenerator { +impl, const D: usize> SwitchGenerator { fn in_out_dependencies(&self) -> Vec { let local_target = |input| Target::wire(self.gate_index, input); @@ -288,7 +288,7 @@ impl, const D: usize> SwitchGenerator { } } -impl, const D: usize> WitnessGenerator for SwitchGenerator { +impl, const D: usize> WitnessGenerator for SwitchGenerator { fn watch_list(&self) -> Vec { self.in_out_dependencies() .union(self.in_switch_dependencies()) @@ -313,7 +313,6 @@ mod tests { use anyhow::Result; - use crate::field::extension_field::quartic::QuarticExtension; use crate::field::field_types::Field; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate::Gate; @@ -321,6 +320,7 @@ mod tests { use crate::gates::switch::SwitchGate; use crate::hash::hash_types::HashOut; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::vars::EvaluationVars; #[test] @@ -360,7 +360,10 @@ mod tests { #[test] fn eval_fns() -> Result<()> { - test_eval_fns::(SwitchGate::<_, 4>::new_from_config( + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + test_eval_fns::(SwitchGate::<_, D>::new_from_config( &CircuitConfig::standard_recursion_config(), 3, )) @@ -368,9 +371,10 @@ mod tests { #[test] fn test_gate_constraint() { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; const CHUNK_SIZE: usize = 4; let num_copies = 3; diff --git a/src/hash/arch/aarch64/poseidon_goldilocks_neon.rs b/src/hash/arch/aarch64/poseidon_goldilocks_neon.rs index 6437818b..6736cd34 100644 --- a/src/hash/arch/aarch64/poseidon_goldilocks_neon.rs +++ b/src/hash/arch/aarch64/poseidon_goldilocks_neon.rs @@ -53,7 +53,7 @@ const fn check_mds_matrix() -> bool { let mut i = 0; let wanted_matrix_exps = [0, 0, 1, 0, 3, 5, 1, 8, 12, 3, 16, 10]; while i < WIDTH { - if >::MDS_MATRIX_EXPS[i] != wanted_matrix_exps[i] { + if ::MDS_MATRIX_EXPS[i] != wanted_matrix_exps[i] { return false; } i += 1; @@ -68,7 +68,7 @@ const fn mds_matrix_inf_norm() -> u64 { let mut cumul = 0; let mut i = 0; while i < WIDTH { - cumul += 1 << >::MDS_MATRIX_EXPS[i]; + cumul += 1 << ::MDS_MATRIX_EXPS[i]; i += 1; } cumul diff --git a/src/hash/arch/x86_64/poseidon_goldilocks_avx2_bmi2.rs b/src/hash/arch/x86_64/poseidon_goldilocks_avx2_bmi2.rs index 35c3714a..86b7edbb 100644 --- a/src/hash/arch/x86_64/poseidon_goldilocks_avx2_bmi2.rs +++ b/src/hash/arch/x86_64/poseidon_goldilocks_avx2_bmi2.rs @@ -47,7 +47,7 @@ const fn check_mds_matrix() -> bool { let mut i = 0; let wanted_matrix_exps = [0, 0, 1, 0, 3, 5, 1, 8, 12, 3, 16, 10]; while i < WIDTH { - if >::MDS_MATRIX_EXPS[i] != wanted_matrix_exps[i] { + if ::MDS_MATRIX_EXPS[i] != wanted_matrix_exps[i] { return false; } i += 1; @@ -62,7 +62,7 @@ const fn mds_matrix_inf_norm() -> u64 { let mut cumul = 0; let mut i = 0; while i < WIDTH { - cumul += 1 << >::MDS_MATRIX_EXPS[i]; + cumul += 1 << ::MDS_MATRIX_EXPS[i]; i += 1; } cumul diff --git a/src/hash/hash_types.rs b/src/hash/hash_types.rs index 0fec294b..19228b41 100644 --- a/src/hash/hash_types.rs +++ b/src/hash/hash_types.rs @@ -1,8 +1,10 @@ use rand::Rng; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::field::field_types::Field; +use crate::field::field_types::{Field, PrimeField, RichField}; use crate::iop::target::Target; +use crate::util::ceil_div_usize; +use crate::util::serialization::Buffer; /// Represents a ~256 bit hash output. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] @@ -57,6 +59,41 @@ impl Default for HashOut { } } +impl From> for HashOut { + fn from(v: Vec) -> Self { + HashOut { + elements: v + .chunks(8) + .take(4) + .map(|x| F::from_canonical_u64(u64::from_le_bytes(x.try_into().unwrap()))) + .collect::>() + .try_into() + .unwrap(), + } + } +} + +impl From> for Vec { + fn from(h: HashOut) -> Self { + h.elements + .into_iter() + .flat_map(|x| x.to_canonical_u64().to_le_bytes()) + .collect() + } +} + +impl From> for Vec { + fn from(h: HashOut) -> Self { + h.elements.to_vec() + } +} + +impl From> for u64 { + fn from(h: HashOut) -> Self { + h.elements[0].to_canonical_u64() + } +} + /// Represents a ~256 bit hash output. #[derive(Copy, Clone, Debug)] pub struct HashOutTarget { @@ -84,3 +121,51 @@ impl HashOutTarget { #[derive(Clone, Debug)] pub struct MerkleCapTarget(pub Vec); + +/// Hash consisting of a byte array. +#[derive(Eq, PartialEq, Copy, Clone, Debug)] +pub struct BytesHash(pub [u8; N]); +impl Serialize for BytesHash { + fn serialize(&self, _serializer: S) -> Result + where + S: Serializer, + { + todo!() + } +} +impl<'de, const N: usize> Deserialize<'de> for BytesHash { + fn deserialize(_deserializer: D) -> Result + where + D: Deserializer<'de>, + { + todo!() + } +} + +impl From> for BytesHash { + fn from(v: Vec) -> Self { + Self(v.try_into().unwrap()) + } +} + +impl From> for Vec { + fn from(hash: BytesHash) -> Self { + hash.0.to_vec() + } +} + +impl From> for u64 { + fn from(hash: BytesHash) -> Self { + u64::from_le_bytes(hash.0[..8].try_into().unwrap()) + } +} + +impl From> for Vec { + fn from(hash: BytesHash) -> Self { + let n = hash.0.len(); + let mut v = hash.0.to_vec(); + v.resize(ceil_div_usize(n, 8) * 8, 0); + let mut buffer = Buffer::new(v); + buffer.read_field_vec(buffer.len() / 8).unwrap() + } +} diff --git a/src/hash/hashing.rs b/src/hash/hashing.rs index 4fd537f1..4760b882 100644 --- a/src/hash/hashing.rs +++ b/src/hash/hashing.rs @@ -5,44 +5,41 @@ use crate::field::field_types::RichField; use crate::hash::hash_types::{HashOut, HashOutTarget}; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; +use crate::plonk::config::AlgebraicHasher; pub(crate) const SPONGE_RATE: usize = 8; pub(crate) const SPONGE_CAPACITY: usize = 4; pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; -pub(crate) const HASH_FAMILY: HashFamily = HashFamily::Poseidon; - -pub(crate) enum HashFamily { - #[allow(dead_code)] - GMiMC, - Poseidon, -} - /// Hash the vector if necessary to reduce its length to ~256 bits. If it already fits, this is a /// no-op. -pub fn hash_or_noop(inputs: Vec) -> HashOut { +pub fn hash_or_noop>(inputs: Vec) -> HashOut { if inputs.len() <= 4 { HashOut::from_partial(inputs) } else { - hash_n_to_hash(inputs, false) + hash_n_to_hash::(inputs, false) } } -impl, const D: usize> CircuitBuilder { - pub fn hash_or_noop(&mut self, inputs: Vec) -> HashOutTarget { +impl, const D: usize> CircuitBuilder { + pub fn hash_or_noop>(&mut self, inputs: Vec) -> HashOutTarget { let zero = self.zero(); if inputs.len() <= 4 { HashOutTarget::from_partial(inputs, zero) } else { - self.hash_n_to_hash(inputs, false) + self.hash_n_to_hash::(inputs, false) } } - pub fn hash_n_to_hash(&mut self, inputs: Vec, pad: bool) -> HashOutTarget { - HashOutTarget::from_vec(self.hash_n_to_m(inputs, 4, pad)) + pub fn hash_n_to_hash>( + &mut self, + inputs: Vec, + pad: bool, + ) -> HashOutTarget { + HashOutTarget::from_vec(self.hash_n_to_m::(inputs, 4, pad)) } - pub fn hash_n_to_m( + pub fn hash_n_to_m>( &mut self, mut inputs: Vec, num_outputs: usize, @@ -67,7 +64,7 @@ impl, const D: usize> CircuitBuilder { // where we would xor or add in the inputs. This is a well-known variant, though, // sometimes called "overwrite mode". state[..input_chunk.len()].copy_from_slice(input_chunk); - state = self.permute(state); + state = self.permute::(state); } // Squeeze until we have the desired number of outputs. @@ -79,25 +76,47 @@ impl, const D: usize> CircuitBuilder { return outputs; } } - state = self.permute(state); + state = self.permute::(state); } } } /// A one-way compression function which takes two ~256 bit inputs and returns a ~256 bit output. -pub fn compress(x: HashOut, y: HashOut) -> HashOut { +pub fn compress>(x: HashOut, y: HashOut) -> HashOut { let mut perm_inputs = [F::ZERO; SPONGE_WIDTH]; perm_inputs[..4].copy_from_slice(&x.elements); perm_inputs[4..8].copy_from_slice(&y.elements); HashOut { - elements: permute(perm_inputs)[..4].try_into().unwrap(), + elements: P::permute(perm_inputs)[..4].try_into().unwrap(), + } +} + +/// Permutation that can be used in the sponge construction for an algebraic hash. +pub trait PlonkyPermutation { + fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH]; +} + +pub struct PoseidonPermutation; +impl PlonkyPermutation for PoseidonPermutation { + fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] { + F::poseidon(input) + } +} +pub struct GMiMCPermutation; +impl PlonkyPermutation for GMiMCPermutation { + fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] { + F::gmimc_permute(input) } } /// If `pad` is enabled, the message is padded using the pad10*1 rule. In general this is required /// for the hash to be secure, but it can safely be disabled in certain cases, like if the input /// length is fixed. -pub fn hash_n_to_m(mut inputs: Vec, num_outputs: usize, pad: bool) -> Vec { +pub fn hash_n_to_m>( + mut inputs: Vec, + num_outputs: usize, + pad: bool, +) -> Vec { if pad { inputs.push(F::ZERO); while (inputs.len() + 1) % SPONGE_WIDTH != 0 { @@ -111,7 +130,7 @@ pub fn hash_n_to_m(mut inputs: Vec, num_outputs: usize, pad: bo // Absorb all input chunks. for input_chunk in inputs.chunks(SPONGE_RATE) { state[..input_chunk.len()].copy_from_slice(input_chunk); - state = permute(state); + state = P::permute(state); } // Squeeze until we have the desired number of outputs. @@ -123,21 +142,13 @@ pub fn hash_n_to_m(mut inputs: Vec, num_outputs: usize, pad: bo return outputs; } } - state = permute(state); + state = P::permute(state); } } -pub fn hash_n_to_hash(inputs: Vec, pad: bool) -> HashOut { - HashOut::from_vec(hash_n_to_m(inputs, 4, pad)) -} - -pub fn hash_n_to_1(inputs: Vec, pad: bool) -> F { - hash_n_to_m(inputs, 1, pad)[0] -} - -pub(crate) fn permute(inputs: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] { - match HASH_FAMILY { - HashFamily::GMiMC => F::gmimc_permute(inputs), - HashFamily::Poseidon => F::poseidon(inputs), - } +pub fn hash_n_to_hash>( + inputs: Vec, + pad: bool, +) -> HashOut { + HashOut::from_vec(hash_n_to_m::(inputs, 4, pad)) } diff --git a/src/hash/merkle_proofs.rs b/src/hash/merkle_proofs.rs index b5cb3b20..20654fa2 100644 --- a/src/hash/merkle_proofs.rs +++ b/src/hash/merkle_proofs.rs @@ -2,18 +2,19 @@ use anyhow::{ensure, Result}; use serde::{Deserialize, Serialize}; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; -use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; -use crate::hash::hashing::{compress, hash_or_noop, SPONGE_WIDTH}; +use crate::field::field_types::RichField; +use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget}; +use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; +use crate::plonk::config::{AlgebraicHasher, Hasher}; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(bound = "")] -pub struct MerkleProof { +pub struct MerkleProof> { /// The Merkle digest of each sibling subtree, staying from the bottommost layer. - pub siblings: Vec>, + pub siblings: Vec, } #[derive(Clone)] @@ -24,21 +25,21 @@ pub struct MerkleProofTarget { /// Verifies that the given leaf data is present at the given index in the Merkle tree with the /// given cap. -pub(crate) fn verify_merkle_proof( +pub(crate) fn verify_merkle_proof>( leaf_data: Vec, leaf_index: usize, - merkle_cap: &MerkleCap, - proof: &MerkleProof, + merkle_cap: &MerkleCap, + proof: &MerkleProof, ) -> Result<()> { let mut index = leaf_index; - let mut current_digest = hash_or_noop(leaf_data); + let mut current_digest = H::hash(leaf_data, false); for &sibling_digest in proof.siblings.iter() { let bit = index & 1; index >>= 1; current_digest = if bit == 1 { - compress(sibling_digest, current_digest) + H::two_to_one(sibling_digest, current_digest) } else { - compress(current_digest, sibling_digest) + H::two_to_one(current_digest, sibling_digest) } } ensure!( @@ -49,11 +50,11 @@ pub(crate) fn verify_merkle_proof( Ok(()) } -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Verifies that the given leaf data is present at the given index in the Merkle tree with the /// given cap. The index is given by it's little-endian bits. #[cfg(test)] - pub(crate) fn verify_merkle_proof( + pub(crate) fn verify_merkle_proof>( &mut self, leaf_data: Vec, leaf_index_bits: &[BoolTarget], @@ -61,13 +62,13 @@ impl, const D: usize> CircuitBuilder { proof: &MerkleProofTarget, ) { let zero = self.zero(); - let mut state: HashOutTarget = self.hash_or_noop(leaf_data); + let mut state: HashOutTarget = self.hash_or_noop::(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { let mut perm_inputs = [zero; SPONGE_WIDTH]; perm_inputs[..4].copy_from_slice(&state.elements); perm_inputs[4..8].copy_from_slice(&sibling.elements); - let outputs = self.permute_swapped(perm_inputs, bit); + let outputs = self.permute_swapped::(perm_inputs, bit); state = HashOutTarget::from_vec(outputs[0..4].to_vec()); } @@ -83,7 +84,7 @@ impl, const D: usize> CircuitBuilder { } /// Same as `verify_merkle_proof` but with the final "cap index" as extra parameter. - pub(crate) fn verify_merkle_proof_with_cap_index( + pub(crate) fn verify_merkle_proof_with_cap_index>( &mut self, leaf_data: Vec, leaf_index_bits: &[BoolTarget], @@ -92,13 +93,13 @@ impl, const D: usize> CircuitBuilder { proof: &MerkleProofTarget, ) { let zero = self.zero(); - let mut state = self.hash_or_noop(leaf_data); + let mut state: HashOutTarget = self.hash_or_noop::(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { let mut perm_inputs = [zero; SPONGE_WIDTH]; perm_inputs[..4].copy_from_slice(&state.elements); perm_inputs[4..8].copy_from_slice(&sibling.elements); - let perm_outs = self.permute_swapped(perm_inputs, bit); + let perm_outs = self.permute_swapped::(perm_inputs, bit); let hash_outs = perm_outs[0..4].try_into().unwrap(); state = HashOutTarget { elements: hash_outs, @@ -127,11 +128,12 @@ mod tests { use rand::{thread_rng, Rng}; use super::*; - use crate::field::goldilocks_field::GoldilocksField; + use crate::field::field_types::Field; use crate::hash::merkle_tree::MerkleTree; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn random_data(n: usize, k: usize) -> Vec> { @@ -140,16 +142,18 @@ mod tests { #[test] fn test_recursive_merkle_proof() -> Result<()> { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); + let mut builder = CircuitBuilder::::new(config); let log_n = 8; let n = 1 << log_n; let cap_height = 1; let leaves = random_data::(n, 7); - let tree = MerkleTree::new(leaves, cap_height); + let tree = MerkleTree::>::Hasher>::new(leaves, cap_height); let i: usize = thread_rng().gen_range(0..n); let proof = tree.prove(i); @@ -171,9 +175,11 @@ mod tests { pw.set_target(data[j], tree.leaves[i][j]); } - builder.verify_merkle_proof(data, &i_bits, &cap_t, &proof_t); + builder.verify_merkle_proof::<>::InnerHasher>( + data, &i_bits, &cap_t, &proof_t, + ); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/src/hash/merkle_tree.rs b/src/hash/merkle_tree.rs index 2a33a143..26a318e3 100644 --- a/src/hash/merkle_tree.rs +++ b/src/hash/merkle_tree.rs @@ -1,44 +1,49 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; -use crate::field::field_types::{Field, RichField}; -use crate::hash::hash_types::HashOut; -use crate::hash::hashing::{compress, hash_or_noop}; +use crate::field::field_types::RichField; use crate::hash::merkle_proofs::MerkleProof; +use crate::plonk::config::Hasher; /// The Merkle cap of height `h` of a Merkle tree is the `h`-th layer (from the root) of the tree. /// It can be used in place of the root to verify Merkle paths, which are `h` elements shorter. #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(bound = "")] -pub struct MerkleCap(pub Vec>); +pub struct MerkleCap>(pub Vec); -impl MerkleCap { +impl> MerkleCap { pub fn len(&self) -> usize { self.0.len() } pub fn flatten(&self) -> Vec { - self.0.iter().flat_map(|h| h.elements).collect() + self.0 + .iter() + .flat_map(|&h| { + let felts: Vec = h.into(); + felts + }) + .collect() } } #[derive(Clone, Debug)] -pub struct MerkleTree { +pub struct MerkleTree> { /// The data in the leaves of the Merkle tree. pub leaves: Vec>, /// The layers of hashes in the tree. The first layer is the one at the bottom. - pub layers: Vec>>, + pub layers: Vec>, /// The Merkle cap. - pub cap: MerkleCap, + pub cap: MerkleCap, } -impl MerkleTree { +impl> MerkleTree { pub fn new(leaves: Vec>, cap_height: usize) -> Self { let mut layers = vec![leaves .par_iter() - .map(|l| hash_or_noop(l.clone())) + .map(|l| H::hash(l.clone(), false)) .collect::>()]; while let Some(l) = layers.last() { if l.len() == 1 << cap_height { @@ -46,7 +51,7 @@ impl MerkleTree { } let next_layer = l .par_chunks(2) - .map(|chunk| compress(chunk[0], chunk[1])) + .map(|chunk| H::two_to_one(chunk[0], chunk[1])) .collect::>(); layers.push(next_layer); } @@ -63,7 +68,7 @@ impl MerkleTree { } /// Create a Merkle proof from a leaf index. - pub fn prove(&self, leaf_index: usize) -> MerkleProof { + pub fn prove(&self, leaf_index: usize) -> MerkleProof { MerkleProof { siblings: self .layers @@ -83,15 +88,19 @@ mod tests { use anyhow::Result; use super::*; - use crate::field::goldilocks_field::GoldilocksField; + use crate::field::extension_field::Extendable; use crate::hash::merkle_proofs::verify_merkle_proof; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; fn random_data(n: usize, k: usize) -> Vec> { (0..n).map(|_| F::rand_vec(k)).collect() } - fn verify_all_leaves(leaves: Vec>, n: usize) -> Result<()> { - let tree = MerkleTree::new(leaves.clone(), 1); + fn verify_all_leaves, C: GenericConfig, const D: usize>( + leaves: Vec>, + n: usize, + ) -> Result<()> { + let tree = MerkleTree::::new(leaves.clone(), 1); for i in 0..n { let proof = tree.prove(i); verify_merkle_proof(leaves[i].clone(), i, &tree.cap, &proof)?; @@ -101,13 +110,15 @@ mod tests { #[test] fn test_merkle_trees() -> Result<()> { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let log_n = 8; let n = 1 << log_n; let leaves = random_data::(n, 7); - verify_all_leaves(leaves, n)?; + verify_all_leaves::(leaves, n)?; Ok(()) } diff --git a/src/hash/path_compression.rs b/src/hash/path_compression.rs index 8b86baac..7ecbeb24 100644 --- a/src/hash/path_compression.rs +++ b/src/hash/path_compression.rs @@ -2,16 +2,16 @@ use std::collections::HashMap; use num::Integer; -use crate::field::field_types::{Field, RichField}; -use crate::hash::hashing::{compress, hash_or_noop}; +use crate::field::field_types::RichField; use crate::hash::merkle_proofs::MerkleProof; +use crate::plonk::config::Hasher; /// Compress multiple Merkle proofs on the same tree by removing redundancy in the Merkle paths. -pub(crate) fn compress_merkle_proofs( +pub(crate) fn compress_merkle_proofs>( cap_height: usize, indices: &[usize], - proofs: &[MerkleProof], -) -> Vec> { + proofs: &[MerkleProof], +) -> Vec> { assert!(!proofs.is_empty()); let height = cap_height + proofs[0].siblings.len(); let num_leaves = 1 << height; @@ -51,13 +51,13 @@ pub(crate) fn compress_merkle_proofs( /// Decompress compressed Merkle proofs. /// Note: The data and indices must be in the same order as in `compress_merkle_proofs`. -pub(crate) fn decompress_merkle_proofs( +pub(crate) fn decompress_merkle_proofs>( leaves_data: &[Vec], leaves_indices: &[usize], - compressed_proofs: &[MerkleProof], + compressed_proofs: &[MerkleProof], height: usize, cap_height: usize, -) -> Vec> { +) -> Vec> { let num_leaves = 1 << height; let compressed_proofs = compressed_proofs.to_vec(); let mut decompressed_proofs = Vec::with_capacity(compressed_proofs.len()); @@ -66,7 +66,7 @@ pub(crate) fn decompress_merkle_proofs( for (&i, v) in leaves_indices.iter().zip(leaves_data) { // Observe the leaves. - seen.insert(i + num_leaves, hash_or_noop(v.to_vec())); + seen.insert(i + num_leaves, H::hash(v.to_vec(), false)); } // Iterators over the siblings. @@ -84,9 +84,9 @@ pub(crate) fn decompress_merkle_proofs( .entry(sibling_index) .or_insert_with(|| *p.next().unwrap()); let parent_hash = if index.is_even() { - compress(current_hash, sibling_hash) + H::two_to_one(current_hash, sibling_hash) } else { - compress(sibling_hash, current_hash) + H::two_to_one(sibling_hash, current_hash) }; seen.insert(index >> 1, parent_hash); } @@ -116,16 +116,18 @@ mod tests { use super::*; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::hash::merkle_tree::MerkleTree; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn test_path_compression() { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let h = 10; let cap_height = 3; let vs = (0..1 << h).map(|_| vec![F::rand()]).collect::>(); - let mt = MerkleTree::new(vs.clone(), cap_height); + let mt = MerkleTree::>::Hasher>::new(vs.clone(), cap_height); let mut rng = thread_rng(); let k = rng.gen_range(1..=1 << h); diff --git a/src/hash/poseidon.rs b/src/hash/poseidon.rs index 8572143a..b00bfbce 100644 --- a/src/hash/poseidon.rs +++ b/src/hash/poseidon.rs @@ -5,9 +5,10 @@ use unroll::unroll_for_loops; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; -use crate::field::field_types::{Field, PrimeField, RichField}; +use crate::field::field_types::{Field, PrimeField}; use crate::gates::gate::Gate; use crate::gates::poseidon_mds::PoseidonMdsGate; +use crate::hash::hashing::SPONGE_WIDTH; use crate::plonk::circuit_builder::CircuitBuilder; // The number of full rounds and partial rounds is given by the @@ -142,11 +143,8 @@ pub const ALL_ROUND_CONSTANTS: [u64; MAX_WIDTH * N_ROUNDS] = [ 0x4543d9df72c4831d, 0xf172d73e69f20739, 0xdfd1c4ff1eb3d868, 0xbc8dfb62d26376f7, ]; -pub trait Poseidon: PrimeField -where - // magic to get const generic expressions to work - [(); WIDTH - 1]:, -{ +const WIDTH: usize = SPONGE_WIDTH; +pub trait Poseidon: PrimeField { // Total number of round constants required: width of the input // times number of rounds. const N_ROUND_CONSTANTS: usize = WIDTH * N_ROUNDS; @@ -176,7 +174,6 @@ where let mut res = 0u128; // This is a hacky way of fully unrolling the loop. - assert!(WIDTH <= 12); for i in 0..12 { if i < WIDTH { res += (v[(i + r) % WIDTH] as u128) << Self::MDS_MATRIX_EXPS[i]; @@ -208,13 +205,13 @@ where v: &[ExtensionTarget; WIDTH], ) -> ExtensionTarget where - Self: RichField + Extendable, + Self: Extendable, { debug_assert!(r < WIDTH); let mut res = builder.zero_extension(); for i in 0..WIDTH { - let c = Self::from_canonical_u64(1 << >::MDS_MATRIX_EXPS[i]); + let c = Self::from_canonical_u64(1 << ::MDS_MATRIX_EXPS[i]); res = builder.mul_const_add_extension(c, v[(i + r) % WIDTH], res); } @@ -232,7 +229,6 @@ where } // This is a hacky way of fully unrolling the loop. - assert!(WIDTH <= 12); for r in 0..12 { if r < WIDTH { let sum = Self::mds_row_shf(r, &state); @@ -264,19 +260,19 @@ where state: &[ExtensionTarget; WIDTH], ) -> [ExtensionTarget; WIDTH] where - Self: RichField + Extendable, + Self: Extendable, { // If we have enough routed wires, we will use PoseidonMdsGate. - let mds_gate = PoseidonMdsGate::::new(); + let mds_gate = PoseidonMdsGate::::new(); if builder.config.num_routed_wires >= mds_gate.num_wires() { let index = builder.add_gate(mds_gate, vec![]); for i in 0..WIDTH { - let input_wire = PoseidonMdsGate::::wires_input(i); + let input_wire = PoseidonMdsGate::::wires_input(i); builder.connect_extension(state[i], ExtensionTarget::from_range(index, input_wire)); } (0..WIDTH) .map(|i| { - let output_wire = PoseidonMdsGate::::wires_output(i); + let output_wire = PoseidonMdsGate::::wires_output(i); ExtensionTarget::from_range(index, output_wire) }) .collect::>() @@ -298,7 +294,6 @@ where fn partial_first_constant_layer, const D: usize>( state: &mut [F; WIDTH], ) { - assert!(WIDTH <= 12); for i in 0..12 { if i < WIDTH { state[i] += F::from_canonical_u64(Self::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]); @@ -311,10 +306,10 @@ where builder: &mut CircuitBuilder, state: &mut [ExtensionTarget; WIDTH], ) where - Self: RichField + Extendable, + Self: Extendable, { for i in 0..WIDTH { - let c = >::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]; + let c = ::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]; let c = Self::Extension::from_canonical_u64(c); let c = builder.constant_extension(c); state[i] = builder.add_extension(state[i], c); @@ -333,10 +328,8 @@ where // c = 0 result[0] = state[0]; - assert!(WIDTH <= 12); for r in 1..12 { if r < WIDTH { - assert!(WIDTH <= 12); for c in 1..12 { if c < WIDTH { // NB: FAST_PARTIAL_ROUND_INITIAL_MATRIX is stored in @@ -359,7 +352,7 @@ where state: &[ExtensionTarget; WIDTH], ) -> [ExtensionTarget; WIDTH] where - Self: RichField + Extendable, + Self: Extendable, { let mut result = [builder.zero_extension(); WIDTH]; @@ -367,7 +360,7 @@ where for r in 1..WIDTH { for c in 1..WIDTH { - let t = >::FAST_PARTIAL_ROUND_INITIAL_MATRIX[r - 1][c - 1]; + let t = ::FAST_PARTIAL_ROUND_INITIAL_MATRIX[r - 1][c - 1]; let t = Self::Extension::from_canonical_u64(t); let t = builder.constant_extension(t); result[c] = builder.mul_add_extension(t, state[r], result[c]); @@ -390,7 +383,6 @@ where // Set d = [M_00 | w^] dot [state] let mut d_sum = (0u128, 0u32); // u160 accumulator - assert!(WIDTH <= 12); for i in 1..12 { if i < WIDTH { let t = Self::FAST_PARTIAL_ROUND_W_HATS[r][i - 1] as u128; @@ -405,7 +397,6 @@ where // result = [d] concat [state[0] * v + state[shift up by 1]] let mut result = [Self::ZERO; WIDTH]; result[0] = d; - assert!(WIDTH <= 12); for i in 1..12 { if i < WIDTH { let t = Self::from_canonical_u64(Self::FAST_PARTIAL_ROUND_VS[r][i - 1]); @@ -444,15 +435,15 @@ where r: usize, ) -> [ExtensionTarget; WIDTH] where - Self: RichField + Extendable, + Self: Extendable, { let s0 = state[0]; let mut d = builder.mul_const_extension( - Self::from_canonical_u64(1 << >::MDS_MATRIX_EXPS[0]), + Self::from_canonical_u64(1 << ::MDS_MATRIX_EXPS[0]), s0, ); for i in 1..WIDTH { - let t = >::FAST_PARTIAL_ROUND_W_HATS[r][i - 1]; + let t = ::FAST_PARTIAL_ROUND_W_HATS[r][i - 1]; let t = Self::Extension::from_canonical_u64(t); let t = builder.constant_extension(t); d = builder.mul_add_extension(t, state[i], d); @@ -461,7 +452,7 @@ where let mut result = [builder.zero_extension(); WIDTH]; result[0] = d; for i in 1..WIDTH { - let t = >::FAST_PARTIAL_ROUND_VS[r][i - 1]; + let t = ::FAST_PARTIAL_ROUND_VS[r][i - 1]; let t = Self::Extension::from_canonical_u64(t); let t = builder.constant_extension(t); result[i] = builder.mul_add_extension(t, state[0], state[i]); @@ -472,7 +463,6 @@ where #[inline(always)] #[unroll_for_loops] fn constant_layer(state: &mut [Self; WIDTH], round_ctr: usize) { - assert!(WIDTH <= 12); for i in 0..12 { if i < WIDTH { let round_constant = ALL_ROUND_CONSTANTS[i + WIDTH * round_ctr]; @@ -499,7 +489,7 @@ where state: &mut [ExtensionTarget; WIDTH], round_ctr: usize, ) where - Self: RichField + Extendable, + Self: Extendable, { for i in 0..WIDTH { let c = ALL_ROUND_CONSTANTS[i + WIDTH * round_ctr]; @@ -524,7 +514,7 @@ where x: ExtensionTarget, ) -> ExtensionTarget where - Self: RichField + Extendable, + Self: Extendable, { // x |--> x^7 builder.exp_u64_extension(x, 7) @@ -533,7 +523,6 @@ where #[inline(always)] #[unroll_for_loops] fn sbox_layer(state: &mut [Self; WIDTH]) { - assert!(WIDTH <= 12); for i in 0..12 { if i < WIDTH { state[i] = Self::sbox_monomial(state[i]); @@ -555,10 +544,10 @@ where builder: &mut CircuitBuilder, state: &mut [ExtensionTarget; WIDTH], ) where - Self: RichField + Extendable, + Self: Extendable, { for i in 0..WIDTH { - state[i] = >::sbox_monomial_recursive(builder, state[i]); + state[i] = ::sbox_monomial_recursive(builder, state[i]); } } @@ -628,39 +617,38 @@ where #[cfg(test)] pub(crate) mod test_helpers { use crate::field::field_types::Field; + use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::poseidon::Poseidon; - pub(crate) fn check_test_vectors( - test_vectors: Vec<([u64; WIDTH], [u64; WIDTH])>, + pub(crate) fn check_test_vectors( + test_vectors: Vec<([u64; SPONGE_WIDTH], [u64; SPONGE_WIDTH])>, ) where - F: Poseidon, - [(); WIDTH - 1]:, + F: Poseidon, { for (input_, expected_output_) in test_vectors.into_iter() { - let mut input = [F::ZERO; WIDTH]; - for i in 0..WIDTH { + let mut input = [F::ZERO; SPONGE_WIDTH]; + for i in 0..SPONGE_WIDTH { input[i] = F::from_canonical_u64(input_[i]); } let output = F::poseidon(input); - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let ex_output = F::from_canonical_u64(expected_output_[i]); assert_eq!(output[i], ex_output); } } } - pub(crate) fn check_consistency() + pub(crate) fn check_consistency() where - F: Poseidon, - [(); WIDTH - 1]:, + F: Poseidon, { - let mut input = [F::ZERO; WIDTH]; - for i in 0..WIDTH { + let mut input = [F::ZERO; SPONGE_WIDTH]; + for i in 0..SPONGE_WIDTH { input[i] = F::from_canonical_u64(i as u64); } let output = F::poseidon(input); let output_naive = F::poseidon_naive(input); - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { assert_eq!(output[i], output_naive[i]); } } diff --git a/src/hash/poseidon_crandall.rs b/src/hash/poseidon_crandall.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/hash/poseidon_crandall.rs @@ -0,0 +1 @@ + diff --git a/src/hash/poseidon_goldilocks.rs b/src/hash/poseidon_goldilocks.rs index 0b1f9a49..4c4221ee 100644 --- a/src/hash/poseidon_goldilocks.rs +++ b/src/hash/poseidon_goldilocks.rs @@ -8,147 +8,7 @@ use crate::field::goldilocks_field::GoldilocksField; use crate::hash::poseidon::{Poseidon, N_PARTIAL_ROUNDS}; #[rustfmt::skip] -impl Poseidon<8> for GoldilocksField { - // The MDS matrix we use is the circulant matrix with first row given by the vector - // [ 2^x for x in MDS_MATRIX_EXPS] = [1, 1, 2, 1, 8, 32, 4, 256] - // - // WARNING: If the MDS matrix is changed, then the following - // constants need to be updated accordingly: - // - FAST_PARTIAL_ROUND_CONSTANTS - // - FAST_PARTIAL_ROUND_VS - // - FAST_PARTIAL_ROUND_W_HATS - // - FAST_PARTIAL_ROUND_INITIAL_MATRIX - const MDS_MATRIX_EXPS: [u64; 8] = [0, 0, 1, 0, 3, 5, 2, 8]; - - const FAST_PARTIAL_FIRST_ROUND_CONSTANT: [u64; 8] = [ - 0x66bbd30e99d311da, 0xac0494d706139435, 0x7eea5812cb4c5eb2, 0x6061af64681ce880, - 0xfce86220df80ac43, 0x5285da71ebb7b008, 0x8649956f6d44d2a2, 0xcf8c90ab81a0ca0a, - ]; - - const FAST_PARTIAL_ROUND_CONSTANTS: [u64; N_PARTIAL_ROUNDS] = [ - 0xd3e8f03df7f0d35c, 0x3ef0eeeed58f09f7, 0x6b54f9fd0ecdfa58, 0x129f9c79c53051f4, - 0xe0ee72d960a7c705, 0x2dc8a0d0d92c1497, 0x6936412d8980befa, 0x64f44cf4c7211138, - 0xcd28551a527e2472, 0x71c8b45ae08e543e, 0xcbde77e27af5b694, 0xab4d6a7cbb49e2f0, - 0xaaef22c4753df029, 0x4889f5d08dbf0f1f, 0x5fa33b282603eb65, 0x86661e9507022660, - 0x3e31490d4eeb1d9f, 0xc581d1f6d84c6485, 0x77e61c9742a20dd3, 0x9edc0491219ecb5c, - 0x5b846917f2f767eb, 0x0, - ]; - - const FAST_PARTIAL_ROUND_VS: [[u64; 8 - 1]; N_PARTIAL_ROUNDS] = [ - [0xb9af2750293b9624, 0x1148fcc5cbe27c57, 0x174a9735f87d5b66, 0x9ade5dad416cccfa, - 0x191867d7fd58636a, 0x1018a176ac6b8850, 0x6baa69bf6caac2f7, ], - [0x5d3a3be85300d127, 0x602d9345fdb2950b, 0xa71b08e14841259d, 0x8c9e66a88cfc2a2f, - 0xd23f18447b9d6ca6, 0x9c7b63750e75136d, 0xc0036bb483def9f6, ], - [0xd8e171f97120488d, 0x963ace7d45dd3534, 0xe1110876d0920bb1, 0xc2554b2a73562b4d, - 0x25c5559e1da9b854, 0xfd6a3146495a05e8, 0x238d725e9bbea44f, ], - [0xf64bc8099412ee92, 0x43a6897f45dac19e, 0xca7101923a589502, 0x142f002e59b5c266, - 0xf03ceac54cef3438, 0x66b181f8f5003148, 0xa771a1eef052f853, ], - [0x9d4b9376927960be, 0x99543e4c8809ec7d, 0x86b30b2577e74c74, 0x5bc8aeabd7389991, - 0xcb9c2b7e2f4ec665, 0x0de73a3c82e91199, 0x0f2d2370f6bc0228, ], - [0x253dd236fc5e4f15, 0x3ec881b20a588043, 0xbc42663d732126fe, 0xe3e6fa02e77ad144, - 0x04b1e0459ba85bbf, 0x6550e387f467aee7, 0xc34b817494f32dd8, ], - [0xd9423529e3d9b44e, 0x327e2609b24d5a59, 0x9ab352e6581fd735, 0x95a6a4e5dd94aefc, - 0x44f860fc8a140181, 0x10fe3ee72bbaf4bc, 0x41b951dfc4190fe2, ], - [0x931b2f16aae2cb8d, 0xb2cd58604bb14653, 0xe68e709a8bcb1228, 0x286b1cb1bdd94d41, - 0xaf3f0e1f41093ffd, 0xcc00f393df3aef69, 0x68eeb30cca0b90fe, ], - [0xcfbc82fae1248b3c, 0xaea4f7382d6e7d1a, 0xfe46b0ab3d6e3160, 0xa7ee349ec637bfd2, - 0xdf5f1ba6dbafdcba, 0xe8d6bcc2b7545ece, 0xd69b6a4d64cc3850, ], - [0xb3057004d66998c6, 0xb9e5e008d480602e, 0xcb401bc12a68178a, 0x9b0c25e0fec9c9ca, - 0x27903301fe272833, 0x5ab55e67746531c9, 0xa785dc1e593047b1, ], - [0xeba6857b4e021502, 0x44325a11dccd4da2, 0xfe061fabb725e7ed, 0x88ade6bf344c857e, - 0xa576bd9fdcb3b259, 0xedeae5b8be128b60, 0x0557f1891844b88a, ], - [0x94c66397aee8b97f, 0x25ac4cb55737667d, 0xc1f035a5dd2d4cc8, 0x916533f52e8205d6, - 0xf564f659b15f376a, 0x9f0032cd56a4328f, 0xa4300a553fe15224, ], - [0xe2a4c0486179d0cb, 0x3c92c7272c4536fd, 0xc08233d9a1db1814, 0x774b36b64d2fb890, - 0xf47210158dfda27b, 0xe44f205f72b1572a, 0x93f2ac3eb28af404, ], - [0x2c657b307f0dbbae, 0xbc8c7fbae563049b, 0xb459200f00172a5e, 0x90e04fdc6dfeccda, - 0x2c0369901c0cc5ea, 0xe0ef32f033d13298, 0x2087a2aecd13db2f, ], - [0x0841fbc2bf24a2b1, 0x44eb9cb920d24a43, 0x23c415122043afc5, 0x313ece0eb0f7b6d6, - 0x273938954c49858c, 0x1dcb6a4a6cf06e6d, 0x1cce7720eb4f6f98, ], - [0x0022555dbdafaac1, 0x001a5afeb9fc4888, 0x002b1f1ca992d571, 0x001fee5206bf439e, - 0x0015d27e30a1621e, 0x0015b6f958368106, 0x010a6aef986e23ce, ], - [0x00000de86b7a238e, 0x000028a51289c2f5, 0x00001b440277fe8a, 0x00000e8e3ea5103e, - 0x00000f9bc91bcf75, 0x0001071dda899dbf, 0x00001e48188120d9, ], - [0x000000126ca1da48, 0x00000013b4d8fc12, 0x0000000a11cf6ba0, 0x0000000a092e06b0, - 0x00000104497e1ca3, 0x00000017ca90627c, 0x000000a21fcd4eab, ], - [0x0000000008bc9a2d, 0x00000000070e1ecf, 0x0000000006989bf1, 0x0000000102279912, - 0x0000000012063786, 0x00000000811f1acd, 0x00000000265a4ea2, ], - [0x000000000002bb2f, 0x0000000000042512, 0x0000000001010c47, 0x00000000000ccc46, - 0x0000000000607b8a, 0x00000000001b1d04, 0x00000000000fd612, ], - [0x0000000000000198, 0x0000000000010065, 0x0000000000000834, 0x000000000000401e, - 0x0000000000001105, 0x0000000000000643, 0x0000000000000609, ], - [0x0000000000000100, 0x0000000000000004, 0x0000000000000020, 0x0000000000000008, - 0x0000000000000001, 0x0000000000000002, 0x0000000000000001, ], - ]; - - const FAST_PARTIAL_ROUND_W_HATS: [[u64; 8 - 1]; N_PARTIAL_ROUNDS] = [ - [0x269b1eb39549a1db, 0x9c2f7295da6fe4ed, 0x1cb34e7859012514, 0x28d524012a1c29c2, - 0x40eaef552e8ec873, 0x1ba83ec01c4ad111, 0xb97f43b8c7379659, ], - [0x797db014cbe89c21, 0xcd8cbe2d94b66eea, 0x1feab2f1f7800637, 0x2dfb3dfab42d3c95, - 0x026ae799f7199a65, 0xff13e93bac5ccd21, 0x85c7c686d5e86fa8, ], - [0x63491cb6f6f9b060, 0xb56e5bf1cd5c5985, 0xf617c6646887cd04, 0x82ad2d36291e4b2c, - 0x34be211a42b111f4, 0xe1427b350e8789bb, 0x4e90daa4a7162d86, ], - [0x23ff08f88b78428a, 0x2b9b6a866210f36c, 0x8f1452c156899e05, 0x5c312425f14e4701, - 0xf010bd4be5eb43dd, 0xb6e3d8976c435cd0, 0x07aae99f2fce8073, ], - [0xc89ef5941b95831b, 0x95931df88bb238d9, 0x0de74ab8bc5ec419, 0x4825380b2d936c13, - 0xb88277e244b69fb6, 0x76114374d9652c44, 0x76ed6bba7d8313c1, ], - [0xc000f50a6bd73faf, 0x9dd8304a9bd9f1b6, 0xb58e0b5e3e40bb29, 0x823c1c7be983035e, - 0xe3fa343aae9e7831, 0x7aa8d38188f752cb, 0xea42c23ed57c33c0, ], - [0x24ecf72c180fc92b, 0x33a4dbfddf7e373b, 0x469df558ba1261c2, 0x60ab4f0f3d2ad4c8, - 0xc110cb1c5c7a7a88, 0x4a4baf941ec7cf67, 0x16965340c1d488ef, ], - [0x79a95b95aa2fd971, 0x04419bf145fd6a4a, 0x71d788554e0d115d, 0x4044371afe7450e1, - 0xb00d7baa7ce81dd6, 0xe46a1479821e235b, 0x80edef59f7553c3f, ], - [0xf1dc222706620f79, 0xfc7232469c59f586, 0x028aef7f4ec9d3d4, 0xf12a3b4e5de9facb, - 0x135973e4aa6b1253, 0xcbff3378151eb32e, 0x034c61764a8d260a, ], - [0x00e52733564fcee6, 0x0c5b3ad3251ccdf4, 0xf49fffc683ce919b, 0xd17292effcfbaa02, - 0xa151d073be3aeb67, 0x2faf5b05065f340f, 0x513705952d8185c8, ], - [0x399e416f7506e439, 0xebf6618c65c571f5, 0x7a4348f382135c3a, 0x171cc2b625ec95f9, - 0x63bff2edafa923af, 0x1f0aa3a5b6c61920, 0xc8f889e2c89fc18c, ], - [0xcba09835c5a7c1fc, 0xfe9ca6a5f9cfe7f5, 0xae51732c9ae24e99, 0xfe19c95080c5fed7, - 0x56d181fad0512be3, 0xb74c82e5a32566eb, 0xfdff5523a2096934, ], - [0x4e9d731c839a6384, 0xa6ab3d286a385a74, 0x92c9a99c9c3d66f1, 0xe3e3cd56f3de8405, - 0x51afd4ef5b764ecc, 0x20f06b5b9cc5911a, 0xd5ab74758e45a1e9, ], - [0x1b40e9633dbe3e6a, 0x61aaf01dddefc2a2, 0xcca587c064e6fa34, 0xfba6904b9a40507b, - 0xbdd6f9280d82b8c2, 0x81ae47de86e77b1a, 0x240a15880d36689b, ], - [0x26136c701690ea6f, 0xfd69557e6072cfb7, 0x58d824017b513eb9, 0x05d7dafb3de8cf5e, - 0xcceb095959c76f7d, 0x83021ef00b804c28, 0x249ac764258cc526, ], - [0xe154d3c75894d969, 0xed0d19dd7a62c62d, 0x33098c41f542ad56, 0x0a00d8de37b9e97e, - 0x4701f379b9cc1b8d, 0xfcf4a08ebee38a80, 0x538455bf65ac55e5, ], - [0xd6bce6dee03ffd40, 0x1b595cc58ad8b6cd, 0x3a57b9cfcbbd1181, 0x5eca20dbf78b6fdf, - 0xf17b83b69550c7ba, 0xa25ad9bb6f6d696f, 0xa7c0a32028a396cd, ], - [0x7074ed0a4493e0cb, 0xaf007f0e547fcdae, 0x1c9a20122a92a480, 0xa394fda7dc2a248c, - 0x9011f48bc126c4ef, 0xfecd3befc1ee4d0b, 0x24b9a7dbf43d5a2b, ], - [0x1ecc6172a78fda5a, 0x654b8deec4e920d2, 0x813eb0e016ae4570, 0x3303807aaa79ad24, - 0xffa5a9ee2ad77929, 0x32ecc1c7d9d0b127, 0x6df4612b0b81b271, ], - [0xdbc7f712822f4575, 0x88e67f35f99b7fe1, 0xf37566abe5e5dbc1, 0xcd8eca65a17c493f, - 0x3568726b02cd955b, 0x1221e6d90b408c61, 0x01c8c201d650b222, ], - [0x02ed134db31e582d, 0x503692ee719f6add, 0xeadaef5785f69755, 0x98ab6d6ac1763ac2, - 0x7a12232114fa6b11, 0x5f1232b59a635f7f, 0x73e5509bf404a257, ], - [0x11c759d7c36ae70a, 0x3f7bfed8879b0281, 0x56127c65148822bd, 0x31f695e2c256d94e, - 0x31da9505206208ba, 0xb9fdbd9aada98a78, 0xc9255cd2a9ee89a3, ], - ]; - - // NB: This is in ROW-major order to support cache-friendly pre-multiplication. - const FAST_PARTIAL_ROUND_INITIAL_MATRIX: [[u64; 8 - 1]; 8 - 1] = [ - [0x44f68560bbf3e205, 0x22f2a0308e9c911f, 0x2cf2fc34afb5e90d, 0xdfd3820dd14dca23, - 0xc8cedeb0115d4cb9, 0xa7e9f1e59b2ace9e, 0x551386ca3a31ccb4, ], - [0xb4257d684cc96d30, 0x6918b8409b32d75b, 0xf42a3433a147167a, 0xaf91167a1880c1b1, - 0xa56b1fba7844632a, 0x27a3a6aa3cd42312, 0xa7e9f1e59b2ace9e, ], - [0xeb1bdec94099409a, 0x8666bcbe8366cb0f, 0x60aa4f11c97e774d, 0x9e0d98f4429fc32b, - 0xb428d8df399e3344, 0xa56b1fba7844632a, 0xc8cedeb0115d4cb9, ], - [0x67ba59d3d88a20df, 0x1d448e0422470936, 0x159c5a4decc6b1f9, 0x3f4325c2395f5587, - 0x9e0d98f4429fc32b, 0xaf91167a1880c1b1, 0xdfd3820dd14dca23, ], - [0x22c4f8e67637ae91, 0x1c0d1308d0a0148d, 0xa0ce3dcce54586f7, 0x159c5a4decc6b1f9, - 0x60aa4f11c97e774d, 0xf42a3433a147167a, 0x2cf2fc34afb5e90d, ], - [0xfb640823e5ee3bac, 0xdb990b6d9cf010db, 0x1c0d1308d0a0148d, 0x1d448e0422470936, - 0x8666bcbe8366cb0f, 0x6918b8409b32d75b, 0x22f2a0308e9c911f, ], - [0x8cf5bd0b11cfcdf1, 0xfb640823e5ee3bac, 0x22c4f8e67637ae91, 0x67ba59d3d88a20df, - 0xeb1bdec94099409a, 0xb4257d684cc96d30, 0x44f68560bbf3e205, ], - ]; -} - -#[rustfmt::skip] -impl Poseidon<12> for GoldilocksField { +impl Poseidon for GoldilocksField { // The MDS matrix we use is the circulant matrix with first row given by the vector // [ 2^x for x in MDS_MATRIX_EXPS] = [1, 1, 2, 1, 8, 32, 2, 256, 4096, 8, 65536, 1024] // @@ -425,7 +285,7 @@ mod tests { let neg_one: u64 = F::NEG_ONE.to_canonical_u64(); #[rustfmt::skip] - let test_vectors8: Vec<([u64; 8], [u64; 8])> = vec![ + let _test_vectors8: Vec<([u64; 8], [u64; 8])> = vec![ ([0, 0, 0, 0, 0, 0, 0, 0, ], [0x649eec3229475d06, 0x72afe85b8b600222, 0x816d0a50ddd39228, 0x5083133a721a187c, 0xbb69bd7d90c490a6, 0xea1d33a65d0a3287, 0xb4d27542d2fba3bc, 0xf9756d565d90c20a, ]), @@ -442,8 +302,6 @@ mod tests { 0x37804ed8ca07fcd5, 0xe78ec2f213e28456, 0xecf67d2aacb4dbe3, 0xad14575187c496ca, ]), ]; - check_test_vectors::(test_vectors8); - #[rustfmt::skip] let test_vectors12: Vec<([u64; 12], [u64; 12])> = vec![ ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], @@ -468,12 +326,11 @@ mod tests { 0x27eca78818ef9c27, 0xf08c93583c24dc47, 0x1c9e1552c07a9f73, 0x7659179192cfdc88, ]), ]; - check_test_vectors::(test_vectors12); + check_test_vectors::(test_vectors12); } #[test] fn consistency() { - check_consistency::(); - check_consistency::(); + check_consistency::(); } } diff --git a/src/iop/challenger.rs b/src/iop/challenger.rs index bd990c6d..1e2cd293 100644 --- a/src/iop/challenger.rs +++ b/src/iop/challenger.rs @@ -1,19 +1,24 @@ +use std::convert::TryInto; +use std::marker::PhantomData; + use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field_types::RichField; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget}; -use crate::hash::hashing::{permute, SPONGE_RATE, SPONGE_WIDTH}; +use crate::hash::hashing::{PlonkyPermutation, SPONGE_RATE, SPONGE_WIDTH}; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; +use crate::plonk::config::{AlgebraicHasher, Hasher}; use crate::plonk::proof::{OpeningSet, OpeningSetTarget}; /// Observes prover messages, and generates challenges by hashing the transcript, a la Fiat-Shamir. #[derive(Clone)] -pub struct Challenger { +pub struct Challenger> { sponge_state: [F; SPONGE_WIDTH], input_buffer: Vec, output_buffer: Vec, + _phantom: PhantomData, } /// Observes prover messages, and generates verifier challenges based on the transcript. @@ -24,12 +29,13 @@ pub struct Challenger { /// design, but it can be viewed as a duplex sponge whose inputs are sometimes zero (when we perform /// multiple squeezes) and whose outputs are sometimes ignored (when we perform multiple /// absorptions). Thus the security properties of a duplex sponge still apply to our design. -impl Challenger { - pub fn new() -> Challenger { +impl> Challenger { + pub fn new() -> Challenger { Challenger { sponge_state: [F::ZERO; SPONGE_WIDTH], input_buffer: Vec::new(), output_buffer: Vec::new(), + _phantom: Default::default(), } } @@ -88,13 +94,14 @@ impl Challenger { } } - pub fn observe_hash(&mut self, hash: &HashOut) { - self.observe_elements(&hash.elements) + pub fn observe_hash>(&mut self, hash: OH::Hash) { + let felts: Vec = hash.into(); + self.observe_elements(&felts) } - pub fn observe_cap(&mut self, cap: &MerkleCap) { - for hash in &cap.0 { - self.observe_elements(&hash.elements) + pub fn observe_cap>(&mut self, cap: &MerkleCap) { + for &hash in &cap.0 { + self.observe_hash::(hash); } } @@ -103,7 +110,7 @@ impl Challenger { if self.output_buffer.is_empty() { // Evaluate the permutation to produce `r` new outputs. - self.sponge_state = permute(self.sponge_state); + self.sponge_state = H::Permutation::permute(self.sponge_state); self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); } @@ -140,7 +147,9 @@ impl Challenger { where F: Extendable, { - (0..n).map(|_| self.get_extension_challenge()).collect() + (0..n) + .map(|_| self.get_extension_challenge::()) + .collect() } /// Absorb any buffered inputs. After calling this, the input buffer will be empty. @@ -158,7 +167,7 @@ impl Challenger { } // Apply the permutation. - self.sponge_state = permute(self.sponge_state); + self.sponge_state = H::Permutation::permute(self.sponge_state); } self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); @@ -167,23 +176,21 @@ impl Challenger { } } -impl Default for Challenger { +impl> Default for Challenger { fn default() -> Self { Self::new() } } /// A recursive version of `Challenger`. -pub struct RecursiveChallenger { +pub struct RecursiveChallenger, H: AlgebraicHasher, const D: usize> { sponge_state: [Target; SPONGE_WIDTH], input_buffer: Vec, output_buffer: Vec, } -impl RecursiveChallenger { - pub(crate) fn new, const D: usize>( - builder: &mut CircuitBuilder, - ) -> Self { +impl, H: AlgebraicHasher, const D: usize> RecursiveChallenger { + pub(crate) fn new(builder: &mut CircuitBuilder) -> Self { let zero = builder.zero(); RecursiveChallenger { sponge_state: [zero; SPONGE_WIDTH], @@ -205,7 +212,7 @@ impl RecursiveChallenger { } } - pub fn observe_opening_set(&mut self, os: &OpeningSetTarget) { + pub fn observe_opening_set(&mut self, os: &OpeningSetTarget) { let OpeningSetTarget { constants, plonk_sigmas, @@ -238,25 +245,22 @@ impl RecursiveChallenger { } } - pub fn observe_extension_element(&mut self, element: ExtensionTarget) { + pub fn observe_extension_element(&mut self, element: ExtensionTarget) { self.observe_elements(&element.0); } - pub fn observe_extension_elements(&mut self, elements: &[ExtensionTarget]) { + pub fn observe_extension_elements(&mut self, elements: &[ExtensionTarget]) { for &element in elements { self.observe_extension_element(element); } } - pub(crate) fn get_challenge, const D: usize>( - &mut self, - builder: &mut CircuitBuilder, - ) -> Target { + pub(crate) fn get_challenge(&mut self, builder: &mut CircuitBuilder) -> Target { self.absorb_buffered_inputs(builder); if self.output_buffer.is_empty() { // Evaluate the permutation to produce `r` new outputs. - self.sponge_state = builder.permute(self.sponge_state); + self.sponge_state = builder.permute::(self.sponge_state); self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); } @@ -265,7 +269,7 @@ impl RecursiveChallenger { .expect("Output buffer should be non-empty") } - pub(crate) fn get_n_challenges, const D: usize>( + pub(crate) fn get_n_challenges( &mut self, builder: &mut CircuitBuilder, n: usize, @@ -273,10 +277,7 @@ impl RecursiveChallenger { (0..n).map(|_| self.get_challenge(builder)).collect() } - pub fn get_hash, const D: usize>( - &mut self, - builder: &mut CircuitBuilder, - ) -> HashOutTarget { + pub fn get_hash(&mut self, builder: &mut CircuitBuilder) -> HashOutTarget { HashOutTarget { elements: [ self.get_challenge(builder), @@ -287,7 +288,7 @@ impl RecursiveChallenger { } } - pub fn get_extension_challenge, const D: usize>( + pub fn get_extension_challenge( &mut self, builder: &mut CircuitBuilder, ) -> ExtensionTarget { @@ -295,10 +296,7 @@ impl RecursiveChallenger { } /// Absorb any buffered inputs. After calling this, the input buffer will be empty. - fn absorb_buffered_inputs, const D: usize>( - &mut self, - builder: &mut CircuitBuilder, - ) { + fn absorb_buffered_inputs(&mut self, builder: &mut CircuitBuilder) { if self.input_buffer.is_empty() { return; } @@ -312,7 +310,7 @@ impl RecursiveChallenger { } // Apply the permutation. - self.sponge_state = builder.permute(self.sponge_state); + self.sponge_state = builder.permute::(self.sponge_state); } self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); @@ -324,18 +322,20 @@ impl RecursiveChallenger { #[cfg(test)] mod tests { use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::challenger::{Challenger, RecursiveChallenger}; use crate::iop::generator::generate_partial_witness; use crate::iop::target::Target; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn no_duplicate_challenges() { - type F = GoldilocksField; - let mut challenger = Challenger::new(); + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + let mut challenger = Challenger::>::InnerHasher>::new(); let mut challenges = Vec::new(); for i in 1..10 { @@ -354,7 +354,9 @@ mod tests { /// Tests for consistency between `Challenger` and `RecursiveChallenger`. #[test] fn test_consistency() { - type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; // These are mostly arbitrary, but we want to test some rounds with enough inputs/outputs to // trigger multiple absorptions/squeezes. @@ -367,7 +369,7 @@ mod tests { .map(|&n| F::rand_vec(n)) .collect(); - let mut challenger = Challenger::new(); + let mut challenger = Challenger::>::InnerHasher>::new(); let mut outputs_per_round: Vec> = Vec::new(); for (r, inputs) in inputs_per_round.iter().enumerate() { challenger.observe_elements(inputs); @@ -375,8 +377,9 @@ mod tests { } let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - let mut recursive_challenger = RecursiveChallenger::new(&mut builder); + let mut builder = CircuitBuilder::::new(config); + let mut recursive_challenger = + RecursiveChallenger::>::InnerHasher, D>::new(&mut builder); let mut recursive_outputs_per_round: Vec> = Vec::new(); for (r, inputs) in inputs_per_round.iter().enumerate() { recursive_challenger.observe_elements(&builder.constants(inputs)); @@ -384,7 +387,7 @@ mod tests { recursive_challenger.get_n_challenges(&mut builder, num_outputs_per_round[r]), ); } - let circuit = builder.build(); + let circuit = builder.build::(); let inputs = PartialWitness::new(); let witness = generate_partial_witness(inputs, &circuit.prover_only, &circuit.common); let recursive_output_values_per_round: Vec> = recursive_outputs_per_round diff --git a/src/iop/generator.rs b/src/iop/generator.rs index ea4ac1f6..d1d300b4 100644 --- a/src/iop/generator.rs +++ b/src/iop/generator.rs @@ -5,7 +5,7 @@ use num::BigUint; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gadgets::arithmetic_u32::U32Target; use crate::gadgets::biguint::BigUintTarget; use crate::gadgets::nonnative::NonNativeTarget; @@ -14,13 +14,19 @@ use crate::iop::target::Target; use crate::iop::wire::Wire; use crate::iop::witness::{PartialWitness, PartitionWitness, Witness}; use crate::plonk::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; +use crate::plonk::config::GenericConfig; /// Given a `PartitionWitness` that has only inputs set, populates the rest of the witness using the /// given set of generators. -pub(crate) fn generate_partial_witness<'a, F: RichField + Extendable, const D: usize>( +pub(crate) fn generate_partial_witness< + 'a, + F: Extendable, + C: GenericConfig, + const D: usize, +>( inputs: PartialWitness, - prover_data: &'a ProverOnlyCircuitData, - common_data: &'a CommonCircuitData, + prover_data: &'a ProverOnlyCircuitData, + common_data: &'a CommonCircuitData, ) -> PartitionWitness<'a, F> { let config = &common_data.config; let generators = &prover_data.generators; diff --git a/src/iop/witness.rs b/src/iop/witness.rs index 6ace4411..17fd0823 100644 --- a/src/iop/witness.rs +++ b/src/iop/witness.rs @@ -4,7 +4,7 @@ use num::{BigUint, FromPrimitive, Zero}; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; -use crate::field::field_types::Field; +use crate::field::field_types::{Field, RichField}; use crate::gadgets::arithmetic_u32::U32Target; use crate::gadgets::biguint::BigUintTarget; use crate::gadgets::nonnative::NonNativeTarget; @@ -13,6 +13,7 @@ use crate::hash::hash_types::{HashOut, MerkleCapTarget}; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::{BoolTarget, Target}; use crate::iop::wire::Wire; +use crate::plonk::config::AlgebraicHasher; /// A witness holds information on the values of targets in a circuit. pub trait Witness { @@ -104,7 +105,13 @@ pub trait Witness { .for_each(|(&t, x)| self.set_target(t, x)); } - fn set_cap_target(&mut self, ct: &MerkleCapTarget, value: &MerkleCap) { + fn set_cap_target>( + &mut self, + ct: &MerkleCapTarget, + value: &MerkleCap, + ) where + F: RichField, + { for (ht, h) in ct.0.iter().zip(&value.0) { self.set_hash_target(*ht, *h); } diff --git a/src/lib.rs b/src/lib.rs index 291e6422..f1014b73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![allow(const_evaluatable_unchecked)] #![allow(clippy::new_without_default)] #![allow(clippy::too_many_arguments)] +#![allow(clippy::type_complexity)] #![allow(clippy::len_without_is_empty)] #![allow(clippy::needless_range_loop)] #![feature(asm_sym)] diff --git a/src/plonk/circuit_builder.rs b/src/plonk/circuit_builder.rs index 8b8ce1ff..e1cd5bbf 100644 --- a/src/plonk/circuit_builder.rs +++ b/src/plonk/circuit_builder.rs @@ -8,7 +8,7 @@ use crate::field::cosets::get_unique_coset_shifts; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::fft::fft_root_table; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::fri::commitment::PolynomialBatchCommitment; use crate::fri::{FriConfig, FriParams}; use crate::gadgets::arithmetic::BaseArithmeticOperation; @@ -27,7 +27,6 @@ use crate::gates::random_access::RandomAccessGate; use crate::gates::subtraction_u32::U32SubtractionGate; use crate::gates::switch::SwitchGate; use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget}; -use crate::hash::hashing::hash_n_to_hash; use crate::iop::generator::{ CopyGenerator, RandomValueGenerator, SimpleGenerator, WitnessGenerator, }; @@ -37,6 +36,7 @@ use crate::plonk::circuit_data::{ CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData, VerifierCircuitData, VerifierOnlyCircuitData, }; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::copy_constraint::CopyConstraint; use crate::plonk::permutation_argument::Forest; use crate::plonk::plonk_common::PlonkPolynomials; @@ -47,7 +47,7 @@ use crate::util::partial_products::num_partial_products; use crate::util::timing::TimingTree; use crate::util::{log2_ceil, log2_strict, transpose, transpose_poly_values}; -pub struct CircuitBuilder, const D: usize> { +pub struct CircuitBuilder, const D: usize> { pub(crate) config: CircuitConfig, /// The types of gates used in this circuit. @@ -85,7 +85,7 @@ pub struct CircuitBuilder, const D: usize> { batched_gates: BatchedGates, } -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { pub fn new(config: CircuitConfig) -> Self { let builder = CircuitBuilder { config, @@ -582,7 +582,7 @@ impl, const D: usize> CircuitBuilder { } /// Builds a "full circuit", with both prover and verifier data. - pub fn build(mut self) -> CircuitData { + pub fn build>(mut self) -> CircuitData { let mut timing = TimingTree::new("preprocess", Level::Trace); let start = Instant::now(); @@ -590,7 +590,8 @@ impl, const D: usize> CircuitBuilder { // Hash the public inputs, and route them to a `PublicInputGate` which will enforce that // those hash wires match the claimed public inputs. - let public_inputs_hash = self.hash_n_to_hash(self.public_inputs.clone(), true); + let public_inputs_hash = + self.hash_n_to_hash::(self.public_inputs.clone(), true); let pi_gate = self.add_gate(PublicInputGate, vec![]); for (&hash_part, wire) in public_inputs_hash .elements @@ -709,7 +710,7 @@ impl, const D: usize> CircuitBuilder { constants_sigmas_cap.flatten(), vec![/* Add other circuit data here */], ]; - let circuit_digest = hash_n_to_hash(circuit_digest_parts.concat(), false); + let circuit_digest = C::Hasher::hash(circuit_digest_parts.concat(), false); let common = CommonCircuitData { config: self.config, @@ -734,7 +735,7 @@ impl, const D: usize> CircuitBuilder { } /// Builds a "prover circuit", with data needed to generate proofs but not verify them. - pub fn build_prover(self) -> ProverCircuitData { + pub fn build_prover>(self) -> ProverCircuitData { // TODO: Can skip parts of this. let CircuitData { prover_only, @@ -748,7 +749,7 @@ impl, const D: usize> CircuitBuilder { } /// Builds a "verifier circuit", with data needed to verify proofs but not generate them. - pub fn build_verifier(self) -> VerifierCircuitData { + pub fn build_verifier>(self) -> VerifierCircuitData { // TODO: Can skip parts of this. let CircuitData { verifier_only, @@ -764,7 +765,7 @@ impl, const D: usize> CircuitBuilder { /// Various gate types can contain multiple copies in a single Gate. This helper struct lets a /// CircuitBuilder track such gates that are currently being "filled up." -pub struct BatchedGates, const D: usize> { +pub struct BatchedGates, const D: usize> { /// A map `(c0, c1) -> (g, i)` from constants `(c0,c1)` to an available arithmetic gate using /// these constants with gate index `g` and already using `i` arithmetic operations. pub(crate) free_arithmetic: HashMap<(F, F), (usize, usize)>, @@ -791,7 +792,7 @@ pub struct BatchedGates, const D: usize> { pub(crate) free_constant: Option<(usize, usize)>, } -impl, const D: usize> BatchedGates { +impl, const D: usize> BatchedGates { pub fn new() -> Self { Self { free_arithmetic: HashMap::new(), @@ -806,7 +807,7 @@ impl, const D: usize> BatchedGates { } } -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Finds the last available arithmetic gate with the given constants or add one if there aren't any. /// Returns `(g,i)` such that there is an arithmetic gate with the given constants at index /// `g` and the gate's `i`-th operation is available. diff --git a/src/plonk/circuit_data.rs b/src/plonk/circuit_data.rs index f0451131..668f350f 100644 --- a/src/plonk/circuit_data.rs +++ b/src/plonk/circuit_data.rs @@ -5,16 +5,16 @@ use anyhow::Result; use crate::field::extension_field::Extendable; use crate::field::fft::FftRootTable; -use crate::field::field_types::{Field, RichField}; use crate::fri::commitment::PolynomialBatchCommitment; use crate::fri::reduction_strategies::FriReductionStrategy; use crate::fri::{FriConfig, FriParams}; use crate::gates::gate::PrefixedGate; -use crate::hash::hash_types::{HashOut, MerkleCapTarget}; +use crate::hash::hash_types::MerkleCapTarget; use crate::hash::merkle_tree::MerkleCap; use crate::iop::generator::WitnessGenerator; use crate::iop::target::Target; use crate::iop::witness::PartialWitness; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs}; use crate::plonk::prover::prove; use crate::plonk::verifier::verify; @@ -85,14 +85,14 @@ impl CircuitConfig { } /// Circuit data required by the prover or the verifier. -pub struct CircuitData, const D: usize> { - pub(crate) prover_only: ProverOnlyCircuitData, - pub(crate) verifier_only: VerifierOnlyCircuitData, - pub(crate) common: CommonCircuitData, +pub struct CircuitData, C: GenericConfig, const D: usize> { + pub(crate) prover_only: ProverOnlyCircuitData, + pub(crate) verifier_only: VerifierOnlyCircuitData, + pub(crate) common: CommonCircuitData, } -impl, const D: usize> CircuitData { - pub fn prove(&self, inputs: PartialWitness) -> Result> { +impl, C: GenericConfig, const D: usize> CircuitData { + pub fn prove(&self, inputs: PartialWitness) -> Result> { prove( &self.prover_only, &self.common, @@ -101,13 +101,13 @@ impl, const D: usize> CircuitData { ) } - pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { + pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { verify(proof_with_pis, &self.verifier_only, &self.common) } pub fn verify_compressed( &self, - compressed_proof_with_pis: CompressedProofWithPublicInputs, + compressed_proof_with_pis: CompressedProofWithPublicInputs, ) -> Result<()> { compressed_proof_with_pis.verify(&self.verifier_only, &self.common) } @@ -120,13 +120,13 @@ impl, const D: usize> CircuitData { /// structure as succinct as we can. Thus we include various precomputed data which isn't strictly /// required, like LDEs of preprocessed polynomials. If more succinctness was desired, we could /// construct a more minimal prover structure and convert back and forth. -pub struct ProverCircuitData, const D: usize> { - pub(crate) prover_only: ProverOnlyCircuitData, - pub(crate) common: CommonCircuitData, +pub struct ProverCircuitData, C: GenericConfig, const D: usize> { + pub(crate) prover_only: ProverOnlyCircuitData, + pub(crate) common: CommonCircuitData, } -impl, const D: usize> ProverCircuitData { - pub fn prove(&self, inputs: PartialWitness) -> Result> { +impl, C: GenericConfig, const D: usize> ProverCircuitData { + pub fn prove(&self, inputs: PartialWitness) -> Result> { prove( &self.prover_only, &self.common, @@ -138,32 +138,36 @@ impl, const D: usize> ProverCircuitData { /// Circuit data required by the prover. #[derive(Debug)] -pub struct VerifierCircuitData, const D: usize> { - pub(crate) verifier_only: VerifierOnlyCircuitData, - pub(crate) common: CommonCircuitData, +pub struct VerifierCircuitData, C: GenericConfig, const D: usize> { + pub(crate) verifier_only: VerifierOnlyCircuitData, + pub(crate) common: CommonCircuitData, } -impl, const D: usize> VerifierCircuitData { - pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { +impl, C: GenericConfig, const D: usize> VerifierCircuitData { + pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { verify(proof_with_pis, &self.verifier_only, &self.common) } pub fn verify_compressed( &self, - compressed_proof_with_pis: CompressedProofWithPublicInputs, + compressed_proof_with_pis: CompressedProofWithPublicInputs, ) -> Result<()> { compressed_proof_with_pis.verify(&self.verifier_only, &self.common) } } /// Circuit data required by the prover, but not the verifier. -pub(crate) struct ProverOnlyCircuitData, const D: usize> { +pub(crate) struct ProverOnlyCircuitData< + F: Extendable, + C: GenericConfig, + const D: usize, +> { pub generators: Vec>>, /// Generator indices (within the `Vec` above), indexed by the representative of each target /// they watch. pub generator_indices_by_watches: BTreeMap>, /// Commitments to the constants polynomials and sigma polynomials. - pub constants_sigmas_commitment: PolynomialBatchCommitment, + pub constants_sigmas_commitment: PolynomialBatchCommitment, /// The transpose of the list of sigma polynomials. pub sigmas: Vec>, /// Subgroup of order `degree`. @@ -181,14 +185,14 @@ pub(crate) struct ProverOnlyCircuitData, const D: u /// Circuit data required by the verifier, but not the prover. #[derive(Debug)] -pub(crate) struct VerifierOnlyCircuitData { +pub(crate) struct VerifierOnlyCircuitData, const D: usize> { /// A commitment to each constant polynomial and each permutation polynomial. - pub(crate) constants_sigmas_cap: MerkleCap, + pub(crate) constants_sigmas_cap: MerkleCap, } /// Circuit data required by both the prover and the verifier. #[derive(Debug)] -pub struct CommonCircuitData, const D: usize> { +pub struct CommonCircuitData, C: GenericConfig, const D: usize> { pub(crate) config: CircuitConfig, pub(crate) fri_params: FriParams, @@ -218,10 +222,10 @@ pub struct CommonCircuitData, const D: usize> { /// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to /// seed Fiat-Shamir. - pub(crate) circuit_digest: HashOut, + pub(crate) circuit_digest: <>::Hasher as Hasher>::Hash, } -impl, const D: usize> CommonCircuitData { +impl, C: GenericConfig, const D: usize> CommonCircuitData { pub fn degree(&self) -> usize { 1 << self.degree_bits } diff --git a/src/plonk/config.rs b/src/plonk/config.rs new file mode 100644 index 00000000..e448bc7c --- /dev/null +++ b/src/plonk/config.rs @@ -0,0 +1,236 @@ +use std::convert::TryInto; +use std::fmt::Debug; + +use keccak_hash::keccak; +use serde::{de::DeserializeOwned, Serialize}; + +use crate::field::extension_field::quadratic::QuadraticExtension; +use crate::field::extension_field::{Extendable, FieldExtension}; +use crate::field::field_types::RichField; +use crate::field::goldilocks_field::GoldilocksField; +use crate::gates::poseidon::PoseidonGate; +use crate::hash::hash_types::{BytesHash, HashOut}; +use crate::hash::hashing::{ + compress, hash_n_to_hash, PlonkyPermutation, PoseidonPermutation, SPONGE_WIDTH, +}; +use crate::iop::target::{BoolTarget, Target}; +use crate::plonk::circuit_builder::CircuitBuilder; +use crate::util::serialization::Buffer; + +/// Trait for hash functions. +pub trait Hasher: Sized + Clone + Debug + Eq + PartialEq { + /// Size of `Hash` in bytes. + const HASH_SIZE: usize; + type Hash: From> + + Into> + + Into> + + Copy + + Clone + + Debug + + Eq + + PartialEq + + Send + + Sync + + Serialize + + DeserializeOwned; + + fn hash(input: Vec, pad: bool) -> Self::Hash; + fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash; +} + +/// Trait for algebraic hash functions, built from a permutation using the sponge construction. +pub trait AlgebraicHasher: Hasher> { + // TODO: Adding a `const WIDTH: usize` here yields a compiler error down the line. + // Maybe try again in a while. + + /// Permutation used in the sponge construction. + type Permutation: PlonkyPermutation; + /// Circuit to conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), + /// then apply the permutation. + fn permute_swapped( + inputs: [Target; SPONGE_WIDTH], + swap: BoolTarget, + builder: &mut CircuitBuilder, + ) -> [Target; SPONGE_WIDTH] + where + F: Extendable; +} + +/// Poseidon hash function. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct PoseidonHash; +impl Hasher for PoseidonHash { + const HASH_SIZE: usize = 4 * 8; + type Hash = HashOut; + + fn hash(input: Vec, pad: bool) -> Self::Hash { + hash_n_to_hash::>::Permutation>(input, pad) + } + + fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash { + compress::>::Permutation>(left, right) + } +} + +impl AlgebraicHasher for PoseidonHash { + type Permutation = PoseidonPermutation; + + fn permute_swapped( + inputs: [Target; SPONGE_WIDTH], + swap: BoolTarget, + builder: &mut CircuitBuilder, + ) -> [Target; SPONGE_WIDTH] + where + F: Extendable, + { + let gate_type = PoseidonGate::::new(); + let gate = builder.add_gate(gate_type, vec![]); + + let swap_wire = PoseidonGate::::WIRE_SWAP; + let swap_wire = Target::wire(gate, swap_wire); + builder.connect(swap.target, swap_wire); + + // Route input wires. + for i in 0..SPONGE_WIDTH { + let in_wire = PoseidonGate::::wire_input(i); + let in_wire = Target::wire(gate, in_wire); + builder.connect(inputs[i], in_wire); + } + + // Collect output wires. + (0..SPONGE_WIDTH) + .map(|i| Target::wire(gate, PoseidonGate::::wire_output(i))) + .collect::>() + .try_into() + .unwrap() + } +} + +// TODO: Remove width from `GMiMCGate` to make this work. +// #[derive(Copy, Clone, Debug, Eq, PartialEq)] +// pub struct GMiMCHash; +// impl Hasher for GMiMCHash { +// const HASH_SIZE: usize = 4 * 8; +// type Hash = HashOut; +// +// fn hash(input: Vec, pad: bool) -> Self::Hash { +// hash_n_to_hash::>::Permutation>(input, pad) +// } +// +// fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash { +// compress::>::Permutation>(left, right) +// } +// } +// +// impl AlgebraicHasher for GMiMCHash { +// type Permutation = GMiMCPermutation; +// +// fn permute_swapped( +// inputs: [Target; WIDTH], +// swap: BoolTarget, +// builder: &mut CircuitBuilder, +// ) -> [Target; WIDTH] +// where +// F: Extendable, +// { +// let gate_type = GMiMCGate::::new(); +// let gate = builder.add_gate(gate_type, vec![]); +// +// let swap_wire = GMiMCGate::::WIRE_SWAP; +// let swap_wire = Target::wire(gate, swap_wire); +// builder.connect(swap.target, swap_wire); +// +// // Route input wires. +// for i in 0..W { +// let in_wire = GMiMCGate::::wire_input(i); +// let in_wire = Target::wire(gate, in_wire); +// builder.connect(inputs[i], in_wire); +// } +// +// // Collect output wires. +// (0..W) +// .map(|i| Target::wire(gate, input: GMiMCGate::wire_output(i))) +// .collect::>() +// .try_into() +// .unwrap() +// } +// } + +/// Keccak-256 hash function. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct KeccakHash; +impl Hasher for KeccakHash { + const HASH_SIZE: usize = N; + type Hash = BytesHash; + + fn hash(input: Vec, _pad: bool) -> Self::Hash { + let mut buffer = Buffer::new(Vec::new()); + buffer.write_field_vec(&input).unwrap(); + let mut arr = [0; N]; + let hash_bytes = keccak(buffer.bytes()).0; + arr.copy_from_slice(&hash_bytes[..N]); + BytesHash(arr) + } + + fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash { + let mut v = vec![0; N * 2]; + v[0..N].copy_from_slice(&left.0); + v[N..].copy_from_slice(&right.0); + let mut arr = [0; N]; + arr.copy_from_slice(&keccak(v).0[..N]); + BytesHash(arr) + } +} + +/// Generic configuration trait. +pub trait GenericConfig: + Debug + Clone + Sync + Sized + Send + Eq + PartialEq +{ + /// Main field. + type F: RichField + Extendable; + /// Field extension of degree D of the main field. + type FE: FieldExtension; + /// Hash function used for building Merkle trees. + type Hasher: Hasher; + /// Algebraic hash function used for the challenger and hashing public inputs. + type InnerHasher: AlgebraicHasher; +} + +/// Configuration trait for "algebraic" configurations, i.e., those using an algebraic hash function +/// in Merkle trees. +/// Same as `GenericConfig` trait but with `InnerHasher: AlgebraicHasher`. +pub trait AlgebraicConfig: + Debug + Clone + Sync + Sized + Send + Eq + PartialEq +{ + type F: RichField + Extendable; + type FE: FieldExtension; + type Hasher: AlgebraicHasher; + type InnerHasher: AlgebraicHasher; +} + +impl, const D: usize> GenericConfig for A { + type F = >::F; + type FE = >::FE; + type Hasher = >::Hasher; + type InnerHasher = >::InnerHasher; +} + +/// Configuration using Poseidon over the Goldilocks field. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct PoseidonGoldilocksConfig; +impl AlgebraicConfig<2> for PoseidonGoldilocksConfig { + type F = GoldilocksField; + type FE = QuadraticExtension; + type Hasher = PoseidonHash; + type InnerHasher = PoseidonHash; +} + +/// Configuration using truncated Keccak over the Goldilocks field. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct KeccakGoldilocksConfig; +impl GenericConfig<2> for KeccakGoldilocksConfig { + type F = GoldilocksField; + type FE = QuadraticExtension; + type Hasher = KeccakHash<25>; + type InnerHasher = PoseidonHash; +} diff --git a/src/plonk/get_challenges.rs b/src/plonk/get_challenges.rs index a749f1c0..94c14765 100644 --- a/src/plonk/get_challenges.rs +++ b/src/plonk/get_challenges.rs @@ -1,14 +1,12 @@ use std::collections::HashSet; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::fri::proof::{CompressedFriProof, FriProof}; use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedEvals}; -use crate::hash::hash_types::HashOut; -use crate::hash::hashing::hash_n_to_1; use crate::hash::merkle_tree::MerkleCap; use crate::iop::challenger::Challenger; use crate::plonk::circuit_data::CommonCircuitData; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::proof::{ CompressedProof, CompressedProofWithPublicInputs, FriInferredElements, OpeningSet, Proof, ProofChallenges, ProofWithPublicInputs, @@ -16,27 +14,27 @@ use crate::plonk::proof::{ use crate::polynomial::PolynomialCoeffs; use crate::util::reverse_bits; -fn get_challenges, const D: usize>( - public_inputs_hash: HashOut, - wires_cap: &MerkleCap, - plonk_zs_partial_products_cap: &MerkleCap, - quotient_polys_cap: &MerkleCap, +fn get_challenges, C: GenericConfig, const D: usize>( + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + wires_cap: &MerkleCap, + plonk_zs_partial_products_cap: &MerkleCap, + quotient_polys_cap: &MerkleCap, openings: &OpeningSet, - commit_phase_merkle_caps: &[MerkleCap], + commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { let config = &common_data.config; let num_challenges = config.num_challenges; let num_fri_queries = config.fri_config.num_query_rounds; let lde_size = common_data.lde_size(); - let mut challenger = Challenger::new(); + let mut challenger = Challenger::::new(); // Observe the instance. - challenger.observe_hash(&common_data.circuit_digest); - challenger.observe_hash(&public_inputs_hash); + challenger.observe_hash::(common_data.circuit_digest); + challenger.observe_hash::(public_inputs_hash); challenger.observe_cap(wires_cap); let plonk_betas = challenger.get_n_challenges(num_challenges); @@ -46,25 +44,25 @@ fn get_challenges, const D: usize>( let plonk_alphas = challenger.get_n_challenges(num_challenges); challenger.observe_cap(quotient_polys_cap); - let plonk_zeta = challenger.get_extension_challenge(); + let plonk_zeta = challenger.get_extension_challenge::(); challenger.observe_opening_set(openings); // Scaling factor to combine polynomials. - let fri_alpha = challenger.get_extension_challenge(); + let fri_alpha = challenger.get_extension_challenge::(); // Recover the random betas used in the FRI reductions. let fri_betas = commit_phase_merkle_caps .iter() .map(|cap| { challenger.observe_cap(cap); - challenger.get_extension_challenge() + challenger.get_extension_challenge::() }) .collect(); challenger.observe_extension_elements(&final_poly.coeffs); - let fri_pow_response = hash_n_to_1( + let fri_pow_response = C::InnerHasher::hash( challenger .get_hash() .elements @@ -73,7 +71,8 @@ fn get_challenges, const D: usize>( .chain(Some(pow_witness)) .collect(), false, - ); + ) + .elements[0]; let fri_query_indices = (0..num_fri_queries) .map(|_| challenger.get_challenge().to_canonical_u64() as usize % lde_size) @@ -91,10 +90,10 @@ fn get_challenges, const D: usize>( }) } -impl, const D: usize> ProofWithPublicInputs { +impl, C: GenericConfig, const D: usize> ProofWithPublicInputs { pub(crate) fn fri_query_indices( &self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { Ok(self.get_challenges(common_data)?.fri_query_indices) } @@ -102,7 +101,7 @@ impl, const D: usize> ProofWithPublicInputs { /// Computes all Fiat-Shamir challenges used in the Plonk proof. pub(crate) fn get_challenges( &self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { let Proof { wires_cap, @@ -132,11 +131,13 @@ impl, const D: usize> ProofWithPublicInputs { } } -impl, const D: usize> CompressedProofWithPublicInputs { +impl, C: GenericConfig, const D: usize> + CompressedProofWithPublicInputs +{ /// Computes all Fiat-Shamir challenges used in the Plonk proof. pub(crate) fn get_challenges( &self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { let CompressedProof { wires_cap, @@ -169,7 +170,7 @@ impl, const D: usize> CompressedProofWithPublicInpu pub(crate) fn get_inferred_elements( &self, challenges: &ProofChallenges, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> FriInferredElements { let ProofChallenges { plonk_zeta, diff --git a/src/plonk/mod.rs b/src/plonk/mod.rs index 3b8fdd6b..b2d1ed03 100644 --- a/src/plonk/mod.rs +++ b/src/plonk/mod.rs @@ -1,5 +1,6 @@ pub mod circuit_builder; pub mod circuit_data; +pub mod config; pub(crate) mod copy_constraint; mod get_challenges; pub(crate) mod permutation_argument; diff --git a/src/plonk/proof.rs b/src/plonk/proof.rs index 94bc4714..db6a1e2e 100644 --- a/src/plonk/proof.rs +++ b/src/plonk/proof.rs @@ -3,30 +3,29 @@ use serde::{Deserialize, Serialize}; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::fri::commitment::PolynomialBatchCommitment; use crate::fri::proof::{CompressedFriProof, FriProof, FriProofTarget}; -use crate::hash::hash_types::{HashOut, MerkleCapTarget}; -use crate::hash::hashing::hash_n_to_hash; +use crate::hash::hash_types::MerkleCapTarget; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::Target; use crate::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::verifier::verify_with_challenges; use crate::util::serialization::Buffer; #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct Proof, const D: usize> { +pub struct Proof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of wire values. - pub wires_cap: MerkleCap, + pub wires_cap: MerkleCap, /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_cap: MerkleCap, + pub plonk_zs_partial_products_cap: MerkleCap, /// Merkle cap of LDEs of the quotient polynomial components. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: FriProof, + pub opening_proof: FriProof, } pub struct ProofTarget { @@ -37,13 +36,13 @@ pub struct ProofTarget { pub opening_proof: FriProofTarget, } -impl, const D: usize> Proof { +impl, C: GenericConfig, const D: usize> Proof { /// Compress the proof. pub fn compress( self, indices: &[usize], - common_data: &CommonCircuitData, - ) -> CompressedProof { + common_data: &CommonCircuitData, + ) -> CompressedProof { let Proof { wires_cap, plonk_zs_partial_products_cap, @@ -64,16 +63,16 @@ impl, const D: usize> Proof { #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct ProofWithPublicInputs, const D: usize> { - pub proof: Proof, +pub struct ProofWithPublicInputs, C: GenericConfig, const D: usize> { + pub proof: Proof, pub public_inputs: Vec, } -impl, const D: usize> ProofWithPublicInputs { +impl, C: GenericConfig, const D: usize> ProofWithPublicInputs { pub fn compress( self, - common_data: &CommonCircuitData, - ) -> anyhow::Result> { + common_data: &CommonCircuitData, + ) -> anyhow::Result> { let indices = self.fri_query_indices(common_data)?; let compressed_proof = self.proof.compress(&indices, common_data); Ok(CompressedProofWithPublicInputs { @@ -82,8 +81,10 @@ impl, const D: usize> ProofWithPublicInputs { }) } - pub(crate) fn get_public_inputs_hash(&self) -> HashOut { - hash_n_to_hash(self.public_inputs.clone(), true) + pub(crate) fn get_public_inputs_hash( + &self, + ) -> <>::InnerHasher as Hasher>::Hash { + C::InnerHasher::hash(self.public_inputs.clone(), true) } pub fn to_bytes(&self) -> anyhow::Result> { @@ -94,7 +95,7 @@ impl, const D: usize> ProofWithPublicInputs { pub fn from_bytes( bytes: Vec, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result { let mut buffer = Buffer::new(bytes); let proof = buffer.read_proof_with_public_inputs(common_data)?; @@ -104,27 +105,27 @@ impl, const D: usize> ProofWithPublicInputs { #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedProof, const D: usize> { +pub struct CompressedProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of wire values. - pub wires_cap: MerkleCap, + pub wires_cap: MerkleCap, /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_cap: MerkleCap, + pub plonk_zs_partial_products_cap: MerkleCap, /// Merkle cap of LDEs of the quotient polynomial components. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A compressed batch FRI argument for all openings. - pub opening_proof: CompressedFriProof, + pub opening_proof: CompressedFriProof, } -impl, const D: usize> CompressedProof { +impl, C: GenericConfig, const D: usize> CompressedProof { /// Decompress the proof. pub(crate) fn decompress( self, challenges: &ProofChallenges, fri_inferred_elements: FriInferredElements, - common_data: &CommonCircuitData, - ) -> Proof { + common_data: &CommonCircuitData, + ) -> Proof { let CompressedProof { wires_cap, plonk_zs_partial_products_cap, @@ -145,16 +146,22 @@ impl, const D: usize> CompressedProof { #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedProofWithPublicInputs, const D: usize> { - pub proof: CompressedProof, +pub struct CompressedProofWithPublicInputs< + F: Extendable, + C: GenericConfig, + const D: usize, +> { + pub proof: CompressedProof, pub public_inputs: Vec, } -impl, const D: usize> CompressedProofWithPublicInputs { +impl, C: GenericConfig, const D: usize> + CompressedProofWithPublicInputs +{ pub fn decompress( self, - common_data: &CommonCircuitData, - ) -> anyhow::Result> { + common_data: &CommonCircuitData, + ) -> anyhow::Result> { let challenges = self.get_challenges(common_data)?; let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); let decompressed_proof = @@ -168,8 +175,8 @@ impl, const D: usize> CompressedProofWithPublicInpu pub(crate) fn verify( self, - verifier_data: &VerifierOnlyCircuitData, - common_data: &CommonCircuitData, + verifier_data: &VerifierOnlyCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result<()> { let challenges = self.get_challenges(common_data)?; let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); @@ -187,8 +194,10 @@ impl, const D: usize> CompressedProofWithPublicInpu ) } - pub(crate) fn get_public_inputs_hash(&self) -> HashOut { - hash_n_to_hash(self.public_inputs.clone(), true) + pub(crate) fn get_public_inputs_hash( + &self, + ) -> <>::InnerHasher as Hasher>::Hash { + C::InnerHasher::hash(self.public_inputs.clone(), true) } pub fn to_bytes(&self) -> anyhow::Result> { @@ -199,7 +208,7 @@ impl, const D: usize> CompressedProofWithPublicInpu pub fn from_bytes( bytes: Vec, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result { let mut buffer = Buffer::new(bytes); let proof = buffer.read_compressed_proof_with_public_inputs(common_data)?; @@ -207,7 +216,7 @@ impl, const D: usize> CompressedProofWithPublicInpu } } -pub(crate) struct ProofChallenges, const D: usize> { +pub(crate) struct ProofChallenges, const D: usize> { // Random values used in Plonk's permutation argument. pub plonk_betas: Vec, @@ -233,9 +242,7 @@ pub(crate) struct ProofChallenges, const D: usize> } /// Coset elements that can be inferred in the FRI reduction steps. -pub(crate) struct FriInferredElements, const D: usize>( - pub Vec, -); +pub(crate) struct FriInferredElements, const D: usize>(pub Vec); pub struct ProofWithPublicInputsTarget { pub proof: ProofTarget, @@ -254,17 +261,17 @@ pub struct OpeningSet, const D: usize> { pub quotient_polys: Vec, } -impl, const D: usize> OpeningSet { - pub fn new( +impl, const D: usize> OpeningSet { + pub fn new>( z: F::Extension, g: F::Extension, - constants_sigmas_commitment: &PolynomialBatchCommitment, - wires_commitment: &PolynomialBatchCommitment, - zs_partial_products_commitment: &PolynomialBatchCommitment, - quotient_polys_commitment: &PolynomialBatchCommitment, - common_data: &CommonCircuitData, + constants_sigmas_commitment: &PolynomialBatchCommitment, + wires_commitment: &PolynomialBatchCommitment, + zs_partial_products_commitment: &PolynomialBatchCommitment, + quotient_polys_commitment: &PolynomialBatchCommitment, + common_data: &CommonCircuitData, ) -> Self { - let eval_commitment = |z: F::Extension, c: &PolynomialBatchCommitment| { + let eval_commitment = |z: F::Extension, c: &PolynomialBatchCommitment| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) @@ -304,18 +311,19 @@ mod tests { use anyhow::Result; use crate::field::field_types::Field; - use crate::field::goldilocks_field::GoldilocksField; use crate::fri::reduction_strategies::FriReductionStrategy; use crate::gates::noop::NoopGate; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_proof_compression() -> Result<()> { - type F = GoldilocksField; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let mut config = CircuitConfig::standard_recursion_config(); config.fri_config.reduction_strategy = FriReductionStrategy::Fixed(vec![1, 1]); @@ -336,7 +344,7 @@ mod tests { for _ in 0..100 { builder.add_gate(NoopGate, vec![]); } - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof.clone(), &data.verifier_only, &data.common)?; diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 8a109382..6cf569e6 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -4,14 +4,12 @@ use anyhow::Result; use rayon::prelude::*; use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::fri::commitment::PolynomialBatchCommitment; -use crate::hash::hash_types::HashOut; -use crate::hash::hashing::hash_n_to_hash; use crate::iop::challenger::Challenger; use crate::iop::generator::generate_partial_witness; use crate::iop::witness::{MatrixWitness, PartialWitness, Witness}; use crate::plonk::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::plonk_common::PlonkPolynomials; use crate::plonk::plonk_common::ZeroPolyOnCoset; use crate::plonk::proof::{Proof, ProofWithPublicInputs}; @@ -23,12 +21,12 @@ use crate::util::partial_products::{partial_products_and_z_gx, quotient_chunk_pr use crate::util::timing::TimingTree; use crate::util::{log2_ceil, transpose}; -pub(crate) fn prove, const D: usize>( - prover_data: &ProverOnlyCircuitData, - common_data: &CommonCircuitData, +pub(crate) fn prove, C: GenericConfig, const D: usize>( + prover_data: &ProverOnlyCircuitData, + common_data: &CommonCircuitData, inputs: PartialWitness, timing: &mut TimingTree, -) -> Result> { +) -> Result> { let config = &common_data.config; let num_challenges = config.num_challenges; let quotient_degree = common_data.quotient_degree(); @@ -41,7 +39,7 @@ pub(crate) fn prove, const D: usize>( ); let public_inputs = partition_witness.get_targets(&prover_data.public_inputs); - let public_inputs_hash = hash_n_to_hash(public_inputs.clone(), true); + let public_inputs_hash = C::InnerHasher::hash(public_inputs.clone(), true); if cfg!(debug_assertions) { // Display the marked targets for debugging purposes. @@ -82,8 +80,8 @@ pub(crate) fn prove, const D: usize>( let mut challenger = Challenger::new(); // Observe the instance. - challenger.observe_hash(&common_data.circuit_digest); - challenger.observe_hash(&public_inputs_hash); + challenger.observe_hash::(common_data.circuit_digest); + challenger.observe_hash::(public_inputs_hash); challenger.observe_cap(&wires_commitment.merkle_tree.cap); let betas = challenger.get_n_challenges(num_challenges); @@ -170,7 +168,7 @@ pub(crate) fn prove, const D: usize>( challenger.observe_cap("ient_polys_commitment.merkle_tree.cap); - let zeta = challenger.get_extension_challenge(); + let zeta = challenger.get_extension_challenge::(); let (opening_proof, openings) = timed!( timing, @@ -203,12 +201,16 @@ pub(crate) fn prove, const D: usize>( } /// Compute the partial products used in the `Z` polynomials. -fn all_wires_permutation_partial_products, const D: usize>( +fn all_wires_permutation_partial_products< + F: Extendable, + C: GenericConfig, + const D: usize, +>( witness: &MatrixWitness, betas: &[F], gammas: &[F], - prover_data: &ProverOnlyCircuitData, - common_data: &CommonCircuitData, + prover_data: &ProverOnlyCircuitData, + common_data: &CommonCircuitData, ) -> Vec>> { (0..common_data.config.num_challenges) .map(|i| { @@ -226,12 +228,16 @@ fn all_wires_permutation_partial_products, const D: /// Compute the partial products used in the `Z` polynomial. /// Returns the polynomials interpolating `partial_products(f / g)` /// where `f, g` are the products in the definition of `Z`: `Z(g^i) = f / g`. -fn wires_permutation_partial_products_and_zs, const D: usize>( +fn wires_permutation_partial_products_and_zs< + F: Extendable, + C: GenericConfig, + const D: usize, +>( witness: &MatrixWitness, beta: F, gamma: F, - prover_data: &ProverOnlyCircuitData, - common_data: &CommonCircuitData, + prover_data: &ProverOnlyCircuitData, + common_data: &CommonCircuitData, ) -> Vec> { let degree = common_data.quotient_degree_factor; let subgroup = &prover_data.subgroup; @@ -283,12 +289,12 @@ fn wires_permutation_partial_products_and_zs, const const BATCH_SIZE: usize = 32; -fn compute_quotient_polys<'a, F: RichField + Extendable, const D: usize>( - common_data: &CommonCircuitData, - prover_data: &'a ProverOnlyCircuitData, - public_inputs_hash: &HashOut, - wires_commitment: &'a PolynomialBatchCommitment, - zs_partial_products_commitment: &'a PolynomialBatchCommitment, +fn compute_quotient_polys<'a, F: Extendable, C: GenericConfig, const D: usize>( + common_data: &CommonCircuitData, + prover_data: &'a ProverOnlyCircuitData, + public_inputs_hash: &<>::InnerHasher as Hasher>::Hash, + wires_commitment: &'a PolynomialBatchCommitment, + zs_partial_products_commitment: &'a PolynomialBatchCommitment, betas: &[F], gammas: &[F], alphas: &[F], @@ -312,7 +318,7 @@ fn compute_quotient_polys<'a, F: RichField + Extendable, const D: usize>( let lde_size = points.len(); // Retrieve the LDE values at index `i`. - let get_at_index = |comm: &'a PolynomialBatchCommitment, i: usize| -> &'a [F] { + let get_at_index = |comm: &'a PolynomialBatchCommitment, i: usize| -> &'a [F] { comm.get_lde_values(i * step) }; diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index 0a03fab0..a5f5c7dd 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -1,23 +1,23 @@ use crate::field::extension_field::Extendable; -use crate::field::field_types::RichField; use crate::hash::hash_types::HashOutTarget; use crate::iop::challenger::RecursiveChallenger; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; +use crate::plonk::config::AlgebraicConfig; use crate::plonk::proof::ProofWithPublicInputsTarget; use crate::plonk::vanishing_poly::eval_vanishing_poly_recursively; use crate::plonk::vars::EvaluationTargets; use crate::util::reducing::ReducingFactorTarget; use crate::with_context; -impl, const D: usize> CircuitBuilder { +impl, const D: usize> CircuitBuilder { /// Recursively verifies an inner proof. - pub fn add_recursive_verifier( + pub fn add_recursive_verifier>( &mut self, proof_with_pis: ProofWithPublicInputsTarget, inner_config: &CircuitConfig, inner_verifier_data: &VerifierCircuitTarget, - inner_common_data: &CommonCircuitData, + inner_common_data: &CommonCircuitData, ) { let ProofWithPublicInputsTarget { proof, @@ -27,7 +27,7 @@ impl, const D: usize> CircuitBuilder { let num_challenges = inner_config.num_challenges; - let public_inputs_hash = &self.hash_n_to_hash(public_inputs, true); + let public_inputs_hash = &self.hash_n_to_hash::(public_inputs, true); let mut challenger = RecursiveChallenger::new(self); @@ -127,7 +127,6 @@ mod tests { use log::{info, Level}; use super::*; - use crate::field::goldilocks_field::GoldilocksField; use crate::fri::proof::{ FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, }; @@ -138,6 +137,7 @@ mod tests { use crate::hash::merkle_proofs::MerkleProofTarget; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_data::VerifierOnlyCircuitData; + use crate::plonk::config::{GenericConfig, KeccakGoldilocksConfig, PoseidonGoldilocksConfig}; use crate::plonk::proof::{ CompressedProofWithPublicInputs, OpeningSetTarget, Proof, ProofTarget, ProofWithPublicInputs, @@ -147,8 +147,8 @@ mod tests { use crate::util::timing::TimingTree; // Construct a `FriQueryRoundTarget` with the same dimensions as the ones in `proof`. - fn get_fri_query_round, const D: usize>( - proof: &Proof, + fn get_fri_query_round, C: GenericConfig, const D: usize>( + proof: &Proof, builder: &mut CircuitBuilder, ) -> FriQueryRoundTarget { let mut query_round = FriQueryRoundTarget { @@ -180,8 +180,8 @@ mod tests { } // Construct a `ProofTarget` with the same dimensions as `proof`. - fn proof_to_proof_target, const D: usize>( - proof_with_pis: &ProofWithPublicInputs, + fn proof_to_proof_target, C: GenericConfig, const D: usize>( + proof_with_pis: &ProofWithPublicInputs, builder: &mut CircuitBuilder, ) -> ProofWithPublicInputsTarget { let ProofWithPublicInputs { @@ -241,8 +241,8 @@ mod tests { } // Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. - fn set_proof_target, const D: usize>( - proof: &ProofWithPublicInputs, + fn set_proof_target, C: AlgebraicConfig, const D: usize>( + proof: &ProofWithPublicInputs, pt: &ProofWithPublicInputsTarget, pw: &mut PartialWitness, ) { @@ -365,12 +365,14 @@ mod tests { #[ignore] fn test_recursive_verifier() -> Result<()> { init_logger(); - type F = GoldilocksField; const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); - let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; - let (proof, _vd, cd) = recursive_proof(proof, vd, cd, &config, &config, None, true, true)?; + let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; + let (proof, _vd, cd) = + recursive_proof::(proof, vd, cd, &config, &config, None, true, true)?; test_serialization(&proof, &cd)?; Ok(()) @@ -380,18 +382,21 @@ mod tests { #[ignore] fn test_recursive_recursive_verifier() -> Result<()> { init_logger(); - type F = GoldilocksField; const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type KC = KeccakGoldilocksConfig; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); // Start with a degree 2^14 proof, then shrink it to 2^13, then to 2^12. - let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; + let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; assert_eq!(cd.degree_bits, 14); let (proof, vd, cd) = - recursive_proof(proof, vd, cd, &config, &config, Some(13), false, false)?; + recursive_proof::(proof, vd, cd, &config, &config, Some(13), false, false)?; assert_eq!(cd.degree_bits, 13); - let (proof, _vd, cd) = recursive_proof(proof, vd, cd, &config, &config, None, true, true)?; + let (proof, _vd, cd) = + recursive_proof::(proof, vd, cd, &config, &config, None, true, true)?; assert_eq!(cd.degree_bits, 12); test_serialization(&proof, &cd)?; @@ -405,13 +410,15 @@ mod tests { #[ignore] fn test_size_optimized_recursion() -> Result<()> { init_logger(); - type F = GoldilocksField; const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type KC = KeccakGoldilocksConfig; + type F = >::F; let standard_config = CircuitConfig::standard_recursion_config(); // An initial dummy proof. - let (proof, vd, cd) = dummy_proof::(&standard_config, 4_000)?; + let (proof, vd, cd) = dummy_proof::(&standard_config, 4_000)?; assert_eq!(cd.degree_bits, 12); // A standard recursive proof. @@ -437,7 +444,7 @@ mod tests { }, ..standard_config }; - let (proof, vd, cd) = recursive_proof( + let (proof, vd, cd) = recursive_proof::( proof, vd, cd, @@ -461,7 +468,7 @@ mod tests { }, ..high_rate_config }; - let (proof, _vd, cd) = recursive_proof( + let (proof, _vd, cd) = recursive_proof::( proof, vd, cd, @@ -479,20 +486,20 @@ mod tests { } /// Creates a dummy proof which should have roughly `num_dummy_gates` gates. - fn dummy_proof, const D: usize>( + fn dummy_proof, C: GenericConfig, const D: usize>( config: &CircuitConfig, num_dummy_gates: u64, ) -> Result<( - ProofWithPublicInputs, - VerifierOnlyCircuitData, - CommonCircuitData, + ProofWithPublicInputs, + VerifierOnlyCircuitData, + CommonCircuitData, )> { let mut builder = CircuitBuilder::::new(config.clone()); for _ in 0..num_dummy_gates { builder.add_gate(NoopGate, vec![]); } - let data = builder.build(); + let data = builder.build::(); let inputs = PartialWitness::new(); let proof = data.prove(inputs)?; data.verify(proof.clone())?; @@ -500,19 +507,24 @@ mod tests { Ok((proof, data.verifier_only, data.common)) } - fn recursive_proof, const D: usize>( - inner_proof: ProofWithPublicInputs, - inner_vd: VerifierOnlyCircuitData, - inner_cd: CommonCircuitData, + fn recursive_proof< + F: Extendable, + C: GenericConfig, + InnerC: AlgebraicConfig, + const D: usize, + >( + inner_proof: ProofWithPublicInputs, + inner_vd: VerifierOnlyCircuitData, + inner_cd: CommonCircuitData, inner_config: &CircuitConfig, config: &CircuitConfig, min_degree_bits: Option, print_gate_counts: bool, print_timing: bool, ) -> Result<( - ProofWithPublicInputs, - VerifierOnlyCircuitData, - CommonCircuitData, + ProofWithPublicInputs, + VerifierOnlyCircuitData, + CommonCircuitData, )> { let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); @@ -543,7 +555,7 @@ mod tests { } } - let data = builder.build(); + let data = builder.build::(); let mut timing = TimingTree::new("prove", Level::Debug); let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?; @@ -557,9 +569,9 @@ mod tests { } /// Test serialization and print some size info. - fn test_serialization, const D: usize>( - proof: &ProofWithPublicInputs, - cd: &CommonCircuitData, + fn test_serialization, C: GenericConfig, const D: usize>( + proof: &ProofWithPublicInputs, + cd: &CommonCircuitData, ) -> Result<()> { let proof_bytes = proof.to_bytes()?; info!("Proof length: {} bytes", proof_bytes.len()); diff --git a/src/plonk/vanishing_poly.rs b/src/plonk/vanishing_poly.rs index a467c363..e1f35bd4 100644 --- a/src/plonk/vanishing_poly.rs +++ b/src/plonk/vanishing_poly.rs @@ -1,11 +1,12 @@ use crate::field::batch_util::batch_add_inplace; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::gate::PrefixedGate; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CommonCircuitData; +use crate::plonk::config::GenericConfig; use crate::plonk::plonk_common; use crate::plonk::plonk_common::{eval_l_1_recursively, ZeroPolyOnCoset}; use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBaseBatch}; @@ -17,8 +18,8 @@ use crate::with_context; /// Evaluate the vanishing polynomial at `x`. In this context, the vanishing polynomial is a random /// linear combination of gate constraints, plus some other terms relating to the permutation /// argument. All such terms should vanish on `H`. -pub(crate) fn eval_vanishing_poly, const D: usize>( - common_data: &CommonCircuitData, +pub(crate) fn eval_vanishing_poly, C: GenericConfig, const D: usize>( + common_data: &CommonCircuitData, x: F::Extension, vars: EvaluationVars, local_zs: &[F::Extension], @@ -89,8 +90,12 @@ pub(crate) fn eval_vanishing_poly, const D: usize>( } /// Like `eval_vanishing_poly`, but specialized for base field points. Batched. -pub(crate) fn eval_vanishing_poly_base_batch, const D: usize>( - common_data: &CommonCircuitData, +pub(crate) fn eval_vanishing_poly_base_batch< + F: Extendable, + C: GenericConfig, + const D: usize, +>( + common_data: &CommonCircuitData, indices_batch: &[usize], xs_batch: &[F], vars_batch: EvaluationVarsBaseBatch, @@ -196,7 +201,7 @@ pub(crate) fn eval_vanishing_poly_base_batch, const /// `num_gate_constraints` is the largest number of constraints imposed by any gate. It is not /// strictly necessary, but it helps performance by ensuring that we allocate a vector with exactly /// the capacity that we need. -pub fn evaluate_gate_constraints, const D: usize>( +pub fn evaluate_gate_constraints, const D: usize>( gates: &[PrefixedGate], num_gate_constraints: usize, vars: EvaluationVars, @@ -220,7 +225,7 @@ pub fn evaluate_gate_constraints, const D: usize>( /// Returns a vector of `num_gate_constraints * vars_batch.len()` field elements. The constraints /// corresponding to `vars_batch[i]` are found in `result[i], result[vars_batch.len() + i], /// result[2 * vars_batch.len() + i], ...`. -pub fn evaluate_gate_constraints_base_batch, const D: usize>( +pub fn evaluate_gate_constraints_base_batch, const D: usize>( gates: &[PrefixedGate], num_gate_constraints: usize, vars_batch: EvaluationVarsBaseBatch, @@ -244,7 +249,7 @@ pub fn evaluate_gate_constraints_base_batch, const constraints_batch } -pub fn evaluate_gate_constraints_recursively, const D: usize>( +pub fn evaluate_gate_constraints_recursively, const D: usize>( builder: &mut CircuitBuilder, gates: &[PrefixedGate], num_gate_constraints: usize, @@ -272,9 +277,13 @@ pub fn evaluate_gate_constraints_recursively, const /// /// Assumes `x != 1`; if `x` could be 1 then this is unsound. This is fine if `x` is a random /// variable drawn from a sufficiently large domain. -pub(crate) fn eval_vanishing_poly_recursively, const D: usize>( +pub(crate) fn eval_vanishing_poly_recursively< + F: Extendable, + C: GenericConfig, + const D: usize, +>( builder: &mut CircuitBuilder, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, x: ExtensionTarget, x_pow_deg: ExtensionTarget, vars: EvaluationTargets, diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index e21fe328..cf27d26f 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -1,28 +1,33 @@ use anyhow::{ensure, Result}; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::fri::verifier::verify_fri_proof; use crate::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; +use crate::plonk::config::GenericConfig; use crate::plonk::plonk_common::reduce_with_powers; use crate::plonk::proof::{ProofChallenges, ProofWithPublicInputs}; use crate::plonk::vanishing_poly::eval_vanishing_poly; use crate::plonk::vars::EvaluationVars; -pub(crate) fn verify, const D: usize>( - proof_with_pis: ProofWithPublicInputs, - verifier_data: &VerifierOnlyCircuitData, - common_data: &CommonCircuitData, +pub(crate) fn verify, C: GenericConfig, const D: usize>( + proof_with_pis: ProofWithPublicInputs, + verifier_data: &VerifierOnlyCircuitData, + common_data: &CommonCircuitData, ) -> Result<()> { let challenges = proof_with_pis.get_challenges(common_data)?; verify_with_challenges(proof_with_pis, challenges, verifier_data, common_data) } -pub(crate) fn verify_with_challenges, const D: usize>( - proof_with_pis: ProofWithPublicInputs, +pub(crate) fn verify_with_challenges< + F: Extendable, + C: GenericConfig, + const D: usize, +>( + proof_with_pis: ProofWithPublicInputs, challenges: ProofChallenges, - verifier_data: &VerifierOnlyCircuitData, - common_data: &CommonCircuitData, + verifier_data: &VerifierOnlyCircuitData, + common_data: &CommonCircuitData, ) -> Result<()> { let public_inputs_hash = &proof_with_pis.get_public_inputs_hash(); diff --git a/src/util/reducing.rs b/src/util/reducing.rs index 4fc15690..562293e5 100644 --- a/src/util/reducing.rs +++ b/src/util/reducing.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; -use crate::field::field_types::{Field, RichField}; +use crate::field::field_types::Field; use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::reducing::ReducingGate; use crate::gates::reducing_extension::ReducingExtensionGate; @@ -102,7 +102,7 @@ impl ReducingFactorTarget { builder: &mut CircuitBuilder, ) -> ExtensionTarget where - F: RichField + Extendable, + F: Extendable, { let l = terms.len(); @@ -157,7 +157,7 @@ impl ReducingFactorTarget { builder: &mut CircuitBuilder, ) -> ExtensionTarget where - F: RichField + Extendable, + F: Extendable, { let l = terms.len(); @@ -217,7 +217,7 @@ impl ReducingFactorTarget { builder: &mut CircuitBuilder, ) -> ExtensionTarget where - F: RichField + Extendable, + F: Extendable, { self.count += terms.len() as u64; terms @@ -234,7 +234,7 @@ impl ReducingFactorTarget { builder: &mut CircuitBuilder, ) -> ExtensionTarget where - F: RichField + Extendable, + F: Extendable, { let exp = builder.exp_u64_extension(self.base, self.count); self.count = 0; @@ -251,16 +251,16 @@ mod tests { use anyhow::Result; use super::*; - use crate::field::extension_field::quartic::QuarticExtension; - use crate::field::goldilocks_field::GoldilocksField; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn test_reduce_gadget_base(n: usize) -> Result<()> { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -279,16 +279,17 @@ mod tests { builder.connect_extension(manual_reduce, circuit_reduce); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) } fn test_reduce_gadget(n: usize) -> Result<()> { - type F = GoldilocksField; - type FF = QuarticExtension; - const D: usize = 4; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -310,7 +311,7 @@ mod tests { builder.connect_extension(manual_reduce, circuit_reduce); - let data = builder.build(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/src/util/serialization.rs b/src/util/serialization.rs index b3a51b5f..06f2a3e5 100644 --- a/src/util/serialization.rs +++ b/src/util/serialization.rs @@ -8,10 +8,10 @@ use crate::fri::proof::{ CompressedFriProof, CompressedFriQueryRounds, FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep, }; -use crate::hash::hash_types::HashOut; use crate::hash::merkle_proofs::MerkleProof; use crate::hash::merkle_tree::MerkleCap; use crate::plonk::circuit_data::CommonCircuitData; +use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::proof::{ CompressedProof, CompressedProofWithPublicInputs, OpeningSet, Proof, ProofWithPublicInputs, }; @@ -78,42 +78,45 @@ impl Buffer { )) } - fn write_hash(&mut self, h: HashOut) -> Result<()> { - for &a in &h.elements { - self.write_field(a)?; - } - Ok(()) - } - fn read_hash(&mut self) -> Result> { - let mut elements = [F::ZERO; 4]; - for a in elements.iter_mut() { - *a = self.read_field()?; - } - Ok(HashOut { elements }) + fn write_hash>(&mut self, h: H::Hash) -> Result<()> { + let bytes: Vec = h.into(); + self.0.write_all(&bytes) } - fn write_merkle_cap(&mut self, cap: &MerkleCap) -> Result<()> { + fn read_hash>(&mut self) -> Result { + let mut buf = vec![0; H::HASH_SIZE]; + self.0.read_exact(&mut buf)?; + Ok(H::Hash::from(buf.to_vec())) + } + + fn write_merkle_cap>( + &mut self, + cap: &MerkleCap, + ) -> Result<()> { for &a in &cap.0 { - self.write_hash(a)?; + self.write_hash::(a)?; } Ok(()) } - fn read_merkle_cap(&mut self, cap_height: usize) -> Result> { + fn read_merkle_cap>( + &mut self, + cap_height: usize, + ) -> Result> { let cap_length = 1 << cap_height; Ok(MerkleCap( (0..cap_length) - .map(|_| self.read_hash()) + .map(|_| self.read_hash::()) .collect::>>()?, )) } - fn write_field_vec(&mut self, v: &[F]) -> Result<()> { + pub fn write_field_vec(&mut self, v: &[F]) -> Result<()> { for &a in v { self.write_field(a)?; } Ok(()) } - fn read_field_vec(&mut self, length: usize) -> Result> { + pub fn read_field_vec(&mut self, length: usize) -> Result> { (0..length) .map(|_| self.read_field()) .collect::>>() @@ -149,9 +152,9 @@ impl Buffer { self.write_field_ext_vec::(&os.partial_products)?; self.write_field_ext_vec::(&os.quotient_polys) } - fn read_opening_set, const D: usize>( + fn read_opening_set, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let constants = self.read_field_ext_vec::(common_data.num_constants)?; @@ -176,7 +179,10 @@ impl Buffer { }) } - fn write_merkle_proof(&mut self, p: &MerkleProof) -> Result<()> { + fn write_merkle_proof>( + &mut self, + p: &MerkleProof, + ) -> Result<()> { let length = p.siblings.len(); self.write_u8( length @@ -184,22 +190,22 @@ impl Buffer { .expect("Merkle proof length must fit in u8."), )?; for &h in &p.siblings { - self.write_hash(h)?; + self.write_hash::(h)?; } Ok(()) } - fn read_merkle_proof(&mut self) -> Result> { + fn read_merkle_proof>(&mut self) -> Result> { let length = self.read_u8()?; Ok(MerkleProof { siblings: (0..length) - .map(|_| self.read_hash()) + .map(|_| self.read_hash::()) .collect::>>()?, }) } - fn write_fri_initial_proof( + fn write_fri_initial_proof, C: GenericConfig, const D: usize>( &mut self, - fitp: &FriInitialTreeProof, + fitp: &FriInitialTreeProof, ) -> Result<()> { for (v, p) in &fitp.evals_proofs { self.write_field_vec(v)?; @@ -207,10 +213,10 @@ impl Buffer { } Ok(()) } - fn read_fri_initial_proof, const D: usize>( + fn read_fri_initial_proof, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let config = &common_data.config; let mut evals_proofs = Vec::with_capacity(4); @@ -236,18 +242,18 @@ impl Buffer { Ok(FriInitialTreeProof { evals_proofs }) } - fn write_fri_query_step, const D: usize>( + fn write_fri_query_step, C: GenericConfig, const D: usize>( &mut self, - fqs: &FriQueryStep, + fqs: &FriQueryStep, ) -> Result<()> { self.write_field_ext_vec::(&fqs.evals)?; self.write_merkle_proof(&fqs.merkle_proof) } - fn read_fri_query_step, const D: usize>( + fn read_fri_query_step, C: GenericConfig, const D: usize>( &mut self, arity: usize, compressed: bool, - ) -> Result> { + ) -> Result> { let evals = self.read_field_ext_vec::(arity - if compressed { 1 } else { 0 })?; let merkle_proof = self.read_merkle_proof()?; Ok(FriQueryStep { @@ -256,22 +262,22 @@ impl Buffer { }) } - fn write_fri_query_rounds, const D: usize>( + fn write_fri_query_rounds, C: GenericConfig, const D: usize>( &mut self, - fqrs: &[FriQueryRound], + fqrs: &[FriQueryRound], ) -> Result<()> { for fqr in fqrs { - self.write_fri_initial_proof(&fqr.initial_trees_proof)?; + self.write_fri_initial_proof::(&fqr.initial_trees_proof)?; for fqs in &fqr.steps { - self.write_fri_query_step(fqs)?; + self.write_fri_query_step::(fqs)?; } } Ok(()) } - fn read_fri_query_rounds, const D: usize>( + fn read_fri_query_rounds, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, - ) -> Result>> { + common_data: &CommonCircuitData, + ) -> Result>> { let config = &common_data.config; let mut fqrs = Vec::with_capacity(config.fri_config.num_query_rounds); for _ in 0..config.fri_config.num_query_rounds { @@ -280,7 +286,7 @@ impl Buffer { .fri_params .reduction_arity_bits .iter() - .map(|&ar| self.read_fri_query_step(1 << ar, false)) + .map(|&ar| self.read_fri_query_step::(1 << ar, false)) .collect::>()?; fqrs.push(FriQueryRound { initial_trees_proof, @@ -290,21 +296,21 @@ impl Buffer { Ok(fqrs) } - fn write_fri_proof, const D: usize>( + fn write_fri_proof, C: GenericConfig, const D: usize>( &mut self, - fp: &FriProof, + fp: &FriProof, ) -> Result<()> { for cap in &fp.commit_phase_merkle_caps { self.write_merkle_cap(cap)?; } - self.write_fri_query_rounds(&fp.query_round_proofs)?; + self.write_fri_query_rounds::(&fp.query_round_proofs)?; self.write_field_ext_vec::(&fp.final_poly.coeffs)?; self.write_field(fp.pow_witness) } - fn read_fri_proof, const D: usize>( + fn read_fri_proof, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.cap_height)) @@ -321,20 +327,20 @@ impl Buffer { }) } - pub fn write_proof, const D: usize>( + pub fn write_proof, C: GenericConfig, const D: usize>( &mut self, - proof: &Proof, + proof: &Proof, ) -> Result<()> { self.write_merkle_cap(&proof.wires_cap)?; self.write_merkle_cap(&proof.plonk_zs_partial_products_cap)?; self.write_merkle_cap(&proof.quotient_polys_cap)?; self.write_opening_set(&proof.openings)?; - self.write_fri_proof(&proof.opening_proof) + self.write_fri_proof::(&proof.opening_proof) } - pub fn read_proof, const D: usize>( + pub fn read_proof, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.cap_height)?; @@ -351,9 +357,13 @@ impl Buffer { }) } - pub fn write_proof_with_public_inputs, const D: usize>( + pub fn write_proof_with_public_inputs< + F: Extendable, + C: GenericConfig, + const D: usize, + >( &mut self, - proof_with_pis: &ProofWithPublicInputs, + proof_with_pis: &ProofWithPublicInputs, ) -> Result<()> { let ProofWithPublicInputs { proof, @@ -362,10 +372,14 @@ impl Buffer { self.write_proof(proof)?; self.write_field_vec(public_inputs) } - pub fn read_proof_with_public_inputs, const D: usize>( + pub fn read_proof_with_public_inputs< + F: Extendable, + C: GenericConfig, + const D: usize, + >( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let proof = self.read_proof(common_data)?; let public_inputs = self.read_field_vec( (self.len() - self.0.position() as usize) / std::mem::size_of::(), @@ -377,9 +391,13 @@ impl Buffer { }) } - fn write_compressed_fri_query_rounds, const D: usize>( + fn write_compressed_fri_query_rounds< + F: Extendable, + C: GenericConfig, + const D: usize, + >( &mut self, - cfqrs: &CompressedFriQueryRounds, + cfqrs: &CompressedFriQueryRounds, ) -> Result<()> { for &i in &cfqrs.indices { self.write_u32(i as u32)?; @@ -388,21 +406,25 @@ impl Buffer { let mut initial_trees_proofs = cfqrs.initial_trees_proofs.iter().collect::>(); initial_trees_proofs.sort_by_key(|&x| x.0); for (_, itp) in initial_trees_proofs { - self.write_fri_initial_proof(itp)?; + self.write_fri_initial_proof::(itp)?; } for h in &cfqrs.steps { let mut fri_query_steps = h.iter().collect::>(); fri_query_steps.sort_by_key(|&x| x.0); for (_, fqs) in fri_query_steps { - self.write_fri_query_step(fqs)?; + self.write_fri_query_step::(fqs)?; } } Ok(()) } - fn read_compressed_fri_query_rounds, const D: usize>( + fn read_compressed_fri_query_rounds< + F: Extendable, + C: GenericConfig, + const D: usize, + >( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let config = &common_data.config; let original_indices = (0..config.fri_config.num_query_rounds) .map(|_| self.read_u32().map(|i| i as usize)) @@ -423,7 +445,7 @@ impl Buffer { }); indices.dedup(); let query_steps = (0..indices.len()) - .map(|_| self.read_fri_query_step(1 << a, true)) + .map(|_| self.read_fri_query_step::(1 << a, true)) .collect::>>()?; steps.push( indices @@ -441,21 +463,21 @@ impl Buffer { }) } - fn write_compressed_fri_proof, const D: usize>( + fn write_compressed_fri_proof, C: GenericConfig, const D: usize>( &mut self, - fp: &CompressedFriProof, + fp: &CompressedFriProof, ) -> Result<()> { for cap in &fp.commit_phase_merkle_caps { self.write_merkle_cap(cap)?; } - self.write_compressed_fri_query_rounds(&fp.query_round_proofs)?; + self.write_compressed_fri_query_rounds::(&fp.query_round_proofs)?; self.write_field_ext_vec::(&fp.final_poly.coeffs)?; self.write_field(fp.pow_witness) } - fn read_compressed_fri_proof, const D: usize>( + fn read_compressed_fri_proof, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.cap_height)) @@ -472,20 +494,20 @@ impl Buffer { }) } - pub fn write_compressed_proof, const D: usize>( + pub fn write_compressed_proof, C: GenericConfig, const D: usize>( &mut self, - proof: &CompressedProof, + proof: &CompressedProof, ) -> Result<()> { self.write_merkle_cap(&proof.wires_cap)?; self.write_merkle_cap(&proof.plonk_zs_partial_products_cap)?; self.write_merkle_cap(&proof.quotient_polys_cap)?; self.write_opening_set(&proof.openings)?; - self.write_compressed_fri_proof(&proof.opening_proof) + self.write_compressed_fri_proof::(&proof.opening_proof) } - pub fn read_compressed_proof, const D: usize>( + pub fn read_compressed_proof, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.cap_height)?; @@ -503,11 +525,12 @@ impl Buffer { } pub fn write_compressed_proof_with_public_inputs< - F: RichField + Extendable, + F: Extendable, + C: GenericConfig, const D: usize, >( &mut self, - proof_with_pis: &CompressedProofWithPublicInputs, + proof_with_pis: &CompressedProofWithPublicInputs, ) -> Result<()> { let CompressedProofWithPublicInputs { proof, @@ -517,12 +540,13 @@ impl Buffer { self.write_field_vec(public_inputs) } pub fn read_compressed_proof_with_public_inputs< - F: RichField + Extendable, + F: Extendable, + C: GenericConfig, const D: usize, >( &mut self, - common_data: &CommonCircuitData, - ) -> Result> { + common_data: &CommonCircuitData, + ) -> Result> { let proof = self.read_compressed_proof(common_data)?; let public_inputs = self.read_field_vec( (self.len() - self.0.position() as usize) / std::mem::size_of::(),