openvm_stark_backend/prover/
opener.rsuse std::fmt::Debug;
use derivative::Derivative;
use itertools::Itertools;
use p3_commit::{Pcs, PolynomialSpace};
use serde::{Deserialize, Serialize};
use tracing::instrument;
use crate::config::{Domain, PcsProof, PcsProverData, StarkGenericConfig};
pub struct OpeningProver<'pcs, SC: StarkGenericConfig> {
pcs: &'pcs SC::Pcs,
zeta: SC::Challenge,
}
impl<'pcs, SC: StarkGenericConfig> OpeningProver<'pcs, SC> {
pub fn new(pcs: &'pcs SC::Pcs, zeta: SC::Challenge) -> Self {
Self { pcs, zeta }
}
#[instrument(name = "FRI opening proofs", skip_all)]
pub fn open(
&self,
challenger: &mut SC::Challenger,
preprocessed: Vec<(&PcsProverData<SC>, Domain<SC>)>,
main: Vec<(&PcsProverData<SC>, Vec<Domain<SC>>)>,
after_challenge: Vec<(&PcsProverData<SC>, Vec<Domain<SC>>)>,
quotient_data: &PcsProverData<SC>,
quotient_degrees: &[usize],
) -> OpeningProof<SC> {
let preprocessed: Vec<_> = preprocessed
.into_iter()
.map(|(data, domain)| (data, vec![domain]))
.collect();
let zeta = self.zeta;
let mut rounds = preprocessed
.iter()
.chain(main.iter())
.chain(after_challenge.iter())
.map(|(data, domains)| {
let points_per_mat = domains
.iter()
.map(|domain| vec![zeta, domain.next_point(zeta).unwrap()])
.collect_vec();
(*data, points_per_mat)
})
.collect_vec();
let num_chunks: usize = quotient_degrees.iter().sum();
let quotient_opening_points = vec![vec![zeta]; num_chunks];
rounds.push((quotient_data, quotient_opening_points));
let (mut opening_values, opening_proof) = self.pcs.open(rounds, challenger);
let mut quotient_openings = opening_values.pop().expect("Should have quotient opening");
let num_after_challenge = after_challenge.len();
let after_challenge_openings = opening_values
.split_off(opening_values.len() - num_after_challenge)
.into_iter()
.map(collect_trace_openings)
.collect_vec();
assert_eq!(
after_challenge_openings.len(),
num_after_challenge,
"Incorrect number of after challenge trace openings"
);
let main_openings = opening_values
.split_off(preprocessed.len())
.into_iter()
.map(collect_trace_openings)
.collect_vec();
assert_eq!(
main_openings.len(),
main.len(),
"Incorrect number of main trace openings"
);
let preprocessed_openings = opening_values
.into_iter()
.map(|values| {
let mut openings = collect_trace_openings(values);
openings
.pop()
.expect("Preprocessed trace should be opened at 1 point")
})
.collect_vec();
assert_eq!(
preprocessed_openings.len(),
preprocessed.len(),
"Incorrect number of preprocessed trace openings"
);
let quotient_openings = quotient_degrees
.iter()
.map(|&chunk_size| {
quotient_openings
.drain(..chunk_size)
.map(|mut op| {
op.pop()
.expect("quotient chunk should be opened at 1 point")
})
.collect_vec()
})
.collect_vec();
OpeningProof {
proof: opening_proof,
values: OpenedValues {
preprocessed: preprocessed_openings,
main: main_openings,
after_challenge: after_challenge_openings,
quotient: quotient_openings,
},
}
}
}
fn collect_trace_openings<Challenge: Debug>(
ops: Vec<Vec<Vec<Challenge>>>,
) -> Vec<AdjacentOpenedValues<Challenge>> {
ops.into_iter()
.map(|op| {
let [local, next] = op.try_into().expect("Should have 2 openings");
AdjacentOpenedValues { local, next }
})
.collect()
}
#[derive(Serialize, Deserialize, Derivative)]
#[serde(bound = "")]
#[derivative(Clone(bound = "SC::Challenge: Clone"))]
pub struct OpeningProof<SC: StarkGenericConfig> {
pub proof: PcsProof<SC>,
pub values: OpenedValues<SC::Challenge>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct OpenedValues<Challenge> {
pub preprocessed: Vec<AdjacentOpenedValues<Challenge>>,
pub main: Vec<Vec<AdjacentOpenedValues<Challenge>>>,
pub after_challenge: Vec<Vec<AdjacentOpenedValues<Challenge>>>,
pub quotient: Vec<Vec<Vec<Challenge>>>,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct AdjacentOpenedValues<Challenge> {
pub local: Vec<Challenge>,
pub next: Vec<Challenge>,
}