use alloc::vec::Vec;
use core::fmt::Debug;
use p3_field::ExtensionField;
use p3_matrix::Matrix;
use p3_matrix::dense::RowMajorMatrix;
use serde::Serialize;
use serde::de::DeserializeOwned;
use crate::{PeriodicLdeTable, PolynomialSpace};
pub type Val<D> = <D as PolynomialSpace>::Val;
pub trait Pcs<Challenge, Challenger>
where
Challenge: ExtensionField<Val<Self::Domain>>,
{
type Domain: PolynomialSpace;
type Commitment: Clone + Serialize + DeserializeOwned;
type ProverData;
type EvaluationsOnDomain<'a>: Matrix<Val<Self::Domain>> + 'a;
type Proof: Clone + Serialize + DeserializeOwned;
type Error: Debug;
const ZK: bool;
const TRACE_IDX: usize = Self::ZK as usize;
const QUOTIENT_IDX: usize = Self::TRACE_IDX + 1;
const PREPROCESSED_TRACE_IDX: usize = Self::QUOTIENT_IDX + 1;
fn natural_domain_for_degree(&self, degree: usize) -> Self::Domain;
fn log_max_lde_height(&self) -> usize;
#[allow(clippy::type_complexity)]
fn commit(
&self,
evaluations: impl IntoIterator<Item = (Self::Domain, RowMajorMatrix<Val<Self::Domain>>)>,
) -> (Self::Commitment, Self::ProverData);
fn commit_preprocessing(
&self,
evaluations: impl IntoIterator<Item = (Self::Domain, RowMajorMatrix<Val<Self::Domain>>)>,
) -> (Self::Commitment, Self::ProverData) {
self.commit(evaluations)
}
#[allow(clippy::type_complexity)]
fn commit_quotient(
&self,
quotient_domain: Self::Domain,
quotient_evaluations: RowMajorMatrix<Val<Self::Domain>>,
num_chunks: usize,
) -> (Self::Commitment, Self::ProverData) {
let quotient_sub_evaluations =
quotient_domain.split_evals(num_chunks, quotient_evaluations);
let quotient_sub_domains = quotient_domain.split_domains(num_chunks);
let ldes = self.get_quotient_ldes(
quotient_sub_domains
.into_iter()
.zip(quotient_sub_evaluations),
num_chunks,
);
self.commit_ldes(ldes)
}
fn get_quotient_ldes(
&self,
evaluations: impl IntoIterator<Item = (Self::Domain, RowMajorMatrix<Val<Self::Domain>>)>,
num_chunks: usize,
) -> Vec<RowMajorMatrix<Val<Self::Domain>>>;
fn commit_ldes(
&self,
ldes: Vec<RowMajorMatrix<Val<Self::Domain>>>,
) -> (Self::Commitment, Self::ProverData);
fn get_evaluations_on_domain<'a>(
&self,
prover_data: &'a Self::ProverData,
idx: usize,
domain: Self::Domain,
) -> Self::EvaluationsOnDomain<'a>;
fn get_evaluations_on_domain_no_random<'a>(
&self,
prover_data: &'a Self::ProverData,
idx: usize,
domain: Self::Domain,
) -> Self::EvaluationsOnDomain<'a> {
self.get_evaluations_on_domain(prover_data, idx, domain)
}
fn open(
&self,
commitment_data_with_opening_points: Vec<(
// The matrices and auxiliary prover data
&Self::ProverData,
// for each matrix,
Vec<
Vec<Challenge>,
>,
)>,
fiat_shamir_challenger: &mut Challenger,
) -> (OpenedValues<Challenge>, Self::Proof);
fn open_with_preprocessing(
&self,
commitment_data_with_opening_points: Vec<(
// The matrices and auxiliary prover data
&Self::ProverData,
// for each matrix,
Vec<
Vec<Challenge>,
>,
)>,
fiat_shamir_challenger: &mut Challenger,
_is_preprocessing: bool,
) -> (OpenedValues<Challenge>, Self::Proof) {
assert!(
!Self::ZK,
"open_with_preprocessing should have a different implementation when ZK is enabled"
);
self.open(commitment_data_with_opening_points, fiat_shamir_challenger)
}
#[allow(clippy::type_complexity)]
fn verify(
&self,
commitments_with_opening_points: Vec<(
// The commitment
Self::Commitment,
// for each matrix in the commitment:
Vec<(
// its domain,
Self::Domain,
// A vector of (point, claimed_evaluation) pairs
Vec<(
// the point the matrix was opened at,
Challenge,
// the claimed evaluations at that point
Vec<Challenge>,
)>,
)>,
)>,
proof: &Self::Proof,
fiat_shamir_challenger: &mut Challenger,
) -> Result<(), Self::Error>;
fn get_opt_randomization_poly_commitment(
&self,
_domain: impl IntoIterator<Item = Self::Domain>,
) -> Option<(Self::Commitment, Self::ProverData)> {
None
}
fn build_periodic_lde_table(
&self,
periodic_cols: &[Vec<Val<Self::Domain>>],
trace_domain: Self::Domain,
quotient_domain: Self::Domain,
) -> PeriodicLdeTable<Val<Self::Domain>>
where
Self::Domain: Clone,
Val<Self::Domain>: Clone,
{
if periodic_cols.is_empty() {
return PeriodicLdeTable::empty();
}
let trace_size = trace_domain.size();
let quotient_size = quotient_domain.size();
assert!(
quotient_size >= trace_size,
"quotient domain size ({quotient_size}) must be >= trace domain size ({trace_size})",
);
assert!(
quotient_size.is_multiple_of(trace_size),
"quotient domain size ({quotient_size}) must be divisible by trace domain size ({trace_size})",
);
let blowup = quotient_size / trace_size;
for col in periodic_cols {
let period = col.len();
assert!(
period > 0 && period.is_power_of_two(),
"periodic column length must be a non-zero power of 2, got {period}",
);
assert!(
trace_size.is_multiple_of(period),
"trace domain size ({trace_size}) must be divisible by periodic column length ({period})",
);
}
let max_period = periodic_cols.iter().map(|c| c.len()).max().unwrap();
let extended_height = max_period
.checked_mul(blowup)
.expect("extended height overflow when computing max_period * blowup");
debug_assert!(extended_height <= quotient_size);
let num_cols = periodic_cols.len();
let row_major_capacity = extended_height
.checked_mul(num_cols)
.expect("row-major periodic table capacity overflow");
let mut quotient_pts = Vec::with_capacity(extended_height);
let mut pt = quotient_domain.first_point();
for _ in 0..extended_height {
quotient_pts.push(pt);
pt = quotient_domain
.next_point(pt)
.expect("quotient domain must support next_point");
}
let padded_cols: Vec<Vec<Val<Self::Domain>>> = periodic_cols
.iter()
.map(|col| (0..max_period).map(|i| col[i % col.len()]).collect())
.collect();
let mut row_major = Vec::with_capacity(row_major_capacity);
for point in quotient_pts.iter().take(extended_height) {
for padded in &padded_cols {
row_major.push(trace_domain.evaluate_periodic_column_at(padded, *point));
}
}
PeriodicLdeTable::new(RowMajorMatrix::new(row_major, num_cols))
}
}
pub type CommitmentWithOpeningPoints<Challenge, Commitment, Domain> = (
Commitment,
Vec<(
// The domain of the matrix
Domain,
// A vector of (point, claimed_evaluation) pairs.
// The claimed evaluation count per point is also the matrix width used by verification.
Vec<(Challenge, Vec<Challenge>)>,
)>,
);
pub type OpenedValues<F> = Vec<OpenedValuesForRound<F>>;
pub type OpenedValuesForRound<F> = Vec<OpenedValuesForMatrix<F>>;
pub type OpenedValuesForMatrix<F> = Vec<OpenedValuesForPoint<F>>;
pub type OpenedValuesForPoint<F> = Vec<F>;