From 4a2681034e4da1c5850ad3f3d4d52c870726ffee Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 27 Jan 2022 12:58:56 +0100 Subject: [PATCH] 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], + } + } }