From fcef5a57f5f38bd39e8ed5989c58ad8fd6b8c50f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 7 Feb 2022 10:25:01 +0100 Subject: [PATCH 01/20] Fibonacci recursive constraints --- starky/src/fibonacci_stark.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index c77775e8..18bc46b5 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -79,7 +79,25 @@ impl, const D: usize> Stark for FibonacciStar vars: StarkEvaluationTargets, yield_constr: &mut RecursiveConstraintConsumer, ) { - todo!() + // Check public inputs. + let pis_constraints = [ + builder.sub_extension(vars.local_values[0], vars.public_inputs[Self::PI_INDEX_X0]), + builder.sub_extension(vars.local_values[1], vars.public_inputs[Self::PI_INDEX_X1]), + builder.sub_extension(vars.local_values[1], vars.public_inputs[Self::PI_INDEX_RES]), + ]; + yield_constr.constraint_first_row(builder, pis_constraints[0]); + yield_constr.constraint_first_row(builder, pis_constraints[1]); + yield_constr.constraint_last_row(builder, pis_constraints[2]); + + // x0 <- x1 + let first_col_constraint = builder.sub_extension(vars.next_values[0], vars.local_values[1]); + yield_constr.constraint(builder, first_col_constraint); + // x1 <- x0 + x1 + let second_col_constraint = { + let tmp = builder.sub_extension(vars.next_values[1], vars.local_values[0]); + builder.sub_extension(tmp, vars.local_values[1]) + }; + yield_constr.constraint(builder, second_col_constraint); } fn constraint_degree(&self) -> usize { From debe742c7f6817a960c9804f13b8e311f6e211fa Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 7 Feb 2022 10:41:52 +0100 Subject: [PATCH 02/20] Progress --- starky/src/lib.rs | 1 + starky/src/proof.rs | 26 ++++- starky/src/recursive_verifier.rs | 195 +++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 starky/src/recursive_verifier.rs diff --git a/starky/src/lib.rs b/starky/src/lib.rs index dc61e7e7..37dec4f8 100644 --- a/starky/src/lib.rs +++ b/starky/src/lib.rs @@ -11,6 +11,7 @@ pub mod constraint_consumer; mod get_challenges; pub mod proof; pub mod prover; +pub mod recursive_verifier; pub mod stark; pub mod stark_testing; pub mod vars; diff --git a/starky/src/proof.rs b/starky/src/proof.rs index b7ecd912..4a6de0bb 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -1,9 +1,11 @@ use plonky2::field::extension_field::Extendable; use plonky2::fri::oracle::PolynomialBatch; -use plonky2::fri::proof::{CompressedFriProof, FriChallenges, FriProof}; +use plonky2::fri::proof::{CompressedFriProof, FriChallenges, FriProof, FriProofTarget}; use plonky2::fri::structure::{FriOpeningBatch, FriOpenings}; -use plonky2::hash::hash_types::RichField; +use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; use plonky2::hash::merkle_tree::MerkleCap; +use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::target::Target; use plonky2::plonk::config::GenericConfig; use rayon::prelude::*; @@ -18,6 +20,13 @@ pub struct StarkProof, C: GenericConfig, pub opening_proof: FriProof, } +pub struct StarkProofTarget { + pub trace_cap: MerkleCapTarget, + pub quotient_polys_cap: MerkleCapTarget, + pub openings: StarkOpeningSetTarget, + pub opening_proof: FriProofTarget, +} + pub struct StarkProofWithPublicInputs< F: RichField + Extendable, C: GenericConfig, @@ -28,6 +37,11 @@ pub struct StarkProofWithPublicInputs< pub public_inputs: Vec, } +pub struct StarkProofWithPublicInputsTarget { + pub proof: StarkProofTarget, + pub public_inputs: Vec, +} + pub struct CompressedStarkProof< F: RichField + Extendable, C: GenericConfig, @@ -112,3 +126,11 @@ impl, const D: usize> StarkOpeningSet { } } } + +pub struct StarkOpeningSetTarget { + pub local_values: Vec>, + pub next_values: Vec>, + pub permutation_zs: Vec>, + pub permutation_zs_right: Vec>, + pub quotient_polys: Vec>, +} diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs new file mode 100644 index 00000000..5b8e9a8a --- /dev/null +++ b/starky/src/recursive_verifier.rs @@ -0,0 +1,195 @@ +use plonky2::field::extension_field::Extendable; +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::config::GenericConfig; +use crate::config::StarkConfig; +use crate::proof::StarkProofWithPublicInputsTarget; +use crate::stark::Stark; + +pub fn verify_stark_proof< F: RichField + Extendable, + C: GenericConfig, + S: Stark, + const D: usize, + >( + builder: &mut CircuitBuilder, + stark: S, + proof_with_pis: StarkProofWithPublicInputsTarget, + inner_config: &StarkConfig + ) + { + let StarkProofWithPublicInputsTarget { + proof, + public_inputs, + } = proof_with_pis; + + assert_eq!(public_inputs.len(), inner_common_data.num_public_inputs); + let public_inputs_hash = self.hash_n_to_hash_no_pad::(public_inputs); + + self.verify_proof( + proof, + public_inputs_hash, + inner_verifier_data, + inner_common_data, + ); + } + + /// Recursively verifies an inner proof. + pub fn verify_proof>( + &mut self, + proof: ProofTarget, + public_inputs_hash: HashOutTarget, + inner_verifier_data: &VerifierCircuitTarget, + inner_common_data: &CommonCircuitData, + ) where + C::Hasher: AlgebraicHasher, + { + let one = self.one_extension(); + + let num_challenges = inner_common_data.config.num_challenges; + + let mut challenger = RecursiveChallenger::::new(self); + + let (betas, gammas, alphas, zeta) = + with_context!(self, "observe proof and generates challenges", { + // Observe the instance. + let digest = HashOutTarget::from_vec( + self.constants(&inner_common_data.circuit_digest.elements), + ); + challenger.observe_hash(&digest); + challenger.observe_hash(&public_inputs_hash); + + challenger.observe_cap(&proof.wires_cap); + let betas = challenger.get_n_challenges(self, num_challenges); + let gammas = challenger.get_n_challenges(self, num_challenges); + + challenger.observe_cap(&proof.plonk_zs_partial_products_cap); + let alphas = challenger.get_n_challenges(self, num_challenges); + + challenger.observe_cap(&proof.quotient_polys_cap); + let zeta = challenger.get_extension_challenge(self); + + (betas, gammas, alphas, zeta) + }); + + let local_constants = &proof.openings.constants; + let local_wires = &proof.openings.wires; + let vars = EvaluationTargets { + local_constants, + local_wires, + public_inputs_hash: &public_inputs_hash, + }; + let local_zs = &proof.openings.plonk_zs; + let next_zs = &proof.openings.plonk_zs_right; + let s_sigmas = &proof.openings.plonk_sigmas; + let partial_products = &proof.openings.partial_products; + + let zeta_pow_deg = self.exp_power_of_2_extension(zeta, inner_common_data.degree_bits); + let vanishing_polys_zeta = with_context!( + self, + "evaluate the vanishing polynomial at our challenge point, zeta.", + eval_vanishing_poly_recursively( + self, + inner_common_data, + zeta, + zeta_pow_deg, + vars, + local_zs, + next_zs, + partial_products, + s_sigmas, + &betas, + &gammas, + &alphas, + ) + ); + + with_context!(self, "check vanishing and quotient polynomials.", { + let quotient_polys_zeta = &proof.openings.quotient_polys; + let mut scale = ReducingFactorTarget::new(zeta_pow_deg); + let z_h_zeta = self.sub_extension(zeta_pow_deg, one); + for (i, chunk) in quotient_polys_zeta + .chunks(inner_common_data.quotient_degree_factor) + .enumerate() + { + let recombined_quotient = scale.reduce(chunk, self); + let computed_vanishing_poly = self.mul_extension(z_h_zeta, recombined_quotient); + self.connect_extension(vanishing_polys_zeta[i], computed_vanishing_poly); + } + }); + + let merkle_caps = &[ + inner_verifier_data.constants_sigmas_cap.clone(), + proof.wires_cap, + proof.plonk_zs_partial_products_cap, + proof.quotient_polys_cap, + ]; + + let fri_instance = inner_common_data.get_fri_instance_target(self, zeta); + with_context!( + self, + "verify FRI proof", + self.verify_fri_proof::( + &fri_instance, + &proof.openings, + merkle_caps, + &proof.opening_proof, + &mut challenger, + &inner_common_data.fri_params, + ) + ); + } + + pub fn add_virtual_proof_with_pis>( + &mut self, + common_data: &CommonCircuitData, + ) -> ProofWithPublicInputsTarget { + let proof = self.add_virtual_proof(common_data); + let public_inputs = self.add_virtual_targets(common_data.num_public_inputs); + ProofWithPublicInputsTarget { + proof, + public_inputs, + } + } + + fn add_virtual_proof>( + &mut self, + common_data: &CommonCircuitData, + ) -> ProofTarget { + let config = &common_data.config; + let fri_params = &common_data.fri_params; + let cap_height = fri_params.config.cap_height; + + let num_leaves_per_oracle = &[ + common_data.num_preprocessed_polys(), + config.num_wires, + common_data.num_zs_partial_products_polys(), + common_data.num_quotient_polys(), + ]; + + ProofTarget { + wires_cap: self.add_virtual_cap(cap_height), + plonk_zs_partial_products_cap: self.add_virtual_cap(cap_height), + quotient_polys_cap: self.add_virtual_cap(cap_height), + openings: self.add_opening_set(common_data), + opening_proof: self.add_virtual_fri_proof(num_leaves_per_oracle, fri_params), + } + } + + fn add_opening_set>( + &mut self, + common_data: &CommonCircuitData, + ) -> OpeningSetTarget { + let config = &common_data.config; + let num_challenges = config.num_challenges; + let total_partial_products = num_challenges * common_data.num_partial_products; + OpeningSetTarget { + constants: self.add_virtual_extension_targets(common_data.num_constants), + plonk_sigmas: self.add_virtual_extension_targets(config.num_routed_wires), + wires: self.add_virtual_extension_targets(config.num_wires), + plonk_zs: self.add_virtual_extension_targets(num_challenges), + plonk_zs_right: self.add_virtual_extension_targets(num_challenges), + partial_products: self.add_virtual_extension_targets(total_partial_products), + quotient_polys: self.add_virtual_extension_targets(common_data.num_quotient_polys()), + } + } +} From ba63a37b7dbe69cad17bfd3b2285e62d89f759cc Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Feb 2022 18:16:33 +0100 Subject: [PATCH 03/20] Compiles --- plonky2/src/fri/challenges.rs | 4 +- plonky2/src/iop/challenger.rs | 4 +- plonky2/src/plonk/get_challenges.rs | 2 +- starky/src/constraint_consumer.rs | 30 ++- starky/src/get_challenges.rs | 99 ++++++- starky/src/proof.rs | 67 ++++- starky/src/prover.rs | 4 +- starky/src/recursive_verifier.rs | 387 +++++++++++++++------------- starky/src/stark.rs | 39 ++- starky/src/verifier.rs | 17 +- 10 files changed, 428 insertions(+), 225 deletions(-) diff --git a/plonky2/src/fri/challenges.rs b/plonky2/src/fri/challenges.rs index 82438383..9222ebc8 100644 --- a/plonky2/src/fri/challenges.rs +++ b/plonky2/src/fri/challenges.rs @@ -89,9 +89,9 @@ impl, H: AlgebraicHasher, const D: usize> commit_phase_merkle_caps: &[MerkleCapTarget], final_poly: &PolynomialCoeffsExtTarget, pow_witness: Target, - inner_common_data: &CommonCircuitData, + inner_fri_config: &FriConfig, ) -> FriChallengesTarget { - let num_fri_queries = inner_common_data.config.fri_config.num_query_rounds; + let num_fri_queries = inner_fri_config.num_query_rounds; // Scaling factor to combine polynomials. let fri_alpha = self.get_extension_challenge(builder); diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index 1519f6ec..c3a4403a 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -166,7 +166,7 @@ pub struct RecursiveChallenger, H: AlgebraicHasher< impl, H: AlgebraicHasher, const D: usize> RecursiveChallenger { - pub(crate) fn new(builder: &mut CircuitBuilder) -> Self { + pub fn new(builder: &mut CircuitBuilder) -> Self { let zero = builder.zero(); RecursiveChallenger { sponge_state: [zero; SPONGE_WIDTH], @@ -222,7 +222,7 @@ impl, H: AlgebraicHasher, const D: usize> .expect("Output buffer should be non-empty") } - pub(crate) fn get_n_challenges( + pub fn get_n_challenges( &mut self, builder: &mut CircuitBuilder, n: usize, diff --git a/plonky2/src/plonk/get_challenges.rs b/plonky2/src/plonk/get_challenges.rs index a67a6207..e8fd3933 100644 --- a/plonky2/src/plonk/get_challenges.rs +++ b/plonky2/src/plonk/get_challenges.rs @@ -275,7 +275,7 @@ impl, const D: usize> CircuitBuilder { commit_phase_merkle_caps, final_poly, pow_witness, - inner_common_data, + &inner_common_data.config.fri_config, ), } } diff --git a/starky/src/constraint_consumer.rs b/starky/src/constraint_consumer.rs index c909b520..932b2db8 100644 --- a/starky/src/constraint_consumer.rs +++ b/starky/src/constraint_consumer.rs @@ -80,10 +80,10 @@ impl ConstraintConsumer

{ pub struct RecursiveConstraintConsumer, const D: usize> { /// A random value used to combine multiple constraints into one. - alpha: Target, + alphas: Vec, /// A running sum of constraints that have been emitted so far, scaled by powers of alpha. - constraint_acc: ExtensionTarget, + constraint_accs: Vec>, /// The evaluation of `X - g^(n-1)`. z_last: ExtensionTarget, @@ -100,6 +100,27 @@ pub struct RecursiveConstraintConsumer, const D: us } impl, const D: usize> RecursiveConstraintConsumer { + pub fn new( + zero: ExtensionTarget, + alphas: Vec, + z_last: ExtensionTarget, + lagrange_basis_first: ExtensionTarget, + lagrange_basis_last: ExtensionTarget, + ) -> Self { + Self { + constraint_accs: vec![zero; alphas.len()], + alphas, + z_last, + lagrange_basis_first, + lagrange_basis_last, + _phantom: Default::default(), + } + } + + pub fn accumulators(self) -> Vec> { + self.constraint_accs + } + /// Add one constraint valid on all rows except the last. pub fn constraint( &mut self, @@ -116,8 +137,9 @@ impl, const D: usize> RecursiveConstraintConsumer, constraint: ExtensionTarget, ) { - self.constraint_acc = - builder.scalar_mul_add_extension(self.alpha, self.constraint_acc, constraint); + for (&alpha, acc) in self.alphas.iter().zip(&mut self.constraint_accs) { + *acc = builder.scalar_mul_add_extension(alpha, *acc, constraint); + } } /// Add one constraint, but first multiply it by a filter such that it will only apply to the diff --git a/starky/src/get_challenges.rs b/starky/src/get_challenges.rs index 7e89ca3e..d44075e7 100644 --- a/starky/src/get_challenges.rs +++ b/starky/src/get_challenges.rs @@ -1,14 +1,21 @@ use anyhow::Result; use plonky2::field::extension_field::Extendable; use plonky2::field::polynomial::PolynomialCoeffs; -use plonky2::fri::proof::FriProof; -use plonky2::hash::hash_types::RichField; +use plonky2::fri::proof::{FriProof, FriProofTarget}; +use plonky2::gadgets::polynomial::PolynomialCoeffsExtTarget; +use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; use plonky2::hash::merkle_tree::MerkleCap; -use plonky2::iop::challenger::Challenger; -use plonky2::plonk::config::GenericConfig; +use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; +use plonky2::iop::target::Target; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use crate::config::StarkConfig; -use crate::proof::{StarkOpeningSet, StarkProof, StarkProofChallenges, StarkProofWithPublicInputs}; +use crate::proof::{ + StarkOpeningSet, StarkOpeningSetTarget, StarkProof, StarkProofChallenges, + StarkProofChallengesTarget, StarkProofTarget, StarkProofWithPublicInputs, + StarkProofWithPublicInputsTarget, +}; #[allow(clippy::too_many_arguments)] fn get_challenges, C: GenericConfig, const D: usize>( @@ -94,6 +101,88 @@ impl, C: GenericConfig, const D: usize> } } +pub(crate) fn get_challenges_target< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +>( + builder: &mut CircuitBuilder, + trace_cap: &MerkleCapTarget, + quotient_polys_cap: &MerkleCapTarget, + openings: &StarkOpeningSetTarget, + commit_phase_merkle_caps: &[MerkleCapTarget], + final_poly: &PolynomialCoeffsExtTarget, + pow_witness: Target, + config: &StarkConfig, + degree_bits: usize, +) -> StarkProofChallengesTarget +where + C::Hasher: AlgebraicHasher, +{ + let num_challenges = config.num_challenges; + let num_fri_queries = config.fri_config.num_query_rounds; + let lde_size = 1 << (degree_bits + config.fri_config.rate_bits); + + let mut challenger = RecursiveChallenger::::new(builder); + + challenger.observe_cap(trace_cap); + let stark_alphas = challenger.get_n_challenges(builder, num_challenges); + + challenger.observe_cap(quotient_polys_cap); + let stark_zeta = challenger.get_extension_challenge(builder); + + challenger.observe_openings(&openings.to_fri_openings()); + + StarkProofChallengesTarget { + stark_alphas, + stark_zeta, + fri_challenges: challenger.fri_challenges::( + builder, + commit_phase_merkle_caps, + final_poly, + pow_witness, + &config.fri_config, + ), + } +} + +impl StarkProofWithPublicInputsTarget { + pub(crate) fn get_challenges, C: GenericConfig>( + &self, + builder: &mut CircuitBuilder, + config: &StarkConfig, + degree_bits: usize, + ) -> StarkProofChallengesTarget + where + C::Hasher: AlgebraicHasher, + { + let StarkProofTarget { + trace_cap, + quotient_polys_cap, + openings, + opening_proof: + FriProofTarget { + commit_phase_merkle_caps, + final_poly, + pow_witness, + .. + }, + } = &self.proof; + + get_challenges_target::( + builder, + trace_cap, + quotient_polys_cap, + openings, + commit_phase_merkle_caps, + final_poly, + *pow_witness, + config, + degree_bits, + ) + } +} + // TODO: Deal with the compressed stuff. // impl, C: GenericConfig, const D: usize> // CompressedProofWithPublicInputs diff --git a/starky/src/proof.rs b/starky/src/proof.rs index 4a6de0bb..3e01621f 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -1,7 +1,11 @@ -use plonky2::field::extension_field::Extendable; +use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::fri::oracle::PolynomialBatch; -use plonky2::fri::proof::{CompressedFriProof, FriChallenges, FriProof, FriProofTarget}; -use plonky2::fri::structure::{FriOpeningBatch, FriOpenings}; +use plonky2::fri::proof::{ + CompressedFriProof, FriChallenges, FriChallengesTarget, FriProof, FriProofTarget, +}; +use plonky2::fri::structure::{ + FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, +}; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::ext_target::ExtensionTarget; @@ -9,6 +13,8 @@ use plonky2::iop::target::Target; use plonky2::plonk::config::GenericConfig; use rayon::prelude::*; +use crate::config::StarkConfig; + pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. pub trace_cap: MerkleCap, @@ -20,6 +26,17 @@ pub struct StarkProof, C: GenericConfig, pub opening_proof: FriProof, } +impl, C: GenericConfig, const D: usize> StarkProof { + pub(crate) fn recover_degree_bits(&self, config: &StarkConfig) -> usize { + let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] + .initial_trees_proof + .evals_proofs[0] + .1; + let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); + 1 << (lde_bits - config.fri_config.rate_bits) + } +} + pub struct StarkProofTarget { pub trace_cap: MerkleCapTarget, pub quotient_polys_cap: MerkleCapTarget, @@ -27,6 +44,17 @@ pub struct StarkProofTarget { pub opening_proof: FriProofTarget, } +impl StarkProofTarget { + pub(crate) fn recover_degree_bits(&self, config: &StarkConfig) -> usize { + let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] + .initial_trees_proof + .evals_proofs[0] + .1; + let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); + 1 << (lde_bits - config.fri_config.rate_bits) + } +} + pub struct StarkProofWithPublicInputs< F: RichField + Extendable, C: GenericConfig, @@ -74,6 +102,12 @@ pub(crate) struct StarkProofChallenges, const D: us pub fri_challenges: FriChallenges, } +pub(crate) struct StarkProofChallengesTarget { + pub stark_alphas: Vec, + pub stark_zeta: ExtensionTarget, + pub fri_challenges: FriChallengesTarget, +} + /// Purported values of each polynomial at the challenge point. pub struct StarkOpeningSet, const D: usize> { pub local_values: Vec, @@ -86,7 +120,7 @@ pub struct StarkOpeningSet, const D: usize> { impl, const D: usize> StarkOpeningSet { pub fn new>( zeta: F::Extension, - g: F::Extension, + g: F, trace_commitment: &PolynomialBatch, quotient_commitment: &PolynomialBatch, ) -> Self { @@ -98,7 +132,7 @@ impl, const D: usize> StarkOpeningSet { }; Self { local_values: eval_commitment(zeta, trace_commitment), - next_values: eval_commitment(zeta * g, trace_commitment), + next_values: eval_commitment(zeta.scalar_mul(g), trace_commitment), permutation_zs: vec![/*TODO*/], permutation_zs_right: vec![/*TODO*/], quotient_polys: eval_commitment(zeta, quotient_commitment), @@ -134,3 +168,26 @@ pub struct StarkOpeningSetTarget { pub permutation_zs_right: Vec>, pub quotient_polys: Vec>, } + +impl StarkOpeningSetTarget { + pub(crate) fn to_fri_openings(&self) -> FriOpeningsTarget { + let zeta_batch = FriOpeningBatchTarget { + values: [ + self.local_values.as_slice(), + self.quotient_polys.as_slice(), + self.permutation_zs.as_slice(), + ] + .concat(), + }; + let zeta_right_batch = FriOpeningBatchTarget { + values: [ + self.next_values.as_slice(), + self.permutation_zs_right.as_slice(), + ] + .concat(), + }; + FriOpeningsTarget { + batches: vec![zeta_batch, zeta_right_batch], + } + } +} diff --git a/starky/src/prover.rs b/starky/src/prover.rs index de97ecce..93e01677 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -106,7 +106,7 @@ where // To avoid leaking witness data, we want to ensure that our opening locations, `zeta` and // `g * zeta`, are not in our subgroup `H`. It suffices to check `zeta` only, since // `(g * zeta)^n = zeta^n`, where `n` is the order of `g`. - let g = F::Extension::primitive_root_of_unity(degree_bits); + let g = F::primitive_root_of_unity(degree_bits); ensure!( zeta.exp_power_of_2(degree_bits) != F::Extension::ONE, "Opening point is in the subgroup." @@ -122,7 +122,7 @@ where timing, "compute openings proof", PolynomialBatch::prove_openings( - &stark.fri_instance(zeta, g, rate_bits, config.num_challenges), + &stark.fri_instance(zeta, g, config.num_challenges), initial_merkle_trees, &mut challenger, &fri_params, diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 5b8e9a8a..8f7f6d8f 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -1,195 +1,210 @@ use plonky2::field::extension_field::Extendable; +use plonky2::field::field_types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::config::GenericConfig; -use crate::config::StarkConfig; -use crate::proof::StarkProofWithPublicInputsTarget; -use crate::stark::Stark; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2::util::reducing::ReducingFactorTarget; +use plonky2::with_context; -pub fn verify_stark_proof< F: RichField + Extendable, +use crate::config::StarkConfig; +use crate::constraint_consumer::RecursiveConstraintConsumer; +use crate::proof::{ + StarkOpeningSetTarget, StarkProofChallengesTarget, StarkProofWithPublicInputsTarget, +}; +use crate::stark::Stark; +use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; + +pub fn verify_stark_proof< + F: RichField + Extendable, C: GenericConfig, S: Stark, const D: usize, - >( - builder: &mut CircuitBuilder, - stark: S, - proof_with_pis: StarkProofWithPublicInputsTarget, - inner_config: &StarkConfig - ) - { - let StarkProofWithPublicInputsTarget { - proof, - public_inputs, - } = proof_with_pis; +>( + builder: &mut CircuitBuilder, + stark: S, + proof_with_pis: StarkProofWithPublicInputsTarget, + inner_config: &StarkConfig, +) where + C::Hasher: AlgebraicHasher, + [(); { S::COLUMNS }]:, + [(); { S::PUBLIC_INPUTS }]:, +{ + assert_eq!(proof_with_pis.public_inputs.len(), S::PUBLIC_INPUTS); + let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config); + let challenges = proof_with_pis.get_challenges::(builder, inner_config, degree_bits); - assert_eq!(public_inputs.len(), inner_common_data.num_public_inputs); - let public_inputs_hash = self.hash_n_to_hash_no_pad::(public_inputs); - - self.verify_proof( - proof, - public_inputs_hash, - inner_verifier_data, - inner_common_data, - ); - } - - /// Recursively verifies an inner proof. - pub fn verify_proof>( - &mut self, - proof: ProofTarget, - public_inputs_hash: HashOutTarget, - inner_verifier_data: &VerifierCircuitTarget, - inner_common_data: &CommonCircuitData, - ) where - C::Hasher: AlgebraicHasher, - { - let one = self.one_extension(); - - let num_challenges = inner_common_data.config.num_challenges; - - let mut challenger = RecursiveChallenger::::new(self); - - let (betas, gammas, alphas, zeta) = - with_context!(self, "observe proof and generates challenges", { - // Observe the instance. - let digest = HashOutTarget::from_vec( - self.constants(&inner_common_data.circuit_digest.elements), - ); - challenger.observe_hash(&digest); - challenger.observe_hash(&public_inputs_hash); - - challenger.observe_cap(&proof.wires_cap); - let betas = challenger.get_n_challenges(self, num_challenges); - let gammas = challenger.get_n_challenges(self, num_challenges); - - challenger.observe_cap(&proof.plonk_zs_partial_products_cap); - let alphas = challenger.get_n_challenges(self, num_challenges); - - challenger.observe_cap(&proof.quotient_polys_cap); - let zeta = challenger.get_extension_challenge(self); - - (betas, gammas, alphas, zeta) - }); - - let local_constants = &proof.openings.constants; - let local_wires = &proof.openings.wires; - let vars = EvaluationTargets { - local_constants, - local_wires, - public_inputs_hash: &public_inputs_hash, - }; - let local_zs = &proof.openings.plonk_zs; - let next_zs = &proof.openings.plonk_zs_right; - let s_sigmas = &proof.openings.plonk_sigmas; - let partial_products = &proof.openings.partial_products; - - let zeta_pow_deg = self.exp_power_of_2_extension(zeta, inner_common_data.degree_bits); - let vanishing_polys_zeta = with_context!( - self, - "evaluate the vanishing polynomial at our challenge point, zeta.", - eval_vanishing_poly_recursively( - self, - inner_common_data, - zeta, - zeta_pow_deg, - vars, - local_zs, - next_zs, - partial_products, - s_sigmas, - &betas, - &gammas, - &alphas, - ) - ); - - with_context!(self, "check vanishing and quotient polynomials.", { - let quotient_polys_zeta = &proof.openings.quotient_polys; - let mut scale = ReducingFactorTarget::new(zeta_pow_deg); - let z_h_zeta = self.sub_extension(zeta_pow_deg, one); - for (i, chunk) in quotient_polys_zeta - .chunks(inner_common_data.quotient_degree_factor) - .enumerate() - { - let recombined_quotient = scale.reduce(chunk, self); - let computed_vanishing_poly = self.mul_extension(z_h_zeta, recombined_quotient); - self.connect_extension(vanishing_polys_zeta[i], computed_vanishing_poly); - } - }); - - let merkle_caps = &[ - inner_verifier_data.constants_sigmas_cap.clone(), - proof.wires_cap, - proof.plonk_zs_partial_products_cap, - proof.quotient_polys_cap, - ]; - - let fri_instance = inner_common_data.get_fri_instance_target(self, zeta); - with_context!( - self, - "verify FRI proof", - self.verify_fri_proof::( - &fri_instance, - &proof.openings, - merkle_caps, - &proof.opening_proof, - &mut challenger, - &inner_common_data.fri_params, - ) - ); - } - - pub fn add_virtual_proof_with_pis>( - &mut self, - common_data: &CommonCircuitData, - ) -> ProofWithPublicInputsTarget { - let proof = self.add_virtual_proof(common_data); - let public_inputs = self.add_virtual_targets(common_data.num_public_inputs); - ProofWithPublicInputsTarget { - proof, - public_inputs, - } - } - - fn add_virtual_proof>( - &mut self, - common_data: &CommonCircuitData, - ) -> ProofTarget { - let config = &common_data.config; - let fri_params = &common_data.fri_params; - let cap_height = fri_params.config.cap_height; - - let num_leaves_per_oracle = &[ - common_data.num_preprocessed_polys(), - config.num_wires, - common_data.num_zs_partial_products_polys(), - common_data.num_quotient_polys(), - ]; - - ProofTarget { - wires_cap: self.add_virtual_cap(cap_height), - plonk_zs_partial_products_cap: self.add_virtual_cap(cap_height), - quotient_polys_cap: self.add_virtual_cap(cap_height), - openings: self.add_opening_set(common_data), - opening_proof: self.add_virtual_fri_proof(num_leaves_per_oracle, fri_params), - } - } - - fn add_opening_set>( - &mut self, - common_data: &CommonCircuitData, - ) -> OpeningSetTarget { - let config = &common_data.config; - let num_challenges = config.num_challenges; - let total_partial_products = num_challenges * common_data.num_partial_products; - OpeningSetTarget { - constants: self.add_virtual_extension_targets(common_data.num_constants), - plonk_sigmas: self.add_virtual_extension_targets(config.num_routed_wires), - wires: self.add_virtual_extension_targets(config.num_wires), - plonk_zs: self.add_virtual_extension_targets(num_challenges), - plonk_zs_right: self.add_virtual_extension_targets(num_challenges), - partial_products: self.add_virtual_extension_targets(total_partial_products), - quotient_polys: self.add_virtual_extension_targets(common_data.num_quotient_polys()), - } - } + verify_stark_proof_with_challenges::( + builder, + stark, + proof_with_pis, + challenges, + inner_config, + degree_bits, + ); } + +/// Recursively verifies an inner proof. +fn verify_stark_proof_with_challenges< + F: RichField + Extendable, + C: GenericConfig, + S: Stark, + const D: usize, +>( + builder: &mut CircuitBuilder, + stark: S, + proof_with_pis: StarkProofWithPublicInputsTarget, + challenges: StarkProofChallengesTarget, + inner_config: &StarkConfig, + degree_bits: usize, +) where + C::Hasher: AlgebraicHasher, + [(); { S::COLUMNS }]:, + [(); { S::PUBLIC_INPUTS }]:, +{ + let one = builder.one_extension(); + + let StarkProofWithPublicInputsTarget { + proof, + public_inputs, + } = proof_with_pis; + let local_values = &proof.openings.local_values; + let next_values = &proof.openings.local_values; + let StarkOpeningSetTarget { + local_values, + next_values, + permutation_zs, + permutation_zs_right, + quotient_polys, + } = &proof.openings; + let vars = StarkEvaluationTargets { + local_values: &local_values.to_vec().try_into().unwrap(), + next_values: &next_values.to_vec().try_into().unwrap(), + public_inputs: &public_inputs + .into_iter() + .map(|t| builder.convert_to_ext(t)) + .collect::>() + .try_into() + .unwrap(), + }; + let (l_1, l_last) = + eval_l_1_and_l_last_recursively(builder, degree_bits, challenges.stark_zeta); + let last = + builder.constant_extension(F::Extension::primitive_root_of_unity(degree_bits).inverse()); + let z_last = builder.sub_extension(challenges.stark_zeta, last); + let mut consumer = RecursiveConstraintConsumer::::new( + builder.zero_extension(), + challenges.stark_alphas, + z_last, + l_1, + l_last, + ); + stark.eval_ext_recursively(builder, vars, &mut consumer); + let vanishing_polys_zeta = consumer.accumulators(); + + // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta. + let quotient_polys_zeta = &proof.openings.quotient_polys; + let zeta_pow_deg = builder.exp_power_of_2_extension(challenges.stark_zeta, degree_bits); + let mut scale = ReducingFactorTarget::new(zeta_pow_deg); + let z_h_zeta = builder.sub_extension(zeta_pow_deg, one); + for (i, chunk) in quotient_polys_zeta + .chunks(stark.quotient_degree_factor()) + .enumerate() + { + let recombined_quotient = scale.reduce(chunk, builder); + let computed_vanishing_poly = builder.mul_extension(z_h_zeta, recombined_quotient); + builder.connect_extension(vanishing_polys_zeta[i], computed_vanishing_poly); + } + + // TODO: Permutation polynomials. + let merkle_caps = &[proof.trace_cap, proof.quotient_polys_cap]; + + let fri_instance = stark.fri_instance_target( + builder, + challenges.stark_zeta, + F::primitive_root_of_unity(degree_bits), + inner_config.num_challenges, + ); + builder.verify_fri_proof::( + &fri_instance, + &proof.openings.to_fri_openings(), + &challenges.fri_challenges, + merkle_caps, + &proof.opening_proof, + &inner_config.fri_params(degree_bits), + ); +} + +fn eval_l_1_and_l_last_recursively, const D: usize>( + builder: &mut CircuitBuilder, + log_n: usize, + x: ExtensionTarget, +) -> (ExtensionTarget, ExtensionTarget) { + let n = builder.constant_extension(F::Extension::from_canonical_usize(1 << log_n)); + let g = builder.constant_extension(F::Extension::primitive_root_of_unity(log_n)); + let x_pow_n = builder.exp_power_of_2_extension(x, log_n); + let one = builder.one_extension(); + let z_x = builder.sub_extension(x_pow_n, one); + let l_1_deno = builder.mul_sub_extension(n, x, n); + let l_last_deno = builder.mul_sub_extension(g, x, one); + let l_last_deno = builder.mul_extension(n, l_last_deno); + + ( + builder.div_extension(z_x, l_1_deno), + builder.div_extension(z_x, l_last_deno), + ) +} + +// pub fn add_virtual_proof_with_pis>( +// &mut self, +// common_data: &CommonCircuitData, +// ) -> ProofWithPublicInputsTarget { +// let proof = self.add_virtual_proof(common_data); +// let public_inputs = self.add_virtual_targets(common_data.num_public_inputs); +// ProofWithPublicInputsTarget { +// proof, +// public_inputs, +// } +// } +// +// fn add_virtual_proof>( +// &mut self, +// common_data: &CommonCircuitData, +// ) -> ProofTarget { +// let config = &common_data.config; +// let fri_params = &common_data.fri_params; +// let cap_height = fri_params.config.cap_height; +// +// let num_leaves_per_oracle = &[ +// common_data.num_preprocessed_polys(), +// config.num_wires, +// common_data.num_zs_partial_products_polys(), +// common_data.num_quotient_polys(), +// ]; +// +// ProofTarget { +// wires_cap: self.add_virtual_cap(cap_height), +// plonk_zs_partial_products_cap: self.add_virtual_cap(cap_height), +// quotient_polys_cap: self.add_virtual_cap(cap_height), +// openings: self.add_opening_set(common_data), +// opening_proof: self.add_virtual_fri_proof(num_leaves_per_oracle, fri_params), +// } +// } +// +// fn add_opening_set>( +// &mut self, +// common_data: &CommonCircuitData, +// ) -> OpeningSetTarget { +// let config = &common_data.config; +// let num_challenges = config.num_challenges; +// let total_partial_products = num_challenges * common_data.num_partial_products; +// OpeningSetTarget { +// constants: self.add_virtual_extension_targets(common_data.num_constants), +// plonk_sigmas: self.add_virtual_extension_targets(config.num_routed_wires), +// wires: self.add_virtual_extension_targets(config.num_wires), +// plonk_zs: self.add_virtual_extension_targets(num_challenges), +// plonk_zs_right: self.add_virtual_extension_targets(num_challenges), +// partial_products: self.add_virtual_extension_targets(total_partial_products), +// quotient_polys: self.add_virtual_extension_targets(common_data.num_quotient_polys()), +// } +// } diff --git a/starky/src/stark.rs b/starky/src/stark.rs index 4b20553e..3ef976e0 100644 --- a/starky/src/stark.rs +++ b/starky/src/stark.rs @@ -1,7 +1,11 @@ use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::field::packed_field::PackedField; -use plonky2::fri::structure::{FriBatchInfo, FriInstanceInfo, FriOracleInfo, FriPolynomialInfo}; +use plonky2::fri::structure::{ + FriBatchInfo, FriBatchInfoTarget, FriInstanceInfo, FriInstanceInfoTarget, FriOracleInfo, + FriPolynomialInfo, +}; use plonky2::hash::hash_types::RichField; +use plonky2::iop::ext_target::ExtensionTarget; use plonky2::plonk::circuit_builder::CircuitBuilder; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; @@ -75,8 +79,7 @@ pub trait Stark, const D: usize>: Sync { fn fri_instance( &self, zeta: F::Extension, - g: F::Extension, - rate_bits: usize, + g: F, num_challenges: usize, ) -> FriInstanceInfo { let no_blinding_oracle = FriOracleInfo { blinding: false }; @@ -88,7 +91,7 @@ pub trait Stark, const D: usize>: Sync { polynomials: [trace_info.clone(), quotient_info].concat(), }; let zeta_right_batch = FriBatchInfo:: { - point: zeta * g, + point: zeta.scalar_mul(g), polynomials: trace_info, }; FriInstanceInfo { @@ -96,4 +99,32 @@ pub trait Stark, const D: usize>: Sync { batches: vec![zeta_batch], } } + + /// Computes the FRI instance used to prove this Stark. + // TODO: Permutation polynomials. + fn fri_instance_target( + &self, + builder: &mut CircuitBuilder, + zeta: ExtensionTarget, + g: F, + num_challenges: usize, + ) -> FriInstanceInfoTarget { + let no_blinding_oracle = FriOracleInfo { blinding: false }; + let trace_info = FriPolynomialInfo::from_range(0, 0..Self::COLUMNS); + let quotient_info = + FriPolynomialInfo::from_range(1, 0..self.quotient_degree_factor() * num_challenges); + let zeta_batch = FriBatchInfoTarget { + point: zeta, + polynomials: [trace_info.clone(), quotient_info].concat(), + }; + let zeta_right = builder.mul_const_extension(g, zeta); + let zeta_right_batch = FriBatchInfoTarget { + point: zeta_right, + polynomials: trace_info, + }; + FriInstanceInfoTarget { + oracles: vec![no_blinding_oracle; 3], + batches: vec![zeta_batch], + } + } } diff --git a/starky/src/verifier.rs b/starky/src/verifier.rs index 91a51bed..f02a5619 100644 --- a/starky/src/verifier.rs +++ b/starky/src/verifier.rs @@ -27,7 +27,8 @@ where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, { - let degree_bits = log2_strict(recover_degree(&proof_with_pis.proof, config)); + ensure!(proof_with_pis.public_inputs.len() == S::PUBLIC_INPUTS); + let degree_bits = proof_with_pis.proof.recover_degree_bits(config); let challenges = proof_with_pis.get_challenges(config, degree_bits)?; verify_with_challenges(stark, proof_with_pis, challenges, degree_bits, config) } @@ -110,8 +111,7 @@ where verify_fri_proof::( &stark.fri_instance( challenges.stark_zeta, - F::primitive_root_of_unity(degree_bits).into(), - config.fri_config.rate_bits, + F::primitive_root_of_unity(degree_bits), config.num_challenges, ), &proof.openings.to_fri_openings(), @@ -137,17 +137,6 @@ fn eval_l_1_and_l_last(log_n: usize, x: F) -> (F, F) { } /// Recover the length of the trace from a STARK proof and a STARK config. -fn recover_degree, C: GenericConfig, const D: usize>( - proof: &StarkProof, - config: &StarkConfig, -) -> usize { - let initial_merkle_proof = &proof.opening_proof.query_round_proofs[0] - .initial_trees_proof - .evals_proofs[0] - .1; - let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); - 1 << (lde_bits - config.fri_config.rate_bits) -} #[cfg(test)] mod tests { From ae330ff6a79df9c953fae81e2a6cc17c17f849a3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Feb 2022 18:19:11 +0100 Subject: [PATCH 04/20] Clippy --- plonky2/src/fri/challenges.rs | 1 - starky/src/get_challenges.rs | 1 + starky/src/recursive_verifier.rs | 11 +++++------ starky/src/verifier.rs | 3 +-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/plonky2/src/fri/challenges.rs b/plonky2/src/fri/challenges.rs index 9222ebc8..0655d31f 100644 --- a/plonky2/src/fri/challenges.rs +++ b/plonky2/src/fri/challenges.rs @@ -10,7 +10,6 @@ use crate::hash::merkle_tree::MerkleCap; use crate::iop::challenger::{Challenger, RecursiveChallenger}; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; impl> Challenger { diff --git a/starky/src/get_challenges.rs b/starky/src/get_challenges.rs index d44075e7..3d815caf 100644 --- a/starky/src/get_challenges.rs +++ b/starky/src/get_challenges.rs @@ -101,6 +101,7 @@ impl, C: GenericConfig, const D: usize> } } +#[allow(clippy::too_many_arguments)] pub(crate) fn get_challenges_target< F: RichField + Extendable, C: GenericConfig, diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 8f7f6d8f..4e41a255 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -5,7 +5,6 @@ use plonky2::iop::ext_target::ExtensionTarget; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::util::reducing::ReducingFactorTarget; -use plonky2::with_context; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; @@ -13,7 +12,7 @@ use crate::proof::{ StarkOpeningSetTarget, StarkProofChallengesTarget, StarkProofWithPublicInputsTarget, }; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; +use crate::vars::StarkEvaluationTargets; pub fn verify_stark_proof< F: RichField + Extendable, @@ -27,8 +26,8 @@ pub fn verify_stark_proof< inner_config: &StarkConfig, ) where C::Hasher: AlgebraicHasher, - [(); { S::COLUMNS }]:, - [(); { S::PUBLIC_INPUTS }]:, + [(); S::COLUMNS]:, + [(); S::PUBLIC_INPUTS]:, { assert_eq!(proof_with_pis.public_inputs.len(), S::PUBLIC_INPUTS); let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config); @@ -59,8 +58,8 @@ fn verify_stark_proof_with_challenges< degree_bits: usize, ) where C::Hasher: AlgebraicHasher, - [(); { S::COLUMNS }]:, - [(); { S::PUBLIC_INPUTS }]:, + [(); S::COLUMNS]:, + [(); S::PUBLIC_INPUTS]:, { let one = builder.one_extension(); diff --git a/starky/src/verifier.rs b/starky/src/verifier.rs index f02a5619..e8ae6221 100644 --- a/starky/src/verifier.rs +++ b/starky/src/verifier.rs @@ -5,11 +5,10 @@ use plonky2::fri::verifier::verify_fri_proof; use plonky2::hash::hash_types::RichField; use plonky2::plonk::config::GenericConfig; use plonky2::plonk::plonk_common::reduce_with_powers; -use plonky2_util::log2_strict; use crate::config::StarkConfig; use crate::constraint_consumer::ConstraintConsumer; -use crate::proof::{StarkOpeningSet, StarkProof, StarkProofChallenges, StarkProofWithPublicInputs}; +use crate::proof::{StarkOpeningSet, StarkProofChallenges, StarkProofWithPublicInputs}; use crate::stark::Stark; use crate::vars::StarkEvaluationVars; From 101b3bac64a49633776a514b7800ad8d5d4ffe3c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Feb 2022 18:24:28 +0100 Subject: [PATCH 05/20] Small optimization --- starky/src/recursive_verifier.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 4e41a255..e672851c 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -86,8 +86,10 @@ fn verify_stark_proof_with_challenges< .try_into() .unwrap(), }; + let zeta_pow_deg = builder.exp_power_of_2_extension(challenges.stark_zeta, degree_bits); + let z_h_zeta = builder.sub_extension(zeta_pow_deg, one); let (l_1, l_last) = - eval_l_1_and_l_last_recursively(builder, degree_bits, challenges.stark_zeta); + eval_l_1_and_l_last_recursively(builder, degree_bits, challenges.stark_zeta, z_h_zeta); let last = builder.constant_extension(F::Extension::primitive_root_of_unity(degree_bits).inverse()); let z_last = builder.sub_extension(challenges.stark_zeta, last); @@ -103,9 +105,7 @@ fn verify_stark_proof_with_challenges< // Check each polynomial identity, of the form `vanishing(x) = Z_H(x) quotient(x)`, at zeta. let quotient_polys_zeta = &proof.openings.quotient_polys; - let zeta_pow_deg = builder.exp_power_of_2_extension(challenges.stark_zeta, degree_bits); let mut scale = ReducingFactorTarget::new(zeta_pow_deg); - let z_h_zeta = builder.sub_extension(zeta_pow_deg, one); for (i, chunk) in quotient_polys_zeta .chunks(stark.quotient_degree_factor()) .enumerate() @@ -138,12 +138,11 @@ fn eval_l_1_and_l_last_recursively, const D: usize> builder: &mut CircuitBuilder, log_n: usize, x: ExtensionTarget, + z_x: ExtensionTarget, ) -> (ExtensionTarget, ExtensionTarget) { let n = builder.constant_extension(F::Extension::from_canonical_usize(1 << log_n)); let g = builder.constant_extension(F::Extension::primitive_root_of_unity(log_n)); - let x_pow_n = builder.exp_power_of_2_extension(x, log_n); let one = builder.one_extension(); - let z_x = builder.sub_extension(x_pow_n, one); let l_1_deno = builder.mul_sub_extension(n, x, n); let l_last_deno = builder.mul_sub_extension(g, x, one); let l_last_deno = builder.mul_extension(n, l_last_deno); From ff7a6548401086766937a1856dec94d18990418b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 9 Feb 2022 17:11:13 +0100 Subject: [PATCH 06/20] Methods for virtual stark proofs --- plonky2/src/fri/mod.rs | 14 ++++ plonky2/src/fri/recursive_verifier.rs | 2 +- plonky2/src/plonk/circuit_builder.rs | 15 +--- starky/src/proof.rs | 1 + starky/src/prover.rs | 2 +- starky/src/recursive_verifier.rs | 112 +++++++++++++------------- 6 files changed, 78 insertions(+), 68 deletions(-) diff --git a/plonky2/src/fri/mod.rs b/plonky2/src/fri/mod.rs index a0cd428b..c491f8f0 100644 --- a/plonky2/src/fri/mod.rs +++ b/plonky2/src/fri/mod.rs @@ -30,6 +30,20 @@ impl FriConfig { pub fn rate(&self) -> f64 { 1.0 / ((1 << self.rate_bits) as f64) } + + pub fn fri_params(&self, degree_bits: usize, hiding: bool) -> FriParams { + let reduction_arity_bits = self.reduction_strategy.reduction_arity_bits( + degree_bits, + self.rate_bits, + self.num_query_rounds, + ); + FriParams { + config: self.clone(), + hiding, + degree_bits, + reduction_arity_bits, + } + } } /// FRI parameters, including generated parameters which are specific to an instance size, in diff --git a/plonky2/src/fri/recursive_verifier.rs b/plonky2/src/fri/recursive_verifier.rs index f51b8fe6..9b619ea8 100644 --- a/plonky2/src/fri/recursive_verifier.rs +++ b/plonky2/src/fri/recursive_verifier.rs @@ -398,7 +398,7 @@ impl, const D: usize> CircuitBuilder { "A non-negligible portion of field elements are in the range that permits non-canonical encodings. Need to do more analysis or enforce canonical encodings."); } - pub(crate) fn add_virtual_fri_proof( + pub fn add_virtual_fri_proof( &mut self, num_leaves_per_oracle: &[usize], params: &FriParams, diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index cf89bf1a..e1536b3a 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -393,18 +393,9 @@ impl, const D: usize> CircuitBuilder { } fn fri_params(&self, degree_bits: usize) -> FriParams { - let fri_config = &self.config.fri_config; - let reduction_arity_bits = fri_config.reduction_strategy.reduction_arity_bits( - degree_bits, - fri_config.rate_bits, - fri_config.num_query_rounds, - ); - FriParams { - config: fri_config.clone(), - hiding: self.config.zero_knowledge, - degree_bits, - reduction_arity_bits, - } + self.config + .fri_config + .fri_params(degree_bits, self.config.zero_knowledge) } /// The number of (base field) `arithmetic` operations that can be performed in a single gate. diff --git a/starky/src/proof.rs b/starky/src/proof.rs index 3e01621f..c505a59b 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -15,6 +15,7 @@ use rayon::prelude::*; use crate::config::StarkConfig; +// TODO: Permutation polynomials. pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. pub trace_cap: MerkleCap, diff --git a/starky/src/prover.rs b/starky/src/prover.rs index 93e01677..728def18 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -114,7 +114,7 @@ where let openings = StarkOpeningSet::new(zeta, g, &trace_commitment, "ient_commitment); challenger.observe_openings(&openings.to_fri_openings()); - // TODO: Add permuation checks + // TODO: Add permutation checks let initial_merkle_trees = &[&trace_commitment, "ient_commitment]; let fri_params = config.fri_params(degree_bits); diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index e672851c..2ac038d6 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -9,7 +9,8 @@ use plonky2::util::reducing::ReducingFactorTarget; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::proof::{ - StarkOpeningSetTarget, StarkProofChallengesTarget, StarkProofWithPublicInputsTarget, + StarkOpeningSetTarget, StarkProofChallengesTarget, StarkProofTarget, + StarkProofWithPublicInputsTarget, }; use crate::stark::Stark; use crate::vars::StarkEvaluationTargets; @@ -153,56 +154,59 @@ fn eval_l_1_and_l_last_recursively, const D: usize> ) } -// pub fn add_virtual_proof_with_pis>( -// &mut self, -// common_data: &CommonCircuitData, -// ) -> ProofWithPublicInputsTarget { -// let proof = self.add_virtual_proof(common_data); -// let public_inputs = self.add_virtual_targets(common_data.num_public_inputs); -// ProofWithPublicInputsTarget { -// proof, -// public_inputs, -// } -// } -// -// fn add_virtual_proof>( -// &mut self, -// common_data: &CommonCircuitData, -// ) -> ProofTarget { -// let config = &common_data.config; -// let fri_params = &common_data.fri_params; -// let cap_height = fri_params.config.cap_height; -// -// let num_leaves_per_oracle = &[ -// common_data.num_preprocessed_polys(), -// config.num_wires, -// common_data.num_zs_partial_products_polys(), -// common_data.num_quotient_polys(), -// ]; -// -// ProofTarget { -// wires_cap: self.add_virtual_cap(cap_height), -// plonk_zs_partial_products_cap: self.add_virtual_cap(cap_height), -// quotient_polys_cap: self.add_virtual_cap(cap_height), -// openings: self.add_opening_set(common_data), -// opening_proof: self.add_virtual_fri_proof(num_leaves_per_oracle, fri_params), -// } -// } -// -// fn add_opening_set>( -// &mut self, -// common_data: &CommonCircuitData, -// ) -> OpeningSetTarget { -// let config = &common_data.config; -// let num_challenges = config.num_challenges; -// let total_partial_products = num_challenges * common_data.num_partial_products; -// OpeningSetTarget { -// constants: self.add_virtual_extension_targets(common_data.num_constants), -// plonk_sigmas: self.add_virtual_extension_targets(config.num_routed_wires), -// wires: self.add_virtual_extension_targets(config.num_wires), -// plonk_zs: self.add_virtual_extension_targets(num_challenges), -// plonk_zs_right: self.add_virtual_extension_targets(num_challenges), -// partial_products: self.add_virtual_extension_targets(total_partial_products), -// quotient_polys: self.add_virtual_extension_targets(common_data.num_quotient_polys()), -// } -// } +pub fn add_virtual_stark_proof_with_pis< + F: RichField + Extendable, + S: Stark, + const D: usize, +>( + builder: &mut CircuitBuilder, + stark: S, + config: &StarkConfig, + degree_bits: usize, +) -> StarkProofWithPublicInputsTarget { + let proof = add_virtual_stark_proof::(builder, stark, config, degree_bits); + let public_inputs = builder.add_virtual_targets(S::PUBLIC_INPUTS); + StarkProofWithPublicInputsTarget { + proof, + public_inputs, + } +} + +pub fn add_virtual_stark_proof, S: Stark, const D: usize>( + builder: &mut CircuitBuilder, + stark: S, + config: &StarkConfig, + degree_bits: usize, +) -> StarkProofTarget { + let fri_params = config.fri_config.fri_params(degree_bits, false); + let cap_height = fri_params.config.cap_height; + + let num_leaves_per_oracle = &[ + S::COLUMNS, + // TODO: permutation polys + stark.quotient_degree_factor() * config.num_challenges, + ]; + + StarkProofTarget { + trace_cap: builder.add_virtual_cap(cap_height), + quotient_polys_cap: builder.add_virtual_cap(cap_height), + openings: add_stark_opening_set::(builder, stark, config), + opening_proof: builder.add_virtual_fri_proof(num_leaves_per_oracle, &fri_params), + } +} + +fn add_stark_opening_set, S: Stark, const D: usize>( + builder: &mut CircuitBuilder, + stark: S, + config: &StarkConfig, +) -> StarkOpeningSetTarget { + let num_challenges = config.num_challenges; + StarkOpeningSetTarget { + local_values: builder.add_virtual_extension_targets(S::COLUMNS), + next_values: builder.add_virtual_extension_targets(S::COLUMNS), + permutation_zs: vec![/*TODO*/], + permutation_zs_right: vec![/*TODO*/], + quotient_polys: builder + .add_virtual_extension_targets(stark.quotient_degree_factor() * num_challenges), + } +} From 3aa192a7f600b3b4f011d103f0422a51b660f601 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 10 Feb 2022 16:04:46 +0100 Subject: [PATCH 07/20] Add witness generation for stark proofs --- plonky2/src/iop/witness.rs | 59 +---- starky/src/fibonacci_stark.rs | 367 ++++++++++++++++++++++++++----- starky/src/recursive_verifier.rs | 54 ++++- 3 files changed, 370 insertions(+), 110 deletions(-) diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index 43dc752d..651e1707 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -201,61 +201,10 @@ pub trait Witness { ); self.set_cap_target(&proof_target.quotient_polys_cap, &proof.quotient_polys_cap); - for (&t, &x) in proof_target - .openings - .wires - .iter() - .zip_eq(&proof.openings.wires) - { - self.set_extension_target(t, x); - } - for (&t, &x) in proof_target - .openings - .constants - .iter() - .zip_eq(&proof.openings.constants) - { - self.set_extension_target(t, x); - } - for (&t, &x) in proof_target - .openings - .plonk_sigmas - .iter() - .zip_eq(&proof.openings.plonk_sigmas) - { - self.set_extension_target(t, x); - } - for (&t, &x) in proof_target - .openings - .plonk_zs - .iter() - .zip_eq(&proof.openings.plonk_zs) - { - self.set_extension_target(t, x); - } - for (&t, &x) in proof_target - .openings - .plonk_zs_right - .iter() - .zip_eq(&proof.openings.plonk_zs_right) - { - self.set_extension_target(t, x); - } - for (&t, &x) in proof_target - .openings - .partial_products - .iter() - .zip_eq(&proof.openings.partial_products) - { - self.set_extension_target(t, x); - } - for (&t, &x) in proof_target - .openings - .quotient_polys - .iter() - .zip_eq(&proof.openings.quotient_polys) - { - self.set_extension_target(t, x); + let openings = proof.openings.to_fri_openings(); + let openings_target = proof_target.openings.to_fri_openings(); + for (batch, batch_target) in openings.batches.iter().zip_eq(&openings_target.batches) { + self.set_extension_targets(&batch_target.values, &batch.values); } set_fri_proof_target(self, &proof_target.opening_proof, &proof.opening_proof); diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 18bc46b5..92432c64 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -105,56 +105,317 @@ impl, const D: usize> Stark for FibonacciStar } } -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2::field::field_types::Field; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use plonky2::util::timing::TimingTree; - - use crate::config::StarkConfig; - use crate::fibonacci_stark::FibonacciStark; - use crate::prover::prove; - use crate::stark_testing::test_stark_low_degree; - use crate::verifier::verify; - - fn fibonacci(n: usize, x0: F, x1: F) -> F { - (0..n).fold((x0, x1), |x, _| (x.1, x.0 + x.1)).1 - } - - #[test] - fn test_fibonacci_stark() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type S = FibonacciStark; - - let config = StarkConfig::standard_fast_config(); - let num_rows = 1 << 5; - let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; - let stark = S::new(num_rows); - let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - let proof = prove::( - stark, - &config, - trace, - public_inputs, - &mut TimingTree::default(), - )?; - - verify(stark, proof, &config) - } - - #[test] - fn test_fibonacci_stark_degree() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type S = FibonacciStark; - - let config = StarkConfig::standard_fast_config(); - let num_rows = 1 << 5; - let stark = S::new(num_rows); - test_stark_low_degree(stark) - } -} +// #[cfg(test)] +// mod tests { +// use anyhow::Result; +// use plonky2::field::extension_field::Extendable; +// use plonky2::field::field_types::Field; +// use plonky2::hash::hash_types::RichField; +// use plonky2::iop::witness::PartialWitness; +// use plonky2::plonk::circuit_builder::CircuitBuilder; +// use plonky2::plonk::circuit_data::CommonCircuitData; +// use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; +// use plonky2::plonk::proof::ProofWithPublicInputs; +// use plonky2::util::timing::TimingTree; +// +// use crate::config::StarkConfig; +// use crate::fibonacci_stark::FibonacciStark; +// use crate::proof::StarkProofWithPublicInputs; +// use crate::prover::prove; +// use crate::recursive_verifier::add_virtual_stark_proof_with_pis; +// use crate::stark_testing::test_stark_low_degree; +// use crate::verifier::verify; +// +// fn fibonacci(n: usize, x0: F, x1: F) -> F { +// (0..n).fold((x0, x1), |x, _| (x.1, x.0 + x.1)).1 +// } +// +// #[test] +// fn test_fibonacci_stark() -> Result<()> { +// const D: usize = 2; +// type C = PoseidonGoldilocksConfig; +// type F = >::F; +// type S = FibonacciStark; +// +// let config = StarkConfig::standard_fast_config(); +// let num_rows = 1 << 5; +// let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; +// let stark = S::new(num_rows); +// let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); +// let proof = prove::( +// stark, +// &config, +// trace, +// public_inputs, +// &mut TimingTree::default(), +// )?; +// +// verify(stark, proof, &config) +// } +// +// #[test] +// fn test_fibonacci_stark_degree() -> Result<()> { +// const D: usize = 2; +// type C = PoseidonGoldilocksConfig; +// type F = >::F; +// type S = FibonacciStark; +// +// let config = StarkConfig::standard_fast_config(); +// let num_rows = 1 << 5; +// let stark = S::new(num_rows); +// test_stark_low_degree(stark) +// } +// +// #[test] +// fn test_recursive_stark_verifier() -> Result<()> { +// init_logger(); +// const D: usize = 2; +// type C = PoseidonGoldilocksConfig; +// type F = >::F; +// type S = FibonacciStark; +// +// let config = StarkConfig::standard_fast_config(); +// let num_rows = 1 << 5; +// let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; +// let stark = S::new(num_rows); +// let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); +// let proof = prove::( +// stark, +// &config, +// trace, +// public_inputs, +// &mut TimingTree::default(), +// )?; +// +// let (proof, _vd, cd) = +// recursive_proof::(proof, vd, cd, &config, None, true, true)?; +// test_serialization(&proof, &cd)?; +// +// Ok(()) +// } +// +// #[test] +// fn test_recursive_recursive_verifier() -> Result<()> { +// init_logger(); +// const D: usize = 2; +// type C = PoseidonGoldilocksConfig; +// type F = >::F; +// +// let config = CircuitConfig::standard_recursion_config(); +// +// // Start with a degree 2^14 proof +// let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; +// assert_eq!(cd.degree_bits, 14); +// +// // Shrink it to 2^13. +// let (proof, vd, cd) = +// recursive_proof::(proof, vd, cd, &config, Some(13), false, false)?; +// assert_eq!(cd.degree_bits, 13); +// +// // Shrink it to 2^12. +// let (proof, _vd, cd) = +// recursive_proof::(proof, vd, cd, &config, None, true, true)?; +// assert_eq!(cd.degree_bits, 12); +// +// test_serialization(&proof, &cd)?; +// +// Ok(()) +// } +// +// /// Creates a chain of recursive proofs where the last proof is made as small as reasonably +// /// possible, using a high rate, high PoW bits, etc. +// #[test] +// #[ignore] +// fn test_size_optimized_recursion() -> Result<()> { +// init_logger(); +// 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)?; +// assert_eq!(cd.degree_bits, 12); +// +// // A standard recursive proof. +// let (proof, vd, cd) = recursive_proof(proof, vd, cd, &standard_config, None, false, false)?; +// assert_eq!(cd.degree_bits, 12); +// +// // A high-rate recursive proof, designed to be verifiable with fewer routed wires. +// let high_rate_config = CircuitConfig { +// fri_config: FriConfig { +// rate_bits: 7, +// proof_of_work_bits: 16, +// num_query_rounds: 12, +// ..standard_config.fri_config.clone() +// }, +// ..standard_config +// }; +// let (proof, vd, cd) = +// recursive_proof::(proof, vd, cd, &high_rate_config, None, true, true)?; +// assert_eq!(cd.degree_bits, 12); +// +// // A final proof, optimized for size. +// let final_config = CircuitConfig { +// num_routed_wires: 37, +// fri_config: FriConfig { +// rate_bits: 8, +// cap_height: 0, +// proof_of_work_bits: 20, +// reduction_strategy: FriReductionStrategy::MinSize(None), +// num_query_rounds: 10, +// }, +// ..high_rate_config +// }; +// let (proof, _vd, cd) = +// recursive_proof::(proof, vd, cd, &final_config, None, true, true)?; +// assert_eq!(cd.degree_bits, 12, "final proof too large"); +// +// test_serialization(&proof, &cd)?; +// +// Ok(()) +// } +// +// #[test] +// fn test_recursive_verifier_multi_hash() -> Result<()> { +// init_logger(); +// const D: usize = 2; +// type PC = PoseidonGoldilocksConfig; +// type KC = KeccakGoldilocksConfig; +// 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, None, false, false)?; +// test_serialization(&proof, &cd)?; +// +// let (proof, _vd, cd) = +// recursive_proof::(proof, vd, cd, &config, None, false, false)?; +// test_serialization(&proof, &cd)?; +// +// Ok(()) +// } +// +// /// Creates a dummy proof which should have roughly `num_dummy_gates` gates. +// fn dummy_proof, C: GenericConfig, const D: usize>( +// config: &CircuitConfig, +// num_dummy_gates: u64, +// ) -> Result<( +// 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 inputs = PartialWitness::new(); +// let proof = data.prove(inputs)?; +// data.verify(proof.clone())?; +// +// Ok((proof, data.verifier_only, data.common)) +// } +// +// fn recursive_proof< +// F: RichField + Extendable, +// C: GenericConfig, +// InnerC: GenericConfig, +// const D: usize, +// >( +// inner_proof: StarkProofWithPublicInputs, +// config: &StarkConfig, +// print_gate_counts: bool, +// print_timing: bool, +// ) -> Result<( +// ProofWithPublicInputs, +// VerifierOnlyCircuitData, +// CommonCircuitData, +// )> +// where +// InnerC::Hasher: AlgebraicHasher, +// { +// let mut builder = CircuitBuilder::::new(config.clone()); +// let mut pw = PartialWitness::new(); +// let degree_bits = inner_proof.proof.recover_degree_bits(config); +// let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, config, degree_bits); +// pw.set_proof_with_pis_target(&pt, &inner_proof); +// +// let inner_data = VerifierCircuitTarget { +// constants_sigmas_cap: builder.add_virtual_cap(inner_cd.config.fri_config.cap_height), +// }; +// pw.set_cap_target( +// &inner_data.constants_sigmas_cap, +// &inner_vd.constants_sigmas_cap, +// ); +// +// builder.verify_proof(pt, &inner_data, &inner_cd); +// +// if print_gate_counts { +// builder.print_gate_counts(0); +// } +// +// if let Some(min_degree_bits) = min_degree_bits { +// // We don't want to pad all the way up to 2^min_degree_bits, as the builder will add a +// // few special gates afterward. So just pad to 2^(min_degree_bits - 1) + 1. Then the +// // builder will pad to the next power of two, 2^min_degree_bits. +// let min_gates = (1 << (min_degree_bits - 1)) + 1; +// for _ in builder.num_gates()..min_gates { +// builder.add_gate(NoopGate, vec![]); +// } +// } +// +// let data = builder.build::(); +// +// let mut timing = TimingTree::new("prove", Level::Debug); +// let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?; +// if print_timing { +// timing.print(); +// } +// +// data.verify(proof.clone())?; +// +// Ok((proof, data.verifier_only, data.common)) +// } +// +// /// Test serialization and print some size info. +// fn test_serialization< +// F: RichField + Extendable, +// C: GenericConfig, +// const D: usize, +// >( +// proof: &ProofWithPublicInputs, +// cd: &CommonCircuitData, +// ) -> Result<()> { +// let proof_bytes = proof.to_bytes()?; +// info!("Proof length: {} bytes", proof_bytes.len()); +// let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, cd)?; +// assert_eq!(proof, &proof_from_bytes); +// +// let now = std::time::Instant::now(); +// let compressed_proof = proof.clone().compress(cd)?; +// let decompressed_compressed_proof = compressed_proof.clone().decompress(cd)?; +// info!("{:.4}s to compress proof", now.elapsed().as_secs_f64()); +// assert_eq!(proof, &decompressed_compressed_proof); +// +// let compressed_proof_bytes = compressed_proof.to_bytes()?; +// info!( +// "Compressed proof length: {} bytes", +// compressed_proof_bytes.len() +// ); +// let compressed_proof_from_bytes = +// CompressedProofWithPublicInputs::from_bytes(compressed_proof_bytes, cd)?; +// assert_eq!(compressed_proof, compressed_proof_from_bytes); +// +// Ok(()) +// } +// +// fn init_logger() { +// let _ = env_logger::builder().format_timestamp(None).try_init(); +// } +// } diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 2ac038d6..7c6e7636 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -1,7 +1,10 @@ +use itertools::Itertools; use plonky2::field::extension_field::Extendable; use plonky2::field::field_types::Field; +use plonky2::fri::witness_util::set_fri_proof_target; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; +use plonky2::iop::witness::Witness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::util::reducing::ReducingFactorTarget; @@ -9,8 +12,8 @@ use plonky2::util::reducing::ReducingFactorTarget; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::proof::{ - StarkOpeningSetTarget, StarkProofChallengesTarget, StarkProofTarget, - StarkProofWithPublicInputsTarget, + StarkOpeningSetTarget, StarkProof, StarkProofChallengesTarget, StarkProofTarget, + StarkProofWithPublicInputs, StarkProofWithPublicInputsTarget, }; use crate::stark::Stark; use crate::vars::StarkEvaluationTargets; @@ -210,3 +213,50 @@ fn add_stark_opening_set, S: Stark, const D: .add_virtual_extension_targets(stark.quotient_degree_factor() * num_challenges), } } + +pub fn set_startk_proof_with_pis_target, W, const D: usize>( + witness: &mut W, + stark_proof_with_pis_target: &StarkProofWithPublicInputsTarget, + stark_proof_with_pis: &StarkProofWithPublicInputs, +) where + F: RichField + Extendable, + C::Hasher: AlgebraicHasher, + W: Witness, +{ + let StarkProofWithPublicInputs { + proof, + public_inputs, + } = stark_proof_with_pis; + let StarkProofWithPublicInputsTarget { + proof: pt, + public_inputs: pi_targets, + } = stark_proof_with_pis_target; + + // Set public inputs. + for (&pi_t, &pi) in pi_targets.iter().zip_eq(public_inputs) { + witness.set_target(pi_t, pi); + } + + set_stark_proof_target(witness, pt, proof); +} + +pub fn set_stark_proof_target, W, const D: usize>( + witness: &mut W, + proof_target: &StarkProofTarget, + proof: &StarkProof, +) where + F: RichField + Extendable, + C::Hasher: AlgebraicHasher, + W: Witness, +{ + witness.set_cap_target(&proof_target.trace_cap, &proof.trace_cap); + witness.set_cap_target(&proof_target.quotient_polys_cap, &proof.quotient_polys_cap); + + let openings = proof.openings.to_fri_openings(); + let openings_target = proof_target.openings.to_fri_openings(); + for (batch, batch_target) in openings.batches.iter().zip_eq(&openings_target.batches) { + witness.set_extension_targets(&batch_target.values, &batch.values); + } + + set_fri_proof_target(witness, &proof_target.opening_proof, &proof.opening_proof); +} From 24c201477cafd1dc3a86d7b39704532620b50a56 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 10 Feb 2022 16:14:18 +0100 Subject: [PATCH 08/20] Recursive stark test (failing) --- plonky2/src/plonk/circuit_data.rs | 10 +- plonky2/src/plonk/prover.rs | 2 +- starky/src/fibonacci_stark.rs | 451 +++++++++--------------------- starky/src/stark.rs | 2 +- 4 files changed, 144 insertions(+), 321 deletions(-) diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 7e667b8d..a113fcdb 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -96,9 +96,9 @@ impl CircuitConfig { /// Circuit data required by the prover or the verifier. pub struct CircuitData, C: GenericConfig, const D: usize> { - pub(crate) prover_only: ProverOnlyCircuitData, - pub(crate) verifier_only: VerifierOnlyCircuitData, - pub(crate) common: CommonCircuitData, + pub prover_only: ProverOnlyCircuitData, + pub verifier_only: VerifierOnlyCircuitData, + pub common: CommonCircuitData, } impl, C: GenericConfig, const D: usize> @@ -181,7 +181,7 @@ impl, C: GenericConfig, const D: usize> } /// Circuit data required by the prover, but not the verifier. -pub(crate) struct ProverOnlyCircuitData< +pub struct ProverOnlyCircuitData< F: RichField + Extendable, C: GenericConfig, const D: usize, @@ -209,7 +209,7 @@ pub(crate) struct ProverOnlyCircuitData< /// Circuit data required by the verifier, but not the prover. #[derive(Debug)] -pub(crate) struct VerifierOnlyCircuitData, const D: usize> { +pub struct VerifierOnlyCircuitData, const D: usize> { /// A commitment to each constant polynomial and each permutation polynomial. pub(crate) constants_sigmas_cap: MerkleCap, } diff --git a/plonky2/src/plonk/prover.rs b/plonky2/src/plonk/prover.rs index d49014f0..9932462b 100644 --- a/plonky2/src/plonk/prover.rs +++ b/plonky2/src/plonk/prover.rs @@ -26,7 +26,7 @@ use crate::util::partial_products::{partial_products_and_z_gx, quotient_chunk_pr use crate::util::timing::TimingTree; use crate::util::transpose; -pub(crate) fn prove, C: GenericConfig, const D: usize>( +pub fn prove, C: GenericConfig, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, inputs: PartialWitness, diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 92432c64..d4c18ff6 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -105,317 +105,140 @@ impl, const D: usize> Stark for FibonacciStar } } -// #[cfg(test)] -// mod tests { -// use anyhow::Result; -// use plonky2::field::extension_field::Extendable; -// use plonky2::field::field_types::Field; -// use plonky2::hash::hash_types::RichField; -// use plonky2::iop::witness::PartialWitness; -// use plonky2::plonk::circuit_builder::CircuitBuilder; -// use plonky2::plonk::circuit_data::CommonCircuitData; -// use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; -// use plonky2::plonk::proof::ProofWithPublicInputs; -// use plonky2::util::timing::TimingTree; -// -// use crate::config::StarkConfig; -// use crate::fibonacci_stark::FibonacciStark; -// use crate::proof::StarkProofWithPublicInputs; -// use crate::prover::prove; -// use crate::recursive_verifier::add_virtual_stark_proof_with_pis; -// use crate::stark_testing::test_stark_low_degree; -// use crate::verifier::verify; -// -// fn fibonacci(n: usize, x0: F, x1: F) -> F { -// (0..n).fold((x0, x1), |x, _| (x.1, x.0 + x.1)).1 -// } -// -// #[test] -// fn test_fibonacci_stark() -> Result<()> { -// const D: usize = 2; -// type C = PoseidonGoldilocksConfig; -// type F = >::F; -// type S = FibonacciStark; -// -// let config = StarkConfig::standard_fast_config(); -// let num_rows = 1 << 5; -// let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; -// let stark = S::new(num_rows); -// let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); -// let proof = prove::( -// stark, -// &config, -// trace, -// public_inputs, -// &mut TimingTree::default(), -// )?; -// -// verify(stark, proof, &config) -// } -// -// #[test] -// fn test_fibonacci_stark_degree() -> Result<()> { -// const D: usize = 2; -// type C = PoseidonGoldilocksConfig; -// type F = >::F; -// type S = FibonacciStark; -// -// let config = StarkConfig::standard_fast_config(); -// let num_rows = 1 << 5; -// let stark = S::new(num_rows); -// test_stark_low_degree(stark) -// } -// -// #[test] -// fn test_recursive_stark_verifier() -> Result<()> { -// init_logger(); -// const D: usize = 2; -// type C = PoseidonGoldilocksConfig; -// type F = >::F; -// type S = FibonacciStark; -// -// let config = StarkConfig::standard_fast_config(); -// let num_rows = 1 << 5; -// let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; -// let stark = S::new(num_rows); -// let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); -// let proof = prove::( -// stark, -// &config, -// trace, -// public_inputs, -// &mut TimingTree::default(), -// )?; -// -// let (proof, _vd, cd) = -// recursive_proof::(proof, vd, cd, &config, None, true, true)?; -// test_serialization(&proof, &cd)?; -// -// Ok(()) -// } -// -// #[test] -// fn test_recursive_recursive_verifier() -> Result<()> { -// init_logger(); -// const D: usize = 2; -// type C = PoseidonGoldilocksConfig; -// type F = >::F; -// -// let config = CircuitConfig::standard_recursion_config(); -// -// // Start with a degree 2^14 proof -// let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; -// assert_eq!(cd.degree_bits, 14); -// -// // Shrink it to 2^13. -// let (proof, vd, cd) = -// recursive_proof::(proof, vd, cd, &config, Some(13), false, false)?; -// assert_eq!(cd.degree_bits, 13); -// -// // Shrink it to 2^12. -// let (proof, _vd, cd) = -// recursive_proof::(proof, vd, cd, &config, None, true, true)?; -// assert_eq!(cd.degree_bits, 12); -// -// test_serialization(&proof, &cd)?; -// -// Ok(()) -// } -// -// /// Creates a chain of recursive proofs where the last proof is made as small as reasonably -// /// possible, using a high rate, high PoW bits, etc. -// #[test] -// #[ignore] -// fn test_size_optimized_recursion() -> Result<()> { -// init_logger(); -// 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)?; -// assert_eq!(cd.degree_bits, 12); -// -// // A standard recursive proof. -// let (proof, vd, cd) = recursive_proof(proof, vd, cd, &standard_config, None, false, false)?; -// assert_eq!(cd.degree_bits, 12); -// -// // A high-rate recursive proof, designed to be verifiable with fewer routed wires. -// let high_rate_config = CircuitConfig { -// fri_config: FriConfig { -// rate_bits: 7, -// proof_of_work_bits: 16, -// num_query_rounds: 12, -// ..standard_config.fri_config.clone() -// }, -// ..standard_config -// }; -// let (proof, vd, cd) = -// recursive_proof::(proof, vd, cd, &high_rate_config, None, true, true)?; -// assert_eq!(cd.degree_bits, 12); -// -// // A final proof, optimized for size. -// let final_config = CircuitConfig { -// num_routed_wires: 37, -// fri_config: FriConfig { -// rate_bits: 8, -// cap_height: 0, -// proof_of_work_bits: 20, -// reduction_strategy: FriReductionStrategy::MinSize(None), -// num_query_rounds: 10, -// }, -// ..high_rate_config -// }; -// let (proof, _vd, cd) = -// recursive_proof::(proof, vd, cd, &final_config, None, true, true)?; -// assert_eq!(cd.degree_bits, 12, "final proof too large"); -// -// test_serialization(&proof, &cd)?; -// -// Ok(()) -// } -// -// #[test] -// fn test_recursive_verifier_multi_hash() -> Result<()> { -// init_logger(); -// const D: usize = 2; -// type PC = PoseidonGoldilocksConfig; -// type KC = KeccakGoldilocksConfig; -// 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, None, false, false)?; -// test_serialization(&proof, &cd)?; -// -// let (proof, _vd, cd) = -// recursive_proof::(proof, vd, cd, &config, None, false, false)?; -// test_serialization(&proof, &cd)?; -// -// Ok(()) -// } -// -// /// Creates a dummy proof which should have roughly `num_dummy_gates` gates. -// fn dummy_proof, C: GenericConfig, const D: usize>( -// config: &CircuitConfig, -// num_dummy_gates: u64, -// ) -> Result<( -// 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 inputs = PartialWitness::new(); -// let proof = data.prove(inputs)?; -// data.verify(proof.clone())?; -// -// Ok((proof, data.verifier_only, data.common)) -// } -// -// fn recursive_proof< -// F: RichField + Extendable, -// C: GenericConfig, -// InnerC: GenericConfig, -// const D: usize, -// >( -// inner_proof: StarkProofWithPublicInputs, -// config: &StarkConfig, -// print_gate_counts: bool, -// print_timing: bool, -// ) -> Result<( -// ProofWithPublicInputs, -// VerifierOnlyCircuitData, -// CommonCircuitData, -// )> -// where -// InnerC::Hasher: AlgebraicHasher, -// { -// let mut builder = CircuitBuilder::::new(config.clone()); -// let mut pw = PartialWitness::new(); -// let degree_bits = inner_proof.proof.recover_degree_bits(config); -// let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, config, degree_bits); -// pw.set_proof_with_pis_target(&pt, &inner_proof); -// -// let inner_data = VerifierCircuitTarget { -// constants_sigmas_cap: builder.add_virtual_cap(inner_cd.config.fri_config.cap_height), -// }; -// pw.set_cap_target( -// &inner_data.constants_sigmas_cap, -// &inner_vd.constants_sigmas_cap, -// ); -// -// builder.verify_proof(pt, &inner_data, &inner_cd); -// -// if print_gate_counts { -// builder.print_gate_counts(0); -// } -// -// if let Some(min_degree_bits) = min_degree_bits { -// // We don't want to pad all the way up to 2^min_degree_bits, as the builder will add a -// // few special gates afterward. So just pad to 2^(min_degree_bits - 1) + 1. Then the -// // builder will pad to the next power of two, 2^min_degree_bits. -// let min_gates = (1 << (min_degree_bits - 1)) + 1; -// for _ in builder.num_gates()..min_gates { -// builder.add_gate(NoopGate, vec![]); -// } -// } -// -// let data = builder.build::(); -// -// let mut timing = TimingTree::new("prove", Level::Debug); -// let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?; -// if print_timing { -// timing.print(); -// } -// -// data.verify(proof.clone())?; -// -// Ok((proof, data.verifier_only, data.common)) -// } -// -// /// Test serialization and print some size info. -// fn test_serialization< -// F: RichField + Extendable, -// C: GenericConfig, -// const D: usize, -// >( -// proof: &ProofWithPublicInputs, -// cd: &CommonCircuitData, -// ) -> Result<()> { -// let proof_bytes = proof.to_bytes()?; -// info!("Proof length: {} bytes", proof_bytes.len()); -// let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, cd)?; -// assert_eq!(proof, &proof_from_bytes); -// -// let now = std::time::Instant::now(); -// let compressed_proof = proof.clone().compress(cd)?; -// let decompressed_compressed_proof = compressed_proof.clone().decompress(cd)?; -// info!("{:.4}s to compress proof", now.elapsed().as_secs_f64()); -// assert_eq!(proof, &decompressed_compressed_proof); -// -// let compressed_proof_bytes = compressed_proof.to_bytes()?; -// info!( -// "Compressed proof length: {} bytes", -// compressed_proof_bytes.len() -// ); -// let compressed_proof_from_bytes = -// CompressedProofWithPublicInputs::from_bytes(compressed_proof_bytes, cd)?; -// assert_eq!(compressed_proof, compressed_proof_from_bytes); -// -// Ok(()) -// } -// -// fn init_logger() { -// let _ = env_logger::builder().format_timestamp(None).try_init(); -// } -// } +#[cfg(test)] +mod tests { + use anyhow::Result; + use log::Level; + use plonky2::field::extension_field::Extendable; + use plonky2::field::field_types::Field; + use plonky2::hash::hash_types::RichField; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; + use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::proof::ProofWithPublicInputs; + use plonky2::util::timing::TimingTree; + use plonky2_util::reverse_index_bits_in_place; + + use crate::config::StarkConfig; + use crate::fibonacci_stark::FibonacciStark; + use crate::proof::StarkProofWithPublicInputs; + use crate::prover::prove; + use crate::recursive_verifier::{ + add_virtual_stark_proof_with_pis, set_startk_proof_with_pis_target, verify_stark_proof, + }; + use crate::stark::Stark; + use crate::stark_testing::test_stark_low_degree; + use crate::verifier::verify; + + fn fibonacci(n: usize, x0: F, x1: F) -> F { + (0..n).fold((x0, x1), |x, _| (x.1, x.0 + x.1)).1 + } + + #[test] + fn test_fibonacci_stark() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type S = FibonacciStark; + + let config = StarkConfig::standard_fast_config(); + let num_rows = 1 << 5; + let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; + let stark = S::new(num_rows); + let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); + let proof = prove::( + stark, + &config, + trace, + public_inputs, + &mut TimingTree::default(), + )?; + + verify(stark, proof, &config) + } + + #[test] + fn test_fibonacci_stark_degree() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type S = FibonacciStark; + + let config = StarkConfig::standard_fast_config(); + let num_rows = 1 << 5; + let stark = S::new(num_rows); + test_stark_low_degree(stark) + } + + #[test] + fn test_recursive_stark_verifier() -> Result<()> { + init_logger(); + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type S = FibonacciStark; + + let config = StarkConfig::standard_fast_config(); + let num_rows = 1 << 5; + let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; + let stark = S::new(num_rows); + let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); + let proof = prove::( + stark, + &config, + trace, + public_inputs, + &mut TimingTree::default(), + )?; + + recursive_proof::(stark, proof, &config, true, true) + } + + fn recursive_proof< + F: RichField + Extendable, + C: GenericConfig, + S: Stark, + InnerC: GenericConfig, + const D: usize, + >( + stark: S, + inner_proof: StarkProofWithPublicInputs, + inner_config: &StarkConfig, + print_gate_counts: bool, + print_timing: bool, + ) -> Result<()> + where + InnerC::Hasher: AlgebraicHasher, + [(); S::COLUMNS]:, + [(); S::PUBLIC_INPUTS]:, + { + let circuit_config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(circuit_config); + let mut pw = PartialWitness::new(); + let degree_bits = inner_proof.proof.recover_degree_bits(inner_config); + let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, inner_config, degree_bits); + set_startk_proof_with_pis_target(&mut pw, &pt, &inner_proof); + + verify_stark_proof::(&mut builder, stark, pt, inner_config); + + if print_gate_counts { + builder.print_gate_counts(0); + } + + let data = builder.build::(); + + let mut timing = TimingTree::new("prove", Level::Debug); + let proof = + plonky2::plonk::prover::prove(&data.prover_only, &data.common, pw, &mut timing)?; + if print_timing { + timing.print(); + } + + data.verify(proof.clone()) + } + + fn init_logger() { + let _ = env_logger::builder().format_timestamp(None).try_init(); + } +} diff --git a/starky/src/stark.rs b/starky/src/stark.rs index 3ef976e0..888dc004 100644 --- a/starky/src/stark.rs +++ b/starky/src/stark.rs @@ -14,7 +14,7 @@ use crate::vars::StarkEvaluationVars; /// Represents a STARK system. // TODO: Add a `constraint_degree` fn that returns the maximum constraint degree. -pub trait Stark, const D: usize>: Sync { +pub trait Stark, const D: usize>: Sync + Copy { /// The total number of columns in the trace. const COLUMNS: usize; /// The number of public inputs. From d22fa8895b487844f2db632eb3e433937c4b6d9c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 11 Feb 2022 10:37:17 +0100 Subject: [PATCH 09/20] Fix one error to get another one --- starky/src/proof.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starky/src/proof.rs b/starky/src/proof.rs index c505a59b..3999e455 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -34,7 +34,7 @@ impl, C: GenericConfig, const D: usize> S .evals_proofs[0] .1; let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); - 1 << (lde_bits - config.fri_config.rate_bits) + lde_bits - config.fri_config.rate_bits } } @@ -52,7 +52,7 @@ impl StarkProofTarget { .evals_proofs[0] .1; let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); - 1 << (lde_bits - config.fri_config.rate_bits) + lde_bits - config.fri_config.rate_bits } } From 2e008eac23611513ecbd43126f22d8130096d7c6 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 09:35:08 +0100 Subject: [PATCH 10/20] Change Merkle tree lead hashing (to change back when #481 lands) --- plonky2/src/hash/merkle_proofs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index f90f0657..91bb17b6 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -62,7 +62,8 @@ impl, const D: usize> CircuitBuilder { proof: &MerkleProofTarget, ) { let zero = self.zero(); - let mut state: HashOutTarget = self.hash_or_noop::(leaf_data); + // TODO: Change this when #481 lands. + let mut state: HashOutTarget = self.hash_n_to_hash_no_pad::(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { let mut perm_inputs = [zero; SPONGE_WIDTH]; @@ -93,7 +94,8 @@ impl, const D: usize> CircuitBuilder { proof: &MerkleProofTarget, ) { let zero = self.zero(); - let mut state: HashOutTarget = self.hash_or_noop::(leaf_data); + // TODO: Change this when #481 lands. + let mut state: HashOutTarget = self.hash_n_to_hash_no_pad::(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { let mut perm_inputs = [zero; SPONGE_WIDTH]; From b0de3328c1945803810e0b407f62eba107b9cc4d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 09:53:33 +0100 Subject: [PATCH 11/20] Working --- plonky2/src/iop/generator.rs | 16 ++++++++++++++++ starky/src/constraint_consumer.rs | 4 ++-- starky/src/fibonacci_stark.rs | 1 + starky/src/proof.rs | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index 73978f5c..961b71a5 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -158,6 +158,22 @@ impl GeneratedValues { } pub fn set_target(&mut self, target: Target, value: F) { + if target + == Target::Wire(Wire { + gate: 42, + input: 54, + }) + { + dbg!(value); + } + if target + == Target::Wire(Wire { + gate: 41, + input: 34, + }) + { + dbg!(value); + } self.target_values.push((target, value)) } diff --git a/starky/src/constraint_consumer.rs b/starky/src/constraint_consumer.rs index 932b2db8..88f66118 100644 --- a/starky/src/constraint_consumer.rs +++ b/starky/src/constraint_consumer.rs @@ -150,7 +150,7 @@ impl, const D: usize> RecursiveConstraintConsumer, ) { let filtered_constraint = builder.mul_extension(constraint, self.lagrange_basis_first); - self.constraint(builder, filtered_constraint); + self.constraint_wrapping(builder, filtered_constraint); } /// Add one constraint, but first multiply it by a filter such that it will only apply to the @@ -161,6 +161,6 @@ impl, const D: usize> RecursiveConstraintConsumer, ) { let filtered_constraint = builder.mul_extension(constraint, self.lagrange_basis_last); - self.constraint(builder, filtered_constraint); + self.constraint_wrapping(builder, filtered_constraint); } } diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index d4c18ff6..1c7b870e 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -191,6 +191,7 @@ mod tests { public_inputs, &mut TimingTree::default(), )?; + verify(stark, proof.clone(), &config)?; recursive_proof::(stark, proof, &config, true, true) } diff --git a/starky/src/proof.rs b/starky/src/proof.rs index 3999e455..8e225e79 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -16,6 +16,7 @@ use rayon::prelude::*; use crate::config::StarkConfig; // TODO: Permutation polynomials. +#[derive(Debug, Clone)] pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. pub trace_cap: MerkleCap, @@ -56,6 +57,7 @@ impl StarkProofTarget { } } +#[derive(Debug, Clone)] pub struct StarkProofWithPublicInputs< F: RichField + Extendable, C: GenericConfig, @@ -110,6 +112,7 @@ pub(crate) struct StarkProofChallengesTarget { } /// Purported values of each polynomial at the challenge point. +#[derive(Debug, Clone)] pub struct StarkOpeningSet, const D: usize> { pub local_values: Vec, pub next_values: Vec, From 80e3c928bb2f99b1fda638064a1fb85abf75065d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 10:00:37 +0100 Subject: [PATCH 12/20] Clippy --- plonky2/src/iop/generator.rs | 16 ---------------- starky/src/fibonacci_stark.rs | 6 ++---- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index 961b71a5..73978f5c 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -158,22 +158,6 @@ impl GeneratedValues { } pub fn set_target(&mut self, target: Target, value: F) { - if target - == Target::Wire(Wire { - gate: 42, - input: 54, - }) - { - dbg!(value); - } - if target - == Target::Wire(Wire { - gate: 41, - input: 34, - }) - { - dbg!(value); - } self.target_values.push((target, value)) } diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 1c7b870e..eff373ac 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -114,11 +114,9 @@ mod tests { use plonky2::hash::hash_types::RichField; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; + use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; - use plonky2::plonk::proof::ProofWithPublicInputs; use plonky2::util::timing::TimingTree; - use plonky2_util::reverse_index_bits_in_place; use crate::config::StarkConfig; use crate::fibonacci_stark::FibonacciStark; @@ -236,7 +234,7 @@ mod tests { timing.print(); } - data.verify(proof.clone()) + data.verify(proof) } fn init_logger() { From 3db9c775b4124a4c98b00a8df2c3886a1d9f3759 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 10:09:08 +0100 Subject: [PATCH 13/20] Add `set_fri_openings` --- plonky2/src/iop/witness.rs | 26 +++++++++++++++++++++----- starky/src/recursive_verifier.rs | 9 ++++----- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index 651e1707..8220e85b 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -5,6 +5,7 @@ use num::{BigUint, FromPrimitive, Zero}; use plonky2_field::extension_field::{Extendable, FieldExtension}; use plonky2_field::field_types::Field; +use crate::fri::structure::{FriOpenings, FriOpeningsTarget}; use crate::fri::witness_util::set_fri_proof_target; use crate::gadgets::arithmetic_u32::U32Target; use crate::gadgets::biguint::BigUintTarget; @@ -201,15 +202,30 @@ pub trait Witness { ); self.set_cap_target(&proof_target.quotient_polys_cap, &proof.quotient_polys_cap); - let openings = proof.openings.to_fri_openings(); - let openings_target = proof_target.openings.to_fri_openings(); - for (batch, batch_target) in openings.batches.iter().zip_eq(&openings_target.batches) { - self.set_extension_targets(&batch_target.values, &batch.values); - } + self.set_fri_openings( + &proof_target.openings.to_fri_openings(), + &proof.openings.to_fri_openings(), + ); set_fri_proof_target(self, &proof_target.opening_proof, &proof.opening_proof); } + fn set_fri_openings( + &mut self, + fri_openings_target: &FriOpeningsTarget, + fri_openings: &FriOpenings, + ) where + F: RichField + Extendable, + { + for (batch_target, batch) in fri_openings_target + .batches + .iter() + .zip_eq(&fri_openings.batches) + { + self.set_extension_targets(&batch_target.values, &batch.values); + } + } + fn set_wire(&mut self, wire: Wire, value: F) { self.set_target(Target::Wire(wire), value) } diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 7c6e7636..16ac07b5 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -252,11 +252,10 @@ pub fn set_stark_proof_target, W, const D: usize>( witness.set_cap_target(&proof_target.trace_cap, &proof.trace_cap); witness.set_cap_target(&proof_target.quotient_polys_cap, &proof.quotient_polys_cap); - let openings = proof.openings.to_fri_openings(); - let openings_target = proof_target.openings.to_fri_openings(); - for (batch, batch_target) in openings.batches.iter().zip_eq(&openings_target.batches) { - witness.set_extension_targets(&batch_target.values, &batch.values); - } + witness.set_fri_openings( + &proof_target.openings.to_fri_openings(), + &proof.openings.to_fri_openings(), + ); set_fri_proof_target(witness, &proof_target.opening_proof, &proof.opening_proof); } From cff39c55500ff6acbafce7b0cef2527d5f0e6c2e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 10:12:24 +0100 Subject: [PATCH 14/20] Change visibility --- plonky2/src/plonk/circuit_data.rs | 6 +++--- starky/src/fibonacci_stark.rs | 10 +--------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index a113fcdb..745e844e 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -96,9 +96,9 @@ impl CircuitConfig { /// Circuit data required by the prover or the verifier. pub struct CircuitData, C: GenericConfig, const D: usize> { - pub prover_only: ProverOnlyCircuitData, - pub verifier_only: VerifierOnlyCircuitData, - pub common: CommonCircuitData, + pub(crate) prover_only: ProverOnlyCircuitData, + pub(crate) verifier_only: VerifierOnlyCircuitData, + pub(crate) common: CommonCircuitData, } impl, C: GenericConfig, const D: usize> diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index eff373ac..8e407968 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -108,7 +108,6 @@ impl, const D: usize> Stark for FibonacciStar #[cfg(test)] mod tests { use anyhow::Result; - use log::Level; use plonky2::field::extension_field::Extendable; use plonky2::field::field_types::Field; use plonky2::hash::hash_types::RichField; @@ -226,14 +225,7 @@ mod tests { } let data = builder.build::(); - - let mut timing = TimingTree::new("prove", Level::Debug); - let proof = - plonky2::plonk::prover::prove(&data.prover_only, &data.common, pw, &mut timing)?; - if print_timing { - timing.print(); - } - + let proof = data.prove(pw)?; data.verify(proof) } From 83701096c4aca631573037b792bb945cbcd1a842 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 10:14:31 +0100 Subject: [PATCH 15/20] More visibility changes --- plonky2/src/plonk/circuit_data.rs | 4 ++-- plonky2/src/plonk/prover.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 745e844e..7e667b8d 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -181,7 +181,7 @@ impl, C: GenericConfig, const D: usize> } /// Circuit data required by the prover, but not the verifier. -pub struct ProverOnlyCircuitData< +pub(crate) struct ProverOnlyCircuitData< F: RichField + Extendable, C: GenericConfig, const D: usize, @@ -209,7 +209,7 @@ pub struct ProverOnlyCircuitData< /// Circuit data required by the verifier, but not the prover. #[derive(Debug)] -pub struct VerifierOnlyCircuitData, const D: usize> { +pub(crate) struct VerifierOnlyCircuitData, const D: usize> { /// A commitment to each constant polynomial and each permutation polynomial. pub(crate) constants_sigmas_cap: MerkleCap, } diff --git a/plonky2/src/plonk/prover.rs b/plonky2/src/plonk/prover.rs index 9932462b..d49014f0 100644 --- a/plonky2/src/plonk/prover.rs +++ b/plonky2/src/plonk/prover.rs @@ -26,7 +26,7 @@ use crate::util::partial_products::{partial_products_and_z_gx, quotient_chunk_pr use crate::util::timing::TimingTree; use crate::util::transpose; -pub fn prove, C: GenericConfig, const D: usize>( +pub(crate) fn prove, C: GenericConfig, const D: usize>( prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, inputs: PartialWitness, From 6dca4e26af3610a75c41d0dc6be1a809a32918bb Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 10:16:02 +0100 Subject: [PATCH 16/20] Unused --- starky/src/fibonacci_stark.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 8e407968..28555207 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -204,7 +204,6 @@ mod tests { inner_proof: StarkProofWithPublicInputs, inner_config: &StarkConfig, print_gate_counts: bool, - print_timing: bool, ) -> Result<()> where InnerC::Hasher: AlgebraicHasher, From 1686cb021fb7c481459d739961f5faf8c7d63e27 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 10:20:59 +0100 Subject: [PATCH 17/20] `verify_stark_proof` -> `recursively_verify_stark_proof` --- starky/src/fibonacci_stark.rs | 5 +++-- starky/src/recursive_verifier.rs | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 28555207..156b14f8 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -122,7 +122,8 @@ mod tests { use crate::proof::StarkProofWithPublicInputs; use crate::prover::prove; use crate::recursive_verifier::{ - add_virtual_stark_proof_with_pis, set_startk_proof_with_pis_target, verify_stark_proof, + add_virtual_stark_proof_with_pis, recursively_verify_stark_proof, + set_startk_proof_with_pis_target, }; use crate::stark::Stark; use crate::stark_testing::test_stark_low_degree; @@ -217,7 +218,7 @@ mod tests { let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, inner_config, degree_bits); set_startk_proof_with_pis_target(&mut pw, &pt, &inner_proof); - verify_stark_proof::(&mut builder, stark, pt, inner_config); + recursively_verify_stark_proof::(&mut builder, stark, pt, inner_config); if print_gate_counts { builder.print_gate_counts(0); diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 16ac07b5..d6d559b6 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -18,7 +18,7 @@ use crate::proof::{ use crate::stark::Stark; use crate::vars::StarkEvaluationTargets; -pub fn verify_stark_proof< +pub fn recursively_verify_stark_proof< F: RichField + Extendable, C: GenericConfig, S: Stark, @@ -37,7 +37,7 @@ pub fn verify_stark_proof< let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config); let challenges = proof_with_pis.get_challenges::(builder, inner_config, degree_bits); - verify_stark_proof_with_challenges::( + recursively_verify_stark_proof_with_challenges::( builder, stark, proof_with_pis, @@ -48,7 +48,7 @@ pub fn verify_stark_proof< } /// Recursively verifies an inner proof. -fn verify_stark_proof_with_challenges< +fn recursively_verify_stark_proof_with_challenges< F: RichField + Extendable, C: GenericConfig, S: Stark, From 7820ba965c2fbd8cbbb9e345e718d3d0972979ce Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 14 Feb 2022 10:23:26 +0100 Subject: [PATCH 18/20] Minor --- starky/src/fibonacci_stark.rs | 4 ++-- starky/src/stark.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 156b14f8..69ff2450 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -191,13 +191,13 @@ mod tests { )?; verify(stark, proof.clone(), &config)?; - recursive_proof::(stark, proof, &config, true, true) + recursive_proof::(stark, proof, &config, true) } fn recursive_proof< F: RichField + Extendable, C: GenericConfig, - S: Stark, + S: Stark + Copy, InnerC: GenericConfig, const D: usize, >( diff --git a/starky/src/stark.rs b/starky/src/stark.rs index 888dc004..3ef976e0 100644 --- a/starky/src/stark.rs +++ b/starky/src/stark.rs @@ -14,7 +14,7 @@ use crate::vars::StarkEvaluationVars; /// Represents a STARK system. // TODO: Add a `constraint_degree` fn that returns the maximum constraint degree. -pub trait Stark, const D: usize>: Sync + Copy { +pub trait Stark, const D: usize>: Sync { /// The total number of columns in the trace. const COLUMNS: usize; /// The number of public inputs. From acd62f122127f54b9f3320571190f9a950d46909 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 15 Feb 2022 08:17:07 +0100 Subject: [PATCH 19/20] Changes after #481 --- plonky2/src/hash/merkle_proofs.rs | 6 ++---- starky/src/fibonacci_stark.rs | 5 ++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index 95a5b88b..c3ebf406 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -65,8 +65,7 @@ impl, const D: usize> CircuitBuilder { proof: &MerkleProofTarget, ) { let zero = self.zero(); - // TODO: Change this when #481 lands. - let mut state: HashOutTarget = self.hash_n_to_hash_no_pad::(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]; @@ -97,8 +96,7 @@ impl, const D: usize> CircuitBuilder { proof: &MerkleProofTarget, ) { let zero = self.zero(); - // TODO: Change this when #481 lands. - let mut state: HashOutTarget = self.hash_n_to_hash_no_pad::(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]; diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 69ff2450..08125180 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -114,7 +114,9 @@ mod tests { use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::config::{ + AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig, + }; use plonky2::util::timing::TimingTree; use crate::config::StarkConfig; @@ -210,6 +212,7 @@ mod tests { InnerC::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, + [(); C::Hasher::HASH_SIZE]:, { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); From 42d6532120ff3834fa81ebcbe542e05483066509 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 15 Feb 2022 08:35:57 +0100 Subject: [PATCH 20/20] PR feedback --- starky/src/config.rs | 13 +------------ starky/src/fibonacci_stark.rs | 19 +++++++++---------- starky/src/get_challenges.rs | 8 -------- starky/src/lib.rs | 1 + starky/src/proof.rs | 1 - starky/src/recursive_verifier.rs | 8 +++----- starky/src/stark.rs | 4 ++-- starky/src/verifier.rs | 8 +++----- system_zero/src/system_zero.rs | 4 ++-- 9 files changed, 21 insertions(+), 45 deletions(-) diff --git a/starky/src/config.rs b/starky/src/config.rs index 24fb725a..500cd957 100644 --- a/starky/src/config.rs +++ b/starky/src/config.rs @@ -29,17 +29,6 @@ impl StarkConfig { } pub(crate) fn fri_params(&self, degree_bits: usize) -> FriParams { - let fri_config = &self.fri_config; - let reduction_arity_bits = fri_config.reduction_strategy.reduction_arity_bits( - degree_bits, - fri_config.rate_bits, - fri_config.num_query_rounds, - ); - FriParams { - config: fri_config.clone(), - hiding: false, - degree_bits, - reduction_arity_bits, - } + self.fri_config.fri_params(degree_bits, false) } } diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 08125180..bd1775e1 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -67,9 +67,9 @@ impl, const D: usize> Stark for FibonacciStar yield_constr .constraint_last_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_RES]); - // x0 <- x1 + // x0' <- x1 yield_constr.constraint(vars.next_values[0] - vars.local_values[1]); - // x1 <- x0 + x1 + // x1' <- x0 + x1 yield_constr.constraint(vars.next_values[1] - vars.local_values[0] - vars.local_values[1]); } @@ -89,10 +89,10 @@ impl, const D: usize> Stark for FibonacciStar yield_constr.constraint_first_row(builder, pis_constraints[1]); yield_constr.constraint_last_row(builder, pis_constraints[2]); - // x0 <- x1 + // x0' <- x1 let first_col_constraint = builder.sub_extension(vars.next_values[0], vars.local_values[1]); yield_constr.constraint(builder, first_col_constraint); - // x1 <- x0 + x1 + // x1' <- x0 + x1 let second_col_constraint = { let tmp = builder.sub_extension(vars.next_values[1], vars.local_values[0]); builder.sub_extension(tmp, vars.local_values[1]) @@ -125,11 +125,11 @@ mod tests { use crate::prover::prove; use crate::recursive_verifier::{ add_virtual_stark_proof_with_pis, recursively_verify_stark_proof, - set_startk_proof_with_pis_target, + set_stark_proof_with_pis_target, }; use crate::stark::Stark; use crate::stark_testing::test_stark_low_degree; - use crate::verifier::verify; + use crate::verifier::verify_stark_proof; fn fibonacci(n: usize, x0: F, x1: F) -> F { (0..n).fold((x0, x1), |x, _| (x.1, x.0 + x.1)).1 @@ -155,7 +155,7 @@ mod tests { &mut TimingTree::default(), )?; - verify(stark, proof, &config) + verify_stark_proof(stark, proof, &config) } #[test] @@ -165,7 +165,6 @@ mod tests { type F = >::F; type S = FibonacciStark; - let config = StarkConfig::standard_fast_config(); let num_rows = 1 << 5; let stark = S::new(num_rows); test_stark_low_degree(stark) @@ -191,7 +190,7 @@ mod tests { public_inputs, &mut TimingTree::default(), )?; - verify(stark, proof.clone(), &config)?; + verify_stark_proof(stark, proof.clone(), &config)?; recursive_proof::(stark, proof, &config, true) } @@ -219,7 +218,7 @@ mod tests { let mut pw = PartialWitness::new(); let degree_bits = inner_proof.proof.recover_degree_bits(inner_config); let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, inner_config, degree_bits); - set_startk_proof_with_pis_target(&mut pw, &pt, &inner_proof); + set_stark_proof_with_pis_target(&mut pw, &pt, &inner_proof); recursively_verify_stark_proof::(&mut builder, stark, pt, inner_config); diff --git a/starky/src/get_challenges.rs b/starky/src/get_challenges.rs index 3d815caf..24845c9a 100644 --- a/starky/src/get_challenges.rs +++ b/starky/src/get_challenges.rs @@ -17,7 +17,6 @@ use crate::proof::{ StarkProofWithPublicInputsTarget, }; -#[allow(clippy::too_many_arguments)] fn get_challenges, C: GenericConfig, const D: usize>( trace_cap: &MerkleCap, quotient_polys_cap: &MerkleCap, @@ -29,8 +28,6 @@ fn get_challenges, C: GenericConfig, cons degree_bits: usize, ) -> Result> { let num_challenges = config.num_challenges; - let num_fri_queries = config.fri_config.num_query_rounds; - let lde_size = 1 << (degree_bits + config.fri_config.rate_bits); let mut challenger = Challenger::::new(); @@ -115,14 +112,11 @@ pub(crate) fn get_challenges_target< final_poly: &PolynomialCoeffsExtTarget, pow_witness: Target, config: &StarkConfig, - degree_bits: usize, ) -> StarkProofChallengesTarget where C::Hasher: AlgebraicHasher, { let num_challenges = config.num_challenges; - let num_fri_queries = config.fri_config.num_query_rounds; - let lde_size = 1 << (degree_bits + config.fri_config.rate_bits); let mut challenger = RecursiveChallenger::::new(builder); @@ -152,7 +146,6 @@ impl StarkProofWithPublicInputsTarget { &self, builder: &mut CircuitBuilder, config: &StarkConfig, - degree_bits: usize, ) -> StarkProofChallengesTarget where C::Hasher: AlgebraicHasher, @@ -179,7 +172,6 @@ impl StarkProofWithPublicInputsTarget { final_poly, *pow_witness, config, - degree_bits, ) } } diff --git a/starky/src/lib.rs b/starky/src/lib.rs index 01667c28..aee0ddbe 100644 --- a/starky/src/lib.rs +++ b/starky/src/lib.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] #![allow(incomplete_features)] +#![allow(clippy::too_many_arguments)] #![feature(generic_const_exprs)] pub mod config; diff --git a/starky/src/proof.rs b/starky/src/proof.rs index 8e225e79..e3fb6f72 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -15,7 +15,6 @@ use rayon::prelude::*; use crate::config::StarkConfig; -// TODO: Permutation polynomials. #[derive(Debug, Clone)] pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index d6d559b6..1a31488e 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -35,7 +35,7 @@ pub fn recursively_verify_stark_proof< { assert_eq!(proof_with_pis.public_inputs.len(), S::PUBLIC_INPUTS); let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config); - let challenges = proof_with_pis.get_challenges::(builder, inner_config, degree_bits); + let challenges = proof_with_pis.get_challenges::(builder, inner_config); recursively_verify_stark_proof_with_challenges::( builder, @@ -71,8 +71,6 @@ fn recursively_verify_stark_proof_with_challenges< proof, public_inputs, } = proof_with_pis; - let local_values = &proof.openings.local_values; - let next_values = &proof.openings.local_values; let StarkOpeningSetTarget { local_values, next_values, @@ -181,7 +179,7 @@ pub fn add_virtual_stark_proof, S: Stark, con config: &StarkConfig, degree_bits: usize, ) -> StarkProofTarget { - let fri_params = config.fri_config.fri_params(degree_bits, false); + let fri_params = config.fri_params(degree_bits); let cap_height = fri_params.config.cap_height; let num_leaves_per_oracle = &[ @@ -214,7 +212,7 @@ fn add_stark_opening_set, S: Stark, const D: } } -pub fn set_startk_proof_with_pis_target, W, const D: usize>( +pub fn set_stark_proof_with_pis_target, W, const D: usize>( witness: &mut W, stark_proof_with_pis_target: &StarkProofWithPublicInputsTarget, stark_proof_with_pis: &StarkProofWithPublicInputs, diff --git a/starky/src/stark.rs b/starky/src/stark.rs index 3ef976e0..98365344 100644 --- a/starky/src/stark.rs +++ b/starky/src/stark.rs @@ -96,7 +96,7 @@ pub trait Stark, const D: usize>: Sync { }; FriInstanceInfo { oracles: vec![no_blinding_oracle; 3], - batches: vec![zeta_batch], + batches: vec![zeta_batch, zeta_right_batch], } } @@ -124,7 +124,7 @@ pub trait Stark, const D: usize>: Sync { }; FriInstanceInfoTarget { oracles: vec![no_blinding_oracle; 3], - batches: vec![zeta_batch], + batches: vec![zeta_batch, zeta_right_batch], } } } diff --git a/starky/src/verifier.rs b/starky/src/verifier.rs index 201f4b9c..b27cf2b3 100644 --- a/starky/src/verifier.rs +++ b/starky/src/verifier.rs @@ -12,7 +12,7 @@ use crate::proof::{StarkOpeningSet, StarkProofChallenges, StarkProofWithPublicIn use crate::stark::Stark; use crate::vars::StarkEvaluationVars; -pub fn verify< +pub fn verify_stark_proof< F: RichField + Extendable, C: GenericConfig, S: Stark, @@ -30,10 +30,10 @@ where ensure!(proof_with_pis.public_inputs.len() == S::PUBLIC_INPUTS); let degree_bits = proof_with_pis.proof.recover_degree_bits(config); let challenges = proof_with_pis.get_challenges(config, degree_bits)?; - verify_with_challenges(stark, proof_with_pis, challenges, degree_bits, config) + verify_stark_proof_with_challenges(stark, proof_with_pis, challenges, degree_bits, config) } -pub(crate) fn verify_with_challenges< +pub(crate) fn verify_stark_proof_with_challenges< F: RichField + Extendable, C: GenericConfig, S: Stark, @@ -54,8 +54,6 @@ where proof, public_inputs, } = proof_with_pis; - let local_values = &proof.openings.local_values; - let next_values = &proof.openings.local_values; let StarkOpeningSet { local_values, next_values, diff --git a/system_zero/src/system_zero.rs b/system_zero/src/system_zero.rs index 2eeb4697..c1062e2a 100644 --- a/system_zero/src/system_zero.rs +++ b/system_zero/src/system_zero.rs @@ -117,7 +117,7 @@ mod tests { use starky::prover::prove; use starky::stark::Stark; use starky::stark_testing::test_stark_low_degree; - use starky::verifier::verify; + use starky::verifier::verify_stark_proof; use crate::system_zero::SystemZero; @@ -136,7 +136,7 @@ mod tests { let trace = system.generate_trace(); let proof = prove::(system, &config, trace, public_inputs, &mut timing)?; - verify(system, proof, &config) + verify_stark_proof(system, proof, &config) } #[test]