From d54cc9a7c8587a085acd605c7a297e14207e998e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 26 Jan 2022 16:08:04 +0100 Subject: [PATCH] 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 {