Working prover

This commit is contained in:
wborgeaud 2022-01-27 12:58:56 +01:00
parent 3e0cb36063
commit 4a2681034e
6 changed files with 127 additions and 38 deletions

View File

@ -127,7 +127,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
}
/// Produces a batch opening proof.
pub(crate) fn prove_openings(
pub fn prove_openings(
instance: &FriInstanceInfo<F, D>,
oracles: &[&Self],
challenger: &mut Challenger<F, C::Hasher>,

View File

@ -9,34 +9,37 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer
use crate::stark::Stark;
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
pub struct JuliaStark<F: RichField + Extendable<D>, const D: usize> {
c: F,
pub struct FibonacciStark<F: RichField + Extendable<D>, const D: usize> {
x0: F,
x1: F,
_phantom: PhantomData<F>,
}
impl<F: RichField + Extendable<D>, const D: usize> JuliaStark<F, D> {
const NUM_COLUMNS: usize = 1;
const NUM_ROWS: usize = 1 << 10;
impl<F: RichField + Extendable<D>, const D: usize> FibonacciStark<F, D> {
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<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for JuliaStark<F, D> {
impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for FibonacciStark<F, D> {
const COLUMNS: usize = Self::NUM_COLUMNS;
const PUBLIC_INPUTS: usize = 0;
@ -48,11 +51,8 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for JuliaStark<F,
FE: FieldExtension<D2, BaseField = F>,
P: PackedField<Scalar = FE>,
{
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<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for JuliaStark<F,
#[cfg(test)]
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;
use crate::config::StarkConfig;
use crate::julia_stark::JuliaStark;
use crate::fibonacci_stark::FibonacciStark;
use crate::prover::prove;
#[test]
fn test_julia_stark() {
fn test_fibonacci_stark() -> Result<()> {
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;
type S = JuliaStark<F, D>;
type S = FibonacciStark<F, D>;
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::<F, C, S, D>(stark, config, trace, &mut TimingTree::default());
prove::<F, C, S, D>(stark, config, trace, &mut TimingTree::default())?;
Ok(())
}
}

View File

@ -14,4 +14,4 @@ pub mod stark;
pub mod vars;
#[cfg(test)]
pub mod julia_stark;
pub mod fibonacci_stark;

View File

@ -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<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> {
/// Merkle cap of LDEs of trace values.
@ -33,3 +35,25 @@ pub struct StarkOpeningSet<F: RichField + Extendable<D>, const D: usize> {
pub permutation_zs: Vec<F::Extension>,
pub quotient_polys: Vec<F::Extension>,
}
impl<F: RichField + Extendable<D>, const D: usize> StarkOpeningSet<F, D> {
pub fn new<C: GenericConfig<D, F = F>>(
zeta: F::Extension,
g: F::Extension,
trace_commitment: &PolynomialBatch<F, C, D>,
quotient_commitment: &PolynomialBatch<F, C, D>,
) -> Self {
let eval_commitment = |z: F::Extension, c: &PolynomialBatch<F, C, D>| {
c.polynomials
.par_iter()
.map(|p| p.to_extension().eval(z))
.collect::<Vec<_>>()
};
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),
}
}
}

View File

@ -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<F, C, S, const D: usize>(
config: StarkConfig,
trace: Vec<[F; S::COLUMNS]>,
timing: &mut TimingTree,
) -> StarkProof<F, C, D>
) -> Result<StarkProof<F, C, D>>
where
F: RichField + Extendable<D>,
C: GenericConfig<D, F = F>,
@ -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<Vec<F>> = 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::<F, C, S, D>(
let quotient_polys = compute_quotient_polys::<F, C, S, D>(
&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(&quotient_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::<D>();
// 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, &quotient_commitment);
// TODO: Add permuation checks
let initial_merkle_trees = &[&trace_commitment, &quotient_commitment];
let fri_params = config.fri_params(degree_bits);
let opening_proof = fri_proof::<F, C, D>(
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<F, C, S, const D: usize>(

View File

@ -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<F: RichField + Extendable<D>, const D: usize>: Sync {
vars: StarkEvaluationTargets<D, { Self::COLUMNS }, { Self::PUBLIC_INPUTS }>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
);
fn fri_instance(
zeta: F::Extension,
g: F::Extension,
rate_bits: usize,
) -> FriInstanceInfo<F, D> {
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::<F, D> {
point: zeta * g,
polynomials: trace_info,
};
FriInstanceInfo {
oracles: vec![no_blinding_oracle; 3],
batches: vec![zeta_batch],
}
}
}