From 92ea4b65d1829f90f07e7c705821c0397daee06f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 31 Jan 2022 18:00:07 +0100 Subject: [PATCH] Constraint check working --- field/src/field_types.rs | 1 + plonky2/src/fri/verifier.rs | 5 ++--- plonky2/src/hash/merkle_proofs.rs | 1 + plonky2/src/plonk/verifier.rs | 2 +- starky/src/fibonacci_stark.rs | 16 +++++++++------- starky/src/get_challenges.rs | 16 +++++++++++----- starky/src/proof.rs | 30 ++++++++++++++++++++---------- starky/src/prover.rs | 23 ++++++++++++++++------- starky/src/verifier.rs | 14 +++++++++----- system_zero/src/system_zero.rs | 2 +- 10 files changed, 71 insertions(+), 39 deletions(-) diff --git a/field/src/field_types.rs b/field/src/field_types.rs index 0d7b314f..845d8e83 100644 --- a/field/src/field_types.rs +++ b/field/src/field_types.rs @@ -389,6 +389,7 @@ pub trait Field: /// Representative `g` of the coset used in FRI, so that LDEs in FRI are done over `gH`. fn coset_shift() -> Self { Self::MULTIPLICATIVE_GROUP_GENERATOR + // Self::ONE } /// Equivalent to *self + x * y, but may be cheaper. diff --git a/plonky2/src/fri/verifier.rs b/plonky2/src/fri/verifier.rs index f41ae969..3e70c025 100644 --- a/plonky2/src/fri/verifier.rs +++ b/plonky2/src/fri/verifier.rs @@ -63,8 +63,7 @@ pub fn verify_fri_proof< const D: usize, >( instance: &FriInstanceInfo, - // Openings of the PLONK polynomials. - os: &OpeningSet, + openings: &FriOpenings, challenges: &FriChallenges, initial_merkle_caps: &[MerkleCap], proof: &FriProof, @@ -88,7 +87,7 @@ pub fn verify_fri_proof< ); let precomputed_reduced_evals = - PrecomputedReducedOpenings::from_os_and_alpha(&os.to_fri_openings(), challenges.fri_alpha); + PrecomputedReducedOpenings::from_os_and_alpha(&openings, challenges.fri_alpha); for (&x_index, round_proof) in challenges .fri_query_indices .iter() diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index c2f3655d..feb39791 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -31,6 +31,7 @@ pub(crate) fn verify_merkle_proof>( merkle_cap: &MerkleCap, proof: &MerkleProof, ) -> Result<()> { + dbg!(leaf_index); let mut index = leaf_index; let mut current_digest = H::hash(&leaf_data, false); for &sibling_digest in proof.siblings.iter() { diff --git a/plonky2/src/plonk/verifier.rs b/plonky2/src/plonk/verifier.rs index f0c976fa..46d41bfe 100644 --- a/plonky2/src/plonk/verifier.rs +++ b/plonky2/src/plonk/verifier.rs @@ -91,7 +91,7 @@ pub(crate) fn verify_with_challenges< verify_fri_proof::( &common_data.get_fri_instance(challenges.plonk_zeta), - &proof.openings, + &proof.openings.to_fri_openings(), &challenges.fri_challenges, merkle_caps, &proof.opening_proof, diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index ea834e99..ffaa14a7 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -12,6 +12,7 @@ use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; /// Toy STARK system used for testing. /// Computes a Fibonacci sequence with state `[x0, x1]` using the state transition /// `x0 <- x1, x1 <- x0 + x1`. +#[derive(Copy, Clone)] struct FibonacciStark, const D: usize> { num_rows: usize, _phantom: PhantomData, @@ -58,10 +59,10 @@ impl, const D: usize> Stark for FibonacciStar FE: FieldExtension, P: PackedField, { - // Check public inputs. - yield_constr.one_first_row(vars.local_values[0] - vars.public_inputs[Self::PI_INDEX_X0]); - yield_constr.one_first_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_X1]); - yield_constr.one_last_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_RES]); + // // Check public inputs. + // yield_constr.one_first_row(vars.local_values[0] - vars.public_inputs[Self::PI_INDEX_X0]); + // yield_constr.one_first_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_X1]); + // yield_constr.one_last_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_RES]); // x0 <- x1 yield_constr.one(vars.next_values[0] - vars.local_values[1]); @@ -89,6 +90,7 @@ mod tests { use crate::config::StarkConfig; use crate::fibonacci_stark::FibonacciStark; use crate::prover::prove; + use crate::verifier::verify; fn fibonacci(n: usize, x0: usize, x1: usize) -> usize { (0..n).fold((0, 1), |x, _| (x.1, x.0 + x.1)).1 @@ -110,14 +112,14 @@ mod tests { ]; let stark = S::new(num_rows); let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - prove::( + let proof = prove::( stark, - config, + &config, trace, public_inputs, &mut TimingTree::default(), )?; - Ok(()) + verify(stark, proof, &config, num_rows) } } diff --git a/starky/src/get_challenges.rs b/starky/src/get_challenges.rs index 927eef6c..d6a9b562 100644 --- a/starky/src/get_challenges.rs +++ b/starky/src/get_challenges.rs @@ -6,6 +6,7 @@ use plonky2::hash::hash_types::RichField; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::challenger::Challenger; use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::plonk::proof::FriChallenges; use crate::config::StarkConfig; use crate::proof::{StarkOpeningSet, StarkProof, StarkProofChallenges, StarkProofWithPublicInputs}; @@ -67,10 +68,12 @@ fn get_challenges, C: GenericConfig, cons Ok(StarkProofChallenges { stark_alphas, stark_zeta, - fri_alpha, - fri_betas, - fri_pow_response, - fri_query_indices, + fri_challenges: FriChallenges { + fri_alpha, + fri_betas, + fri_pow_response, + fri_query_indices, + }, }) } @@ -82,7 +85,10 @@ impl, C: GenericConfig, const D: usize> config: &StarkConfig, degree_bits: usize, ) -> anyhow::Result> { - Ok(self.get_challenges(config, degree_bits)?.fri_query_indices) + Ok(self + .get_challenges(config, degree_bits)? + .fri_challenges + .fri_query_indices) } /// Computes all Fiat-Shamir challenges used in the Plonk proof. diff --git a/starky/src/proof.rs b/starky/src/proof.rs index fe4ac43d..2d9597d0 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -2,10 +2,12 @@ use plonky2::field::extension_field::Extendable; use plonky2::field::field_types::Field; use plonky2::fri::oracle::PolynomialBatch; use plonky2::fri::proof::{CompressedFriProof, FriProof}; +use plonky2::fri::structure::{FriOpeningBatch, FriOpenings}; use plonky2::hash::hash_types::RichField; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::challenger::Challenger; use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::plonk::proof::FriChallenges; use rayon::prelude::*; pub struct StarkProof, C: GenericConfig, const D: usize> { @@ -58,16 +60,7 @@ pub(crate) struct StarkProofChallenges, const D: us // Point at which the PLONK polynomials are opened. pub stark_zeta: F::Extension, - // Scaling factor to combine polynomials. - pub fri_alpha: F::Extension, - - // Betas used in the FRI commit phase reductions. - pub fri_betas: Vec, - - pub fri_pow_response: F, - - // Indices at which the oracle is queried in FRI. - pub fri_query_indices: Vec, + pub fri_challenges: FriChallenges, } /// Purported values of each polynomial at the challenge point. @@ -111,4 +104,21 @@ impl, const D: usize> StarkOpeningSet { challenger.observe_extension_elements(v); } } + + pub(crate) fn to_fri_openings(&self) -> FriOpenings { + let zeta_batch = FriOpeningBatch { + values: [ + self.local_values.as_slice(), + self.quotient_polys.as_slice(), + self.permutation_zs.as_slice(), + ] + .concat(), + }; + let zeta_right_batch = FriOpeningBatch { + values: self.next_values.to_vec(), + }; + FriOpenings { + batches: vec![zeta_batch, zeta_right_batch], + } + } } diff --git a/starky/src/prover.rs b/starky/src/prover.rs index a3f2cb2d..6a22e671 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -23,7 +23,7 @@ use crate::vars::StarkEvaluationVars; // TODO: Deal with public inputs. pub fn prove( stark: S, - config: StarkConfig, + config: &StarkConfig, trace: Vec<[F; S::COLUMNS]>, public_inputs: [F; S::PUBLIC_INPUTS], timing: &mut TimingTree, @@ -101,7 +101,7 @@ where None, ) ); - let quotient_polys_cap = quotient_commitment.merkle_tree.cap; + let quotient_polys_cap = quotient_commitment.merkle_tree.cap.clone(); challenger.observe_cap("ient_polys_cap); let zeta = challenger.get_extension_challenge::(); @@ -164,7 +164,6 @@ where [(); S::PUBLIC_INPUTS]:, { let degree = 1 << degree_bits; - let points = F::two_adic_subgroup(degree_bits + rate_bits); // Evaluation of the first Lagrange polynomial on the LDE domain. let lagrange_first = { @@ -179,12 +178,18 @@ where evals.lde(rate_bits) }; - let z_h_on_coset = ZeroPolyOnCoset::new(degree_bits, rate_bits); + let z_h_on_coset = ZeroPolyOnCoset::::new(degree_bits, rate_bits); // Retrieve the LDE values at index `i`. let get_at_index = |comm: &PolynomialBatch, i: usize| -> [F; S::COLUMNS] { comm.get_lde_values(i).try_into().unwrap() }; + let last = F::primitive_root_of_unity(degree_bits).inverse(); + let coset = F::cyclic_subgroup_coset_known_order( + F::primitive_root_of_unity(degree_bits + rate_bits), + F::coset_shift(), + degree << rate_bits, + ); let quotient_values = (0..degree << rate_bits) .into_par_iter() @@ -197,15 +202,19 @@ where ); let vars = StarkEvaluationVars:: { local_values: &get_at_index(trace_commitment, i), - next_values: &get_at_index(trace_commitment, (i + 1) % (degree << rate_bits)), + next_values: &get_at_index( + trace_commitment, + (i + (1 << rate_bits)) % (degree << rate_bits), + ), public_inputs: &public_inputs, }; stark.eval_packed_base(vars, &mut consumer); - // TODO: Fix this once we a genuine `PackedField`. + // TODO: Fix this once we use a genuine `PackedField`. let mut constraints_evals = consumer.accumulators(); let denominator_inv = z_h_on_coset.eval_inverse(i); + let z_last = coset[i] - last; for eval in &mut constraints_evals { - *eval *= denominator_inv; + *eval *= denominator_inv * z_last; } constraints_evals }) diff --git a/starky/src/verifier.rs b/starky/src/verifier.rs index 46dc948f..63e063af 100644 --- a/starky/src/verifier.rs +++ b/starky/src/verifier.rs @@ -92,16 +92,19 @@ where let quotient_polys_zeta = &proof.openings.quotient_polys; let zeta_pow_deg = challenges.stark_zeta.exp_power_of_2(degree_bits); let z_h_zeta = zeta_pow_deg - F::Extension::ONE; + let g = F::primitive_root_of_unity(degree_bits + config.fri_config.rate_bits); + let last = F::primitive_root_of_unity(degree_bits).inverse(); + let z_last = challenges.stark_zeta - last.into(); // `quotient_polys_zeta` holds `num_challenges * quotient_degree_factor` evaluations. // Each chunk of `quotient_degree_factor` holds the evaluations of `t_0(zeta),...,t_{quotient_degree_factor-1}(zeta)` // where the "real" quotient polynomial is `t(X) = t_0(X) + t_1(X)*X^n + t_2(X)*X^{2n} + ...`. // So to reconstruct `t(zeta)` we can compute `reduce_with_powers(chunk, zeta^n)` for each // `quotient_degree_factor`-sized chunk of the original evaluations. for (i, chunk) in quotient_polys_zeta - .chunks(config.fri_config.rate_bits) + .chunks(1 << config.fri_config.rate_bits) .enumerate() { - ensure!(acc[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg)); + ensure!(acc[i] == z_h_zeta * reduce_with_powers(chunk, zeta_pow_deg) / z_last); } let merkle_caps = &[proof.trace_cap, proof.quotient_polys_cap]; @@ -112,8 +115,8 @@ where F::primitive_root_of_unity(degree_bits).into(), config.fri_config.rate_bits, ), - &proof.openings, - &challenges, + &proof.openings.to_fri_openings(), + &challenges.fri_challenges, merkle_caps, &proof.opening_proof, &config.fri_params(degree_bits), @@ -145,5 +148,6 @@ fn recover_degree, C: GenericConfig, cons .1 .siblings .len() - + config.fri_config.cap_height) + + config.fri_config.cap_height + - config.fri_config.rate_bits) } diff --git a/system_zero/src/system_zero.rs b/system_zero/src/system_zero.rs index 49e25e6c..38326b68 100644 --- a/system_zero/src/system_zero.rs +++ b/system_zero/src/system_zero.rs @@ -108,7 +108,7 @@ mod tests { let config = StarkConfig::standard_fast_config(); let mut timing = TimingTree::new("prove", Level::Debug); let trace = system.generate_trace(); - prove::(system, config, trace, public_inputs, &mut timing)?; + prove::(system, &config, trace, public_inputs, &mut timing)?; Ok(()) }