From d54cc9a7c8587a085acd605c7a297e14207e998e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 26 Jan 2022 16:08:04 +0100 Subject: [PATCH 1/8] First try --- field/src/lib.rs | 1 + field/src/zero_poly_coset.rs | 47 ++++++++++++++++ plonky2/src/plonk/plonk_common.rs | 46 --------------- plonky2/src/plonk/prover.rs | 3 +- plonky2/src/plonk/vanishing_poly.rs | 3 +- starky/src/constraint_consumer.rs | 19 +++++++ starky/src/prover.rs | 87 ++++++++++++++++++++++++++++- starky/src/stark.rs | 2 +- util/src/lib.rs | 1 + 9 files changed, 157 insertions(+), 52 deletions(-) create mode 100644 field/src/zero_poly_coset.rs diff --git a/field/src/lib.rs b/field/src/lib.rs index f190bcbc..2c89aab3 100644 --- a/field/src/lib.rs +++ b/field/src/lib.rs @@ -24,6 +24,7 @@ pub mod packed_field; pub mod polynomial; pub mod secp256k1_base; pub mod secp256k1_scalar; +pub mod zero_poly_coset; #[cfg(test)] mod field_testing; diff --git a/field/src/zero_poly_coset.rs b/field/src/zero_poly_coset.rs new file mode 100644 index 00000000..0b7452f5 --- /dev/null +++ b/field/src/zero_poly_coset.rs @@ -0,0 +1,47 @@ +use crate::field_types::Field; + +/// Precomputations of the evaluation of `Z_H(X) = X^n - 1` on a coset `gK` with `H <= K`. +pub struct ZeroPolyOnCoset { + /// `n = |H|`. + n: F, + /// `rate = |K|/|H|`. + rate: usize, + /// Holds `g^n * (w^n)^i - 1 = g^n * v^i - 1` for `i in 0..rate`, with `w` a generator of `K` and `v` a + /// `rate`-primitive root of unity. + evals: Vec, + /// Holds the multiplicative inverses of `evals`. + inverses: Vec, +} + +impl ZeroPolyOnCoset { + pub fn new(n_log: usize, rate_bits: usize) -> Self { + let g_pow_n = F::coset_shift().exp_power_of_2(n_log); + let evals = F::two_adic_subgroup(rate_bits) + .into_iter() + .map(|x| g_pow_n * x - F::ONE) + .collect::>(); + let inverses = F::batch_multiplicative_inverse(&evals); + Self { + n: F::from_canonical_usize(1 << n_log), + rate: 1 << rate_bits, + evals, + inverses, + } + } + + /// Returns `Z_H(g * w^i)`. + pub fn eval(&self, i: usize) -> F { + self.evals[i % self.rate] + } + + /// Returns `1 / Z_H(g * w^i)`. + pub fn eval_inverse(&self, i: usize) -> F { + self.inverses[i % self.rate] + } + + /// Returns `L_1(x) = Z_H(x)/(n * (x - 1))` with `x = w^i`. + pub fn eval_l1(&self, i: usize, x: F) -> F { + // Could also precompute the inverses using Montgomery. + self.eval(i) * (self.n * (x - F::ONE)).inverse() + } +} diff --git a/plonky2/src/plonk/plonk_common.rs b/plonky2/src/plonk/plonk_common.rs index 92c4168d..74495198 100644 --- a/plonky2/src/plonk/plonk_common.rs +++ b/plonky2/src/plonk/plonk_common.rs @@ -63,52 +63,6 @@ pub(crate) fn eval_zero_poly(n: usize, x: F) -> F { x.exp_u64(n as u64) - F::ONE } -/// Precomputations of the evaluation of `Z_H(X) = X^n - 1` on a coset `gK` with `H <= K`. -pub(crate) struct ZeroPolyOnCoset { - /// `n = |H|`. - n: F, - /// `rate = |K|/|H|`. - rate: usize, - /// Holds `g^n * (w^n)^i - 1 = g^n * v^i - 1` for `i in 0..rate`, with `w` a generator of `K` and `v` a - /// `rate`-primitive root of unity. - evals: Vec, - /// Holds the multiplicative inverses of `evals`. - inverses: Vec, -} - -impl ZeroPolyOnCoset { - pub fn new(n_log: usize, rate_bits: usize) -> Self { - let g_pow_n = F::coset_shift().exp_power_of_2(n_log); - let evals = F::two_adic_subgroup(rate_bits) - .into_iter() - .map(|x| g_pow_n * x - F::ONE) - .collect::>(); - let inverses = F::batch_multiplicative_inverse(&evals); - Self { - n: F::from_canonical_usize(1 << n_log), - rate: 1 << rate_bits, - evals, - inverses, - } - } - - /// Returns `Z_H(g * w^i)`. - pub fn eval(&self, i: usize) -> F { - self.evals[i % self.rate] - } - - /// Returns `1 / Z_H(g * w^i)`. - pub fn eval_inverse(&self, i: usize) -> F { - self.inverses[i % self.rate] - } - - /// Returns `L_1(x) = Z_H(x)/(n * (x - 1))` with `x = w^i`. - pub fn eval_l1(&self, i: usize, x: F) -> F { - // Could also precompute the inverses using Montgomery. - self.eval(i) * (self.n * (x - F::ONE)).inverse() - } -} - /// Evaluate the Lagrange basis `L_1` with `L_1(1) = 1`, and `L_1(x) = 0` for other members of an /// order `n` multiplicative subgroup. pub(crate) fn eval_l_1(n: usize, x: F) -> F { diff --git a/plonky2/src/plonk/prover.rs b/plonky2/src/plonk/prover.rs index 2a11e4c0..09caf81e 100644 --- a/plonky2/src/plonk/prover.rs +++ b/plonky2/src/plonk/prover.rs @@ -4,6 +4,7 @@ use anyhow::ensure; use anyhow::Result; use plonky2_field::extension_field::Extendable; use plonky2_field::polynomial::{PolynomialCoeffs, PolynomialValues}; +use plonky2_field::zero_poly_coset::ZeroPolyOnCoset; use plonky2_util::log2_ceil; use rayon::prelude::*; @@ -15,7 +16,7 @@ use crate::iop::generator::generate_partial_witness; use crate::iop::witness::{MatrixWitness, PartialWitness, Witness}; use crate::plonk::circuit_data::{CommonCircuitData, ProverOnlyCircuitData}; use crate::plonk::config::{GenericConfig, Hasher}; -use crate::plonk::plonk_common::{PlonkOracle, ZeroPolyOnCoset}; +use crate::plonk::plonk_common::PlonkOracle; use crate::plonk::proof::OpeningSet; use crate::plonk::proof::{Proof, ProofWithPublicInputs}; use crate::plonk::vanishing_poly::eval_vanishing_poly_base_batch; diff --git a/plonky2/src/plonk/vanishing_poly.rs b/plonky2/src/plonk/vanishing_poly.rs index 74e0fab3..70de5833 100644 --- a/plonky2/src/plonk/vanishing_poly.rs +++ b/plonky2/src/plonk/vanishing_poly.rs @@ -1,6 +1,7 @@ use plonky2_field::batch_util::batch_add_inplace; use plonky2_field::extension_field::{Extendable, FieldExtension}; use plonky2_field::field_types::Field; +use plonky2_field::zero_poly_coset::ZeroPolyOnCoset; use crate::gates::gate::PrefixedGate; use crate::hash::hash_types::RichField; @@ -10,7 +11,7 @@ use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::config::GenericConfig; use crate::plonk::plonk_common; -use crate::plonk::plonk_common::{eval_l_1_recursively, ZeroPolyOnCoset}; +use crate::plonk::plonk_common::eval_l_1_recursively; use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBaseBatch}; use crate::util::partial_products::{check_partial_products, check_partial_products_recursively}; use crate::util::reducing::ReducingFactorTarget; diff --git a/starky/src/constraint_consumer.rs b/starky/src/constraint_consumer.rs index 09b5397f..20f29192 100644 --- a/starky/src/constraint_consumer.rs +++ b/starky/src/constraint_consumer.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; use plonky2::field::extension_field::Extendable; +use plonky2::field::field_types::Field; use plonky2::field::packed_field::PackedField; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; @@ -24,6 +25,24 @@ pub struct ConstraintConsumer { } impl ConstraintConsumer

{ + pub fn new( + alpha: P::Scalar, + lagrange_basis_first: P::Scalar, + lagrange_basis_last: P::Scalar, + ) -> Self { + Self { + alpha, + constraint_acc: P::ZEROS, + lagrange_basis_first, + lagrange_basis_last, + } + } + + // TODO: Do this correctly. + pub fn accumulator(&self) -> P::Scalar { + self.constraint_acc.as_slice()[0] + } + /// Add one constraint. pub fn one(&mut self, constraint: P) { self.constraint_acc *= self.alpha; diff --git a/starky/src/prover.rs b/starky/src/prover.rs index bda478e5..ad86143b 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -1,10 +1,12 @@ use itertools::Itertools; use plonky2::field::extension_field::Extendable; -use plonky2::field::polynomial::PolynomialValues; +use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; +use plonky2::field::zero_poly_coset::ZeroPolyOnCoset; use plonky2::fri::oracle::PolynomialBatch; use plonky2::fri::prover::fri_proof; use plonky2::hash::hash_types::RichField; use plonky2::iop::challenger::Challenger; +use plonky2::plonk::circuit_data::CommonCircuitData; use plonky2::plonk::config::GenericConfig; use plonky2::timed; use plonky2::util::timing::TimingTree; @@ -13,8 +15,10 @@ use plonky2_util::log2_strict; use rayon::prelude::*; use crate::config::StarkConfig; +use crate::constraint_consumer::ConstraintConsumer; use crate::proof::StarkProof; use crate::stark::Stark; +use crate::vars::StarkEvaluationVars; pub fn prove( stark: S, @@ -27,6 +31,7 @@ where C: GenericConfig, S: Stark, [(); S::COLUMNS]:, + [(); S::PUBLIC_INPUTS]:, { let degree_bits = log2_strict(trace.len()); @@ -57,13 +62,23 @@ where ) ); - let trace_cap = trace_commitment.merkle_tree.cap; + let trace_cap = trace_commitment.merkle_tree.cap.clone(); + let mut challenger = Challenger::new(); + challenger.observe_cap(&trace_cap); + + let alphas = challenger.get_n_challenges(config.num_challenges); + let quotient = compute_quotient_polys::( + &stark, + &trace_commitment, + &alphas, + degree_bits, + rate_bits, + ); let openings = todo!(); let initial_merkle_trees = todo!(); let lde_polynomial_coeffs = todo!(); let lde_polynomial_values = todo!(); - let mut challenger = Challenger::new(); let fri_params = config.fri_params(degree_bits); let opening_proof = fri_proof::( @@ -81,3 +96,69 @@ where opening_proof, } } + +fn compute_quotient_polys( + stark: &S, + trace_commitment: &PolynomialBatch, + alphas: &[F], + degree_bits: usize, + rate_bits: usize, +) -> Vec> +where + F: RichField + Extendable, + C: GenericConfig, + S: Stark, + [(); S::COLUMNS]:, + [(); S::PUBLIC_INPUTS]:, +{ + let degree = 1 << degree_bits; + let points = F::two_adic_subgroup(degree_bits + rate_bits); + + let lagrange_first = { + let mut evals = PolynomialValues::new(vec![F::ZERO; degree]); + evals.values[0] = F::ONE; + evals.lde(rate_bits) + }; + let lagrange_last = { + let mut evals = PolynomialValues::new(vec![F::ZERO; degree]); + evals.values[degree - 1] = F::ONE; + evals.lde(rate_bits) + }; + + let z_h_on_coset = ZeroPolyOnCoset::new(degree_bits, rate_bits); + + alphas + .iter() + .map(|&alpha| { + let quotient_evals = PolynomialValues::new( + (0..degree << rate_bits) + .into_par_iter() + .map(|i| { + let mut consumer = ConstraintConsumer::::new( + alpha, + lagrange_first.values[i], + lagrange_last.values[i], + ); + let vars = + StarkEvaluationVars:: { + local_values: trace_commitment + .get_lde_values(i) + .try_into() + .unwrap(), + next_values: trace_commitment + .get_lde_values((i + 1) % (degree << rate_bits)) + .try_into() + .unwrap(), + public_inputs: &[F::ZERO; S::PUBLIC_INPUTS], + }; + stark.eval_packed_base(vars, &mut consumer); + let constraints_eval = consumer.accumulator(); + let denominator_inv = z_h_on_coset.eval_inverse(i); + constraints_eval * denominator_inv + }) + .collect(), + ); + quotient_evals.coset_ifft(F::coset_shift()) + }) + .collect() +} diff --git a/starky/src/stark.rs b/starky/src/stark.rs index 8d6abb69..6be5be2c 100644 --- a/starky/src/stark.rs +++ b/starky/src/stark.rs @@ -8,7 +8,7 @@ use crate::vars::StarkEvaluationTargets; use crate::vars::StarkEvaluationVars; /// Represents a STARK system. -pub trait Stark, const D: usize> { +pub trait Stark, const D: usize>: Sync { /// The total number of columns in the trace. const COLUMNS: usize; /// The number of public inputs. diff --git a/util/src/lib.rs b/util/src/lib.rs index f760cfba..61677ff0 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -11,6 +11,7 @@ use std::mem::size_of; use std::ptr::{swap, swap_nonoverlapping}; mod transpose_util; + use crate::transpose_util::transpose_in_place_square; pub fn bits_u64(n: u64) -> usize { From 3e0cb36063add2124e7f969628f0116d41a91d05 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 27 Jan 2022 07:56:22 +0100 Subject: [PATCH 2/8] Added test stark --- starky/src/constraint_consumer.rs | 10 +--- starky/src/julia_stark.rs | 91 +++++++++++++++++++++++++++++++ starky/src/lib.rs | 3 + 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 starky/src/julia_stark.rs diff --git a/starky/src/constraint_consumer.rs b/starky/src/constraint_consumer.rs index 20f29192..c7a8bfea 100644 --- a/starky/src/constraint_consumer.rs +++ b/starky/src/constraint_consumer.rs @@ -17,19 +17,15 @@ pub struct ConstraintConsumer { /// The evaluation of the Lagrange basis polynomial which is nonzero at the point associated /// with the first trace row, and zero at other points in the subgroup. - lagrange_basis_first: P::Scalar, + lagrange_basis_first: P, /// The evaluation of the Lagrange basis polynomial which is nonzero at the point associated /// with the last trace row, and zero at other points in the subgroup. - lagrange_basis_last: P::Scalar, + lagrange_basis_last: P, } impl ConstraintConsumer

{ - pub fn new( - alpha: P::Scalar, - lagrange_basis_first: P::Scalar, - lagrange_basis_last: P::Scalar, - ) -> Self { + pub fn new(alpha: P::Scalar, lagrange_basis_first: P, lagrange_basis_last: P) -> Self { Self { alpha, constraint_acc: P::ZEROS, diff --git a/starky/src/julia_stark.rs b/starky/src/julia_stark.rs new file mode 100644 index 00000000..e8bca9fe --- /dev/null +++ b/starky/src/julia_stark.rs @@ -0,0 +1,91 @@ +use std::marker::PhantomData; + +use plonky2::field::extension_field::{Extendable, FieldExtension}; +use plonky2::field::packed_field::PackedField; +use plonky2::hash::hash_types::RichField; +use plonky2::plonk::circuit_builder::CircuitBuilder; + +use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use crate::stark::Stark; +use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; + +pub struct JuliaStark, const D: usize> { + c: F, + _phantom: PhantomData, +} + +impl, const D: usize> JuliaStark { + const NUM_COLUMNS: usize = 1; + const NUM_ROWS: usize = 1 << 10; + + fn new(c: F) -> Self { + Self { + c, + _phantom: PhantomData, + } + } + + fn generate_trace(&self) -> Vec<[F; Self::NUM_COLUMNS]> { + (0..Self::NUM_ROWS) + .scan([F::ZERO; Self::NUM_COLUMNS], |acc, _| { + let tmp = *acc; + acc[0] = acc[0] * acc[0] + self.c; + Some(tmp) + }) + .collect() + } +} + +impl, const D: usize> Stark for JuliaStark { + const COLUMNS: usize = Self::NUM_COLUMNS; + const PUBLIC_INPUTS: usize = 0; + + fn eval_packed_generic( + &self, + vars: StarkEvaluationVars, + yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + yield_constr.one( + vars.next_values[0] + - vars.local_values[0] * vars.local_values[0] + - FE::from_basefield(self.c), + ); + } + + fn eval_ext_recursively( + &self, + builder: &mut CircuitBuilder, + vars: StarkEvaluationTargets, + yield_constr: &mut RecursiveConstraintConsumer, + ) { + todo!() + } +} + +#[cfg(test)] +mod tests { + use plonky2::field::field_types::Field; + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::util::timing::TimingTree; + + use crate::config::StarkConfig; + use crate::julia_stark::JuliaStark; + use crate::prover::prove; + + #[test] + fn test_julia_stark() { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + type S = JuliaStark; + + let config = StarkConfig::standard_fast_config(); + let stark = S::new(F::NEG_ONE); + let trace = stark.generate_trace(); + prove::(stark, config, trace, &mut TimingTree::default()); + } +} diff --git a/starky/src/lib.rs b/starky/src/lib.rs index be28a01e..72407511 100644 --- a/starky/src/lib.rs +++ b/starky/src/lib.rs @@ -12,3 +12,6 @@ pub mod proof; pub mod prover; pub mod stark; pub mod vars; + +#[cfg(test)] +pub mod julia_stark; From 4a2681034e4da1c5850ad3f3d4d52c870726ffee Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 27 Jan 2022 12:58:56 +0100 Subject: [PATCH 3/8] Working prover --- plonky2/src/fri/oracle.rs | 2 +- .../{julia_stark.rs => fibonacci_stark.rs} | 43 +++++------ starky/src/lib.rs | 2 +- starky/src/proof.rs | 24 +++++++ starky/src/prover.rs | 71 ++++++++++++++----- starky/src/stark.rs | 23 ++++++ 6 files changed, 127 insertions(+), 38 deletions(-) rename starky/src/{julia_stark.rs => fibonacci_stark.rs} (70%) diff --git a/plonky2/src/fri/oracle.rs b/plonky2/src/fri/oracle.rs index c016f0ee..0922962a 100644 --- a/plonky2/src/fri/oracle.rs +++ b/plonky2/src/fri/oracle.rs @@ -127,7 +127,7 @@ impl, C: GenericConfig, const D: usize> } /// Produces a batch opening proof. - pub(crate) fn prove_openings( + pub fn prove_openings( instance: &FriInstanceInfo, oracles: &[&Self], challenger: &mut Challenger, diff --git a/starky/src/julia_stark.rs b/starky/src/fibonacci_stark.rs similarity index 70% rename from starky/src/julia_stark.rs rename to starky/src/fibonacci_stark.rs index e8bca9fe..3d8d4be3 100644 --- a/starky/src/julia_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -9,34 +9,37 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer use crate::stark::Stark; use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; -pub struct JuliaStark, const D: usize> { - c: F, +pub struct FibonacciStark, const D: usize> { + x0: F, + x1: F, _phantom: PhantomData, } -impl, const D: usize> JuliaStark { - const NUM_COLUMNS: usize = 1; - const NUM_ROWS: usize = 1 << 10; +impl, const D: usize> FibonacciStark { + const NUM_COLUMNS: usize = 2; + const NUM_ROWS: usize = 1 << 5; - fn new(c: F) -> Self { + fn new(x0: F, x1: F) -> Self { Self { - c, + x0, + x1, _phantom: PhantomData, } } fn generate_trace(&self) -> Vec<[F; Self::NUM_COLUMNS]> { (0..Self::NUM_ROWS) - .scan([F::ZERO; Self::NUM_COLUMNS], |acc, _| { + .scan([self.x0, self.x1], |acc, _| { let tmp = *acc; - acc[0] = acc[0] * acc[0] + self.c; + acc[0] = tmp[1]; + acc[1] = tmp[0] + tmp[1]; Some(tmp) }) .collect() } } -impl, const D: usize> Stark for JuliaStark { +impl, const D: usize> Stark for FibonacciStark { const COLUMNS: usize = Self::NUM_COLUMNS; const PUBLIC_INPUTS: usize = 0; @@ -48,11 +51,8 @@ impl, const D: usize> Stark for JuliaStark, P: PackedField, { - yield_constr.one( - vars.next_values[0] - - vars.local_values[0] * vars.local_values[0] - - FE::from_basefield(self.c), - ); + yield_constr.one(vars.next_values[0] - vars.local_values[1]); + yield_constr.one(vars.next_values[1] - vars.local_values[0] - vars.local_values[1]); } fn eval_ext_recursively( @@ -67,25 +67,28 @@ impl, const D: usize> Stark for JuliaStark Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; type F = >::F; - type S = JuliaStark; + type S = FibonacciStark; let config = StarkConfig::standard_fast_config(); - let stark = S::new(F::NEG_ONE); + let stark = S::new(F::ZERO, F::ONE); let trace = stark.generate_trace(); - prove::(stark, config, trace, &mut TimingTree::default()); + prove::(stark, config, trace, &mut TimingTree::default())?; + + Ok(()) } } diff --git a/starky/src/lib.rs b/starky/src/lib.rs index 72407511..541950ab 100644 --- a/starky/src/lib.rs +++ b/starky/src/lib.rs @@ -14,4 +14,4 @@ pub mod stark; pub mod vars; #[cfg(test)] -pub mod julia_stark; +pub mod fibonacci_stark; diff --git a/starky/src/proof.rs b/starky/src/proof.rs index 1cdbbd3c..22ebf5e2 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -1,8 +1,10 @@ use plonky2::field::extension_field::Extendable; +use plonky2::fri::oracle::PolynomialBatch; use plonky2::fri::proof::{CompressedFriProof, FriProof}; use plonky2::hash::hash_types::RichField; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::plonk::config::GenericConfig; +use rayon::prelude::*; pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. @@ -33,3 +35,25 @@ pub struct StarkOpeningSet, const D: usize> { pub permutation_zs: Vec, pub quotient_polys: Vec, } + +impl, const D: usize> StarkOpeningSet { + pub fn new>( + zeta: F::Extension, + g: F::Extension, + trace_commitment: &PolynomialBatch, + quotient_commitment: &PolynomialBatch, + ) -> Self { + let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { + c.polynomials + .par_iter() + .map(|p| p.to_extension().eval(z)) + .collect::>() + }; + Self { + local_values: eval_commitment(zeta, trace_commitment), + next_values: eval_commitment(zeta * g, trace_commitment), + permutation_zs: vec![], + quotient_polys: eval_commitment(zeta, quotient_commitment), + } + } +} diff --git a/starky/src/prover.rs b/starky/src/prover.rs index ad86143b..fac876aa 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -1,5 +1,7 @@ +use anyhow::{ensure, Result}; use itertools::Itertools; use plonky2::field::extension_field::Extendable; +use plonky2::field::field_types::Field; use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; use plonky2::field::zero_poly_coset::ZeroPolyOnCoset; use plonky2::fri::oracle::PolynomialBatch; @@ -16,7 +18,7 @@ use rayon::prelude::*; use crate::config::StarkConfig; use crate::constraint_consumer::ConstraintConsumer; -use crate::proof::StarkProof; +use crate::proof::{StarkOpeningSet, StarkProof}; use crate::stark::Stark; use crate::vars::StarkEvaluationVars; @@ -25,7 +27,7 @@ pub fn prove( config: StarkConfig, trace: Vec<[F; S::COLUMNS]>, timing: &mut TimingTree, -) -> StarkProof +) -> Result> where F: RichField + Extendable, C: GenericConfig, @@ -33,7 +35,8 @@ where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, { - let degree_bits = log2_strict(trace.len()); + let degree = trace.len(); + let degree_bits = log2_strict(degree); let trace_vecs = trace.into_iter().map(|row| row.to_vec()).collect_vec(); let trace_col_major: Vec> = transpose(&trace_vecs); @@ -67,34 +70,70 @@ where challenger.observe_cap(&trace_cap); let alphas = challenger.get_n_challenges(config.num_challenges); - let quotient = compute_quotient_polys::( + let quotient_polys = compute_quotient_polys::( &stark, &trace_commitment, &alphas, degree_bits, rate_bits, ); - let openings = todo!(); + let all_quotient_chunks = quotient_polys + .into_par_iter() + .flat_map(|mut quotient_poly| { + quotient_poly.trim(); + quotient_poly + .pad(degree << rate_bits) + .expect("Quotient has failed, the vanishing polynomial is not divisible by `Z_H"); + // Split t into degree-n chunks. + quotient_poly.chunks(degree) + }) + .collect(); + let quotient_commitment = timed!( + timing, + "compute quotient commitment", + PolynomialBatch::from_coeffs( + all_quotient_chunks, + rate_bits, + false, + config.fri_config.cap_height, + timing, + None, + ) + ); + challenger.observe_cap("ient_commitment.merkle_tree.cap); - let initial_merkle_trees = todo!(); - let lde_polynomial_coeffs = todo!(); - let lde_polynomial_values = todo!(); + let zeta = challenger.get_extension_challenge::(); + // 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); + ensure!( + zeta.exp_power_of_2(degree_bits) != F::Extension::ONE, + "Opening point is in the subgroup." + ); + let openings = StarkOpeningSet::new(zeta, g, &trace_commitment, "ient_commitment); + + // TODO: Add permuation checks + let initial_merkle_trees = &[&trace_commitment, "ient_commitment]; let fri_params = config.fri_params(degree_bits); - let opening_proof = fri_proof::( - initial_merkle_trees, - lde_polynomial_coeffs, - lde_polynomial_values, - &mut challenger, - &fri_params, + let opening_proof = timed!( timing, + "compute openings proof", + PolynomialBatch::prove_openings( + &S::fri_instance(zeta, g, rate_bits), + initial_merkle_trees, + &mut challenger, + &fri_params, + timing, + ) ); - StarkProof { + Ok(StarkProof { trace_cap, openings, opening_proof, - } + }) } fn compute_quotient_polys( diff --git a/starky/src/stark.rs b/starky/src/stark.rs index 6be5be2c..3c44f343 100644 --- a/starky/src/stark.rs +++ b/starky/src/stark.rs @@ -1,5 +1,6 @@ use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::field::packed_field::PackedField; +use plonky2::fri::structure::{FriBatchInfo, FriInstanceInfo, FriOracleInfo, FriPolynomialInfo}; use plonky2::hash::hash_types::RichField; use plonky2::plonk::circuit_builder::CircuitBuilder; @@ -59,4 +60,26 @@ pub trait Stark, const D: usize>: Sync { vars: StarkEvaluationTargets, yield_constr: &mut RecursiveConstraintConsumer, ); + + fn fri_instance( + zeta: F::Extension, + g: F::Extension, + rate_bits: usize, + ) -> FriInstanceInfo { + 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..1 << rate_bits); + let zeta_batch = FriBatchInfo { + point: zeta, + polynomials: [trace_info.clone(), quotient_info].concat(), + }; + let zeta_right_batch = FriBatchInfo:: { + point: zeta * g, + polynomials: trace_info, + }; + FriInstanceInfo { + oracles: vec![no_blinding_oracle; 3], + batches: vec![zeta_batch], + } + } } From 1770e83c632214f9d8bd439ecc24b9930a24a17e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 27 Jan 2022 13:02:36 +0100 Subject: [PATCH 4/8] Clippy --- starky/src/constraint_consumer.rs | 1 - starky/src/fibonacci_stark.rs | 1 - starky/src/prover.rs | 2 -- system_zero/src/system_zero.rs | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/starky/src/constraint_consumer.rs b/starky/src/constraint_consumer.rs index c7a8bfea..bc76f03b 100644 --- a/starky/src/constraint_consumer.rs +++ b/starky/src/constraint_consumer.rs @@ -1,7 +1,6 @@ use std::marker::PhantomData; use plonky2::field::extension_field::Extendable; -use plonky2::field::field_types::Field; use plonky2::field::packed_field::PackedField; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 3d8d4be3..e6caa1e6 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -69,7 +69,6 @@ impl, const D: usize> Stark for FibonacciStar mod tests { use anyhow::Result; use plonky2::field::field_types::Field; - use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2::util::timing::TimingTree; diff --git a/starky/src/prover.rs b/starky/src/prover.rs index fac876aa..29d9f2e4 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -5,10 +5,8 @@ use plonky2::field::field_types::Field; use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; use plonky2::field::zero_poly_coset::ZeroPolyOnCoset; use plonky2::fri::oracle::PolynomialBatch; -use plonky2::fri::prover::fri_proof; use plonky2::hash::hash_types::RichField; use plonky2::iop::challenger::Challenger; -use plonky2::plonk::circuit_data::CommonCircuitData; use plonky2::plonk::config::GenericConfig; use plonky2::timed; use plonky2::util::timing::TimingTree; diff --git a/system_zero/src/system_zero.rs b/system_zero/src/system_zero.rs index a16fb699..47950eb2 100644 --- a/system_zero/src/system_zero.rs +++ b/system_zero/src/system_zero.rs @@ -104,6 +104,6 @@ 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, &mut timing); + prove::(system, config, trace, &mut timing).unwrap(); } } From b6cb72b629867209a09535c0c4274032422926e0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 27 Jan 2022 13:27:06 +0100 Subject: [PATCH 5/8] Comments --- starky/src/fibonacci_stark.rs | 5 +++++ starky/src/proof.rs | 2 +- starky/src/prover.rs | 29 ++++++++++++++++++++--------- starky/src/stark.rs | 2 ++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index e6caa1e6..5e41f18e 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -9,6 +9,9 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer use crate::stark::Stark; use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; +/// Toy STARK system used for testing. +/// Computes a Fibonacci sequence with inital values `x0, x1` using the transition +/// `x0 <- x1, x1 <- x0 + x1`. pub struct FibonacciStark, const D: usize> { x0: F, x1: F, @@ -51,7 +54,9 @@ impl, const D: usize> Stark for FibonacciStar FE: FieldExtension, P: PackedField, { + // x0 <- x1 yield_constr.one(vars.next_values[0] - vars.local_values[1]); + // x1 <- x0 + x1 yield_constr.one(vars.next_values[1] - vars.local_values[0] - vars.local_values[1]); } diff --git a/starky/src/proof.rs b/starky/src/proof.rs index 22ebf5e2..4218e71f 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -52,7 +52,7 @@ impl, const D: usize> StarkOpeningSet { Self { local_values: eval_commitment(zeta, trace_commitment), next_values: eval_commitment(zeta * g, trace_commitment), - permutation_zs: vec![], + permutation_zs: vec![/*TODO*/], quotient_polys: eval_commitment(zeta, quotient_commitment), } } diff --git a/starky/src/prover.rs b/starky/src/prover.rs index 29d9f2e4..5af22871 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -20,6 +20,7 @@ use crate::proof::{StarkOpeningSet, StarkProof}; use crate::stark::Stark; use crate::vars::StarkEvaluationVars; +// TODO: Deal with public inputs. pub fn prove( stark: S, config: StarkConfig, @@ -82,7 +83,7 @@ where quotient_poly .pad(degree << rate_bits) .expect("Quotient has failed, the vanishing polynomial is not divisible by `Z_H"); - // Split t into degree-n chunks. + // Split quotient into degree-n chunks. quotient_poly.chunks(degree) }) .collect(); @@ -134,6 +135,10 @@ where }) } +/// Computes the quotient polynomials `(sum alpha^i C_i(x)) / Z_H(x)` for `alpha` in `alphas`, +/// where the `C_i`s are the Stark constraints. +// TODO: This won't work for the Fibonacci example because the constraints wrap around the subgroup. +// The denominator should be the vanishing polynomial of `H` without its last element. fn compute_quotient_polys( stark: &S, trace_commitment: &PolynomialBatch, @@ -151,11 +156,13 @@ where 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 = { let mut evals = PolynomialValues::new(vec![F::ZERO; degree]); evals.values[0] = F::ONE; evals.lde(rate_bits) }; + // Evaluation of the last Lagrange polynomial on the LDE domain. let lagrange_last = { let mut evals = PolynomialValues::new(vec![F::ZERO; degree]); evals.values[degree - 1] = F::ONE; @@ -164,6 +171,11 @@ where 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() + }; + alphas .iter() .map(|&alpha| { @@ -171,6 +183,7 @@ where (0..degree << rate_bits) .into_par_iter() .map(|i| { + // TODO: Set `P` to a genuine `PackedField` here. let mut consumer = ConstraintConsumer::::new( alpha, lagrange_first.values[i], @@ -178,17 +191,15 @@ where ); let vars = StarkEvaluationVars:: { - local_values: trace_commitment - .get_lde_values(i) - .try_into() - .unwrap(), - next_values: trace_commitment - .get_lde_values((i + 1) % (degree << rate_bits)) - .try_into() - .unwrap(), + local_values: &get_at_index(trace_commitment, i), + next_values: &get_at_index( + trace_commitment, + (i + 1) % (degree << rate_bits), + ), public_inputs: &[F::ZERO; S::PUBLIC_INPUTS], }; stark.eval_packed_base(vars, &mut consumer); + // TODO: Fix this once we a genuine `PackedField`. let constraints_eval = consumer.accumulator(); let denominator_inv = z_h_on_coset.eval_inverse(i); constraints_eval * denominator_inv diff --git a/starky/src/stark.rs b/starky/src/stark.rs index 3c44f343..f91d4fdd 100644 --- a/starky/src/stark.rs +++ b/starky/src/stark.rs @@ -61,6 +61,8 @@ pub trait Stark, const D: usize>: Sync { yield_constr: &mut RecursiveConstraintConsumer, ); + /// Computes the FRI instance used to prove this Stark. + // TODO: Permutation polynomials. fn fri_instance( zeta: F::Extension, g: F::Extension, From e78630ae81134c5c0447b7bec65c8f664cdb8979 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 28 Jan 2022 05:02:31 +0100 Subject: [PATCH 6/8] PR feedback --- starky/src/fibonacci_stark.rs | 46 ++++++++++++++++++++++++++-------- starky/src/prover.rs | 5 +++- system_zero/src/system_zero.rs | 10 ++++++-- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 5e41f18e..ad2c8e8e 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -12,26 +12,33 @@ use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; /// Toy STARK system used for testing. /// Computes a Fibonacci sequence with inital values `x0, x1` using the transition /// `x0 <- x1, x1 <- x0 + x1`. -pub struct FibonacciStark, const D: usize> { +struct FibonacciStark, const D: usize> { x0: F, x1: F, + num_rows: usize, _phantom: PhantomData, } impl, const D: usize> FibonacciStark { - const NUM_COLUMNS: usize = 2; - const NUM_ROWS: usize = 1 << 5; + // The first public input is `x0`. + const PI_INDEX_X0: usize = 0; + // The second public input is `x1`. + const PI_INDEX_X1: usize = 1; + // The third public input is the second element of the last row, which should be equal to the + // `(num_rows + 1)`-th Fibonacci number. + const PI_INDEX_RES: usize = 2; - fn new(x0: F, x1: F) -> Self { + fn new(num_rows: usize, x0: F, x1: F) -> Self { Self { x0, x1, + num_rows, _phantom: PhantomData, } } - fn generate_trace(&self) -> Vec<[F; Self::NUM_COLUMNS]> { - (0..Self::NUM_ROWS) + fn generate_trace(&self) -> Vec<[F; Self::COLUMNS]> { + (0..self.num_rows) .scan([self.x0, self.x1], |acc, _| { let tmp = *acc; acc[0] = tmp[1]; @@ -43,8 +50,8 @@ impl, const D: usize> FibonacciStark { } impl, const D: usize> Stark for FibonacciStark { - const COLUMNS: usize = Self::NUM_COLUMNS; - const PUBLIC_INPUTS: usize = 0; + const COLUMNS: usize = 2; + const PUBLIC_INPUTS: usize = 3; fn eval_packed_generic( &self, @@ -54,6 +61,9 @@ impl, const D: usize> Stark for FibonacciStar FE: FieldExtension, P: PackedField, { + 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]); // x1 <- x0 + x1 @@ -81,6 +91,10 @@ mod tests { use crate::fibonacci_stark::FibonacciStark; use crate::prover::prove; + fn fibonacci(n: usize, x0: usize, x1: usize) -> usize { + (0..n).fold((0, 1), |x, _| (x.1, x.0 + x.1)).1 + } + #[test] fn test_fibonacci_stark() -> Result<()> { const D: usize = 2; @@ -89,9 +103,21 @@ mod tests { type S = FibonacciStark; let config = StarkConfig::standard_fast_config(); - let stark = S::new(F::ZERO, F::ONE); + let num_rows = 1 << 5; + let public_inputs = [ + F::ZERO, + F::ONE, + F::from_canonical_usize(fibonacci(num_rows - 1, 0, 1)), + ]; + let stark = S::new(num_rows, public_inputs[0], public_inputs[1]); let trace = stark.generate_trace(); - prove::(stark, config, trace, &mut TimingTree::default())?; + prove::( + stark, + config, + trace, + public_inputs, + &mut TimingTree::default(), + )?; Ok(()) } diff --git a/starky/src/prover.rs b/starky/src/prover.rs index 5af22871..5473db68 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -25,6 +25,7 @@ pub fn prove( stark: S, config: StarkConfig, trace: Vec<[F; S::COLUMNS]>, + public_inputs: [F; S::PUBLIC_INPUTS], timing: &mut TimingTree, ) -> Result> where @@ -72,6 +73,7 @@ where let quotient_polys = compute_quotient_polys::( &stark, &trace_commitment, + public_inputs, &alphas, degree_bits, rate_bits, @@ -142,6 +144,7 @@ where fn compute_quotient_polys( stark: &S, trace_commitment: &PolynomialBatch, + public_inputs: [F; S::PUBLIC_INPUTS], alphas: &[F], degree_bits: usize, rate_bits: usize, @@ -196,7 +199,7 @@ where trace_commitment, (i + 1) % (degree << rate_bits), ), - public_inputs: &[F::ZERO; S::PUBLIC_INPUTS], + public_inputs: &public_inputs, }; stark.eval_packed_base(vars, &mut consumer); // TODO: Fix this once we a genuine `PackedField`. diff --git a/system_zero/src/system_zero.rs b/system_zero/src/system_zero.rs index 47950eb2..49e25e6c 100644 --- a/system_zero/src/system_zero.rs +++ b/system_zero/src/system_zero.rs @@ -83,27 +83,33 @@ impl, const D: usize> Stark for SystemZero Result<()> { type F = GoldilocksField; type C = PoseidonGoldilocksConfig; const D: usize = 2; type S = SystemZero; let system = S::default(); + let public_inputs = [F::ZERO; S::PUBLIC_INPUTS]; let config = StarkConfig::standard_fast_config(); let mut timing = TimingTree::new("prove", Level::Debug); let trace = system.generate_trace(); - prove::(system, config, trace, &mut timing).unwrap(); + prove::(system, config, trace, public_inputs, &mut timing)?; + + Ok(()) } } From c73f32ef2ba2b6428b30e855c8471e4e20739992 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 28 Jan 2022 13:59:43 +0100 Subject: [PATCH 7/8] Remove initial values from Fibonacci STARK state --- starky/src/fibonacci_stark.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index ad2c8e8e..ea834e99 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -10,11 +10,9 @@ use crate::stark::Stark; use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; /// Toy STARK system used for testing. -/// Computes a Fibonacci sequence with inital values `x0, x1` using the transition +/// Computes a Fibonacci sequence with state `[x0, x1]` using the state transition /// `x0 <- x1, x1 <- x0 + x1`. struct FibonacciStark, const D: usize> { - x0: F, - x1: F, num_rows: usize, _phantom: PhantomData, } @@ -25,21 +23,20 @@ impl, const D: usize> FibonacciStark { // The second public input is `x1`. const PI_INDEX_X1: usize = 1; // The third public input is the second element of the last row, which should be equal to the - // `(num_rows + 1)`-th Fibonacci number. + // `num_rows`-th Fibonacci number. const PI_INDEX_RES: usize = 2; - fn new(num_rows: usize, x0: F, x1: F) -> Self { + fn new(num_rows: usize) -> Self { Self { - x0, - x1, num_rows, _phantom: PhantomData, } } - fn generate_trace(&self) -> Vec<[F; Self::COLUMNS]> { + /// Generate the trace using `x0, x1` as inital state values. + fn generate_trace(&self, x0: F, x1: F) -> Vec<[F; Self::COLUMNS]> { (0..self.num_rows) - .scan([self.x0, self.x1], |acc, _| { + .scan([x0, x1], |acc, _| { let tmp = *acc; acc[0] = tmp[1]; acc[1] = tmp[0] + tmp[1]; @@ -61,9 +58,11 @@ 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]); + // x0 <- x1 yield_constr.one(vars.next_values[0] - vars.local_values[1]); // x1 <- x0 + x1 @@ -109,8 +108,8 @@ mod tests { F::ONE, F::from_canonical_usize(fibonacci(num_rows - 1, 0, 1)), ]; - let stark = S::new(num_rows, public_inputs[0], public_inputs[1]); - let trace = stark.generate_trace(); + let stark = S::new(num_rows); + let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); prove::( stark, config, From dff9a4095547f02a17e6019f15f9f275e2d76dae Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 28 Jan 2022 17:06:40 +0100 Subject: [PATCH 8/8] Batch alphas in constraint consumer --- starky/src/constraint_consumer.rs | 27 ++++++++------ starky/src/prover.rs | 61 +++++++++++++++---------------- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/starky/src/constraint_consumer.rs b/starky/src/constraint_consumer.rs index bc76f03b..adb88e41 100644 --- a/starky/src/constraint_consumer.rs +++ b/starky/src/constraint_consumer.rs @@ -8,11 +8,11 @@ use plonky2::iop::target::Target; use plonky2::plonk::circuit_builder::CircuitBuilder; pub struct ConstraintConsumer { - /// A random value used to combine multiple constraints into one. - alpha: P::Scalar, + /// Random values used to combine multiple constraints into one. + alphas: Vec, - /// A running sum of constraints that have been emitted so far, scaled by powers of alpha. - constraint_acc: P, + /// Running sums of constraints that have been emitted so far, scaled by powers of alpha. + constraint_accs: Vec

, /// The evaluation of the Lagrange basis polynomial which is nonzero at the point associated /// with the first trace row, and zero at other points in the subgroup. @@ -24,24 +24,29 @@ pub struct ConstraintConsumer { } impl ConstraintConsumer

{ - pub fn new(alpha: P::Scalar, lagrange_basis_first: P, lagrange_basis_last: P) -> Self { + pub fn new(alphas: Vec, lagrange_basis_first: P, lagrange_basis_last: P) -> Self { Self { - alpha, - constraint_acc: P::ZEROS, + constraint_accs: vec![P::ZEROS; alphas.len()], + alphas, lagrange_basis_first, lagrange_basis_last, } } // TODO: Do this correctly. - pub fn accumulator(&self) -> P::Scalar { - self.constraint_acc.as_slice()[0] + pub fn accumulators(self) -> Vec { + self.constraint_accs + .into_iter() + .map(|acc| acc.as_slice()[0]) + .collect() } /// Add one constraint. pub fn one(&mut self, constraint: P) { - self.constraint_acc *= self.alpha; - self.constraint_acc += constraint; + for (&alpha, acc) in self.alphas.iter().zip(&mut self.constraint_accs) { + *acc *= alpha; + *acc += constraint; + } } /// Add a series of constraints. diff --git a/starky/src/prover.rs b/starky/src/prover.rs index 5473db68..e0652b24 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -74,7 +74,7 @@ where &stark, &trace_commitment, public_inputs, - &alphas, + alphas, degree_bits, rate_bits, ); @@ -145,7 +145,7 @@ fn compute_quotient_polys( stark: &S, trace_commitment: &PolynomialBatch, public_inputs: [F; S::PUBLIC_INPUTS], - alphas: &[F], + alphas: Vec, degree_bits: usize, rate_bits: usize, ) -> Vec> @@ -179,37 +179,34 @@ where comm.get_lde_values(i).try_into().unwrap() }; - alphas - .iter() - .map(|&alpha| { - let quotient_evals = PolynomialValues::new( - (0..degree << rate_bits) - .into_par_iter() - .map(|i| { - // TODO: Set `P` to a genuine `PackedField` here. - let mut consumer = ConstraintConsumer::::new( - alpha, - lagrange_first.values[i], - lagrange_last.values[i], - ); - let vars = - StarkEvaluationVars:: { - local_values: &get_at_index(trace_commitment, i), - next_values: &get_at_index( - trace_commitment, - (i + 1) % (degree << rate_bits), - ), - public_inputs: &public_inputs, - }; - stark.eval_packed_base(vars, &mut consumer); - // TODO: Fix this once we a genuine `PackedField`. - let constraints_eval = consumer.accumulator(); - let denominator_inv = z_h_on_coset.eval_inverse(i); - constraints_eval * denominator_inv - }) - .collect(), + let quotient_values = (0..degree << rate_bits) + .into_par_iter() + .map(|i| { + // TODO: Set `P` to a genuine `PackedField` here. + let mut consumer = ConstraintConsumer::::new( + alphas.clone(), + lagrange_first.values[i], + lagrange_last.values[i], ); - quotient_evals.coset_ifft(F::coset_shift()) + let vars = StarkEvaluationVars:: { + local_values: &get_at_index(trace_commitment, i), + next_values: &get_at_index(trace_commitment, (i + 1) % (degree << rate_bits)), + public_inputs: &public_inputs, + }; + stark.eval_packed_base(vars, &mut consumer); + // TODO: Fix this once we a genuine `PackedField`. + let mut constraints_evals = consumer.accumulators(); + let denominator_inv = z_h_on_coset.eval_inverse(i); + for eval in &mut constraints_evals { + *eval *= denominator_inv; + } + constraints_evals }) + .collect::>(); + + transpose("ient_values) + .into_par_iter() + .map(PolynomialValues::new) + .map(|values| values.coset_ifft(F::coset_shift())) .collect() }