use alloc::vec::Vec;
use p3_field::{ExtensionField, Field};
use p3_multilinear_util::point::Point;
use p3_multilinear_util::poly::Poly;
use crate::Claim;
use crate::svo::{SvoAccumulators, SvoPoint};
pub type ProverMultiClaim<F, EF> = MultiClaim<EF, SvoPoint<F, EF>, Vec<Poly<EF>>>;
pub type ProverVirtualClaim<EF> = Claim<EF, Point<EF>, SvoAccumulators<EF>>;
pub type VerifierOpening<EF> = Opening<EF, ()>;
pub type VerifierMultiClaim<EF> = MultiClaim<EF, Point<EF>, ()>;
pub type VerifierVirtualClaim<EF> = Claim<EF, Point<EF>, ()>;
#[derive(Debug, Clone)]
pub struct Opening<EF: Field, Data> {
pub(crate) poly_idx: Option<usize>,
pub(crate) eval: EF,
pub(crate) data: Data,
}
impl<EF: Field, Data> Opening<EF, Data> {
pub const fn eval(&self) -> EF {
self.eval
}
pub const fn poly_idx(&self) -> Option<usize> {
self.poly_idx
}
pub const fn data(&self) -> &Data {
&self.data
}
}
impl<EF: Field> Opening<EF, ()> {
pub const fn new(poly_idx: usize, eval: EF) -> Self {
Self {
poly_idx: Some(poly_idx),
eval,
data: (),
}
}
}
#[derive(Debug, Clone)]
pub struct MultiClaim<F: ExtensionField<F>, Point, Data> {
pub(super) point: Point,
pub(super) openings: Vec<Opening<F, Data>>,
}
impl<EF: Field, Point, Data> MultiClaim<EF, Point, Data> {
pub const fn new(point: Point, openings: Vec<Opening<EF, Data>>) -> Self {
Self { point, openings }
}
pub const fn point(&self) -> &Point {
&self.point
}
pub const fn len(&self) -> usize {
self.openings.len()
}
pub const fn is_empty(&self) -> bool {
self.openings.is_empty()
}
pub fn openings(&self) -> &[Opening<EF, Data>] {
&self.openings
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use alloc::vec::Vec;
use p3_baby_bear::BabyBear;
use p3_field::PrimeCharacteristicRing;
use super::*;
type F = BabyBear;
#[test]
fn opening_new_sets_poly_idx_eval_and_unit_data() {
let opening: Opening<F, ()> = Opening::new(3, F::from_u64(42));
assert_eq!(opening.poly_idx(), Some(3));
assert_eq!(opening.eval(), F::from_u64(42));
assert_eq!(opening.data(), &());
}
#[test]
fn opening_struct_literal_supports_virtual_form() {
let opening: Opening<F, ()> = Opening {
poly_idx: None,
eval: F::from_u64(7),
data: (),
};
assert_eq!(opening.poly_idx(), None);
assert_eq!(opening.eval(), F::from_u64(7));
}
#[test]
fn opening_accessors_reflect_non_unit_data() {
let data = vec![F::from_u64(1), F::from_u64(2), F::from_u64(3)];
let opening: Opening<F, Vec<F>> = Opening {
poly_idx: Some(0),
eval: F::from_u64(99),
data: data.clone(),
};
assert_eq!(opening.data(), &data);
}
#[test]
fn opening_clone_copies_every_field() {
let original: Opening<F, Vec<F>> = Opening {
poly_idx: Some(5),
eval: F::from_u64(11),
data: vec![F::from_u64(10)],
};
let cloned = original.clone();
assert_eq!(cloned.poly_idx(), original.poly_idx());
assert_eq!(cloned.eval(), original.eval());
assert_eq!(cloned.data(), original.data());
}
#[test]
fn multi_claim_new_preserves_shared_point() {
let openings = vec![
Opening::<F, ()>::new(0, F::from_u64(1)),
Opening::<F, ()>::new(1, F::from_u64(2)),
];
let claim = MultiClaim::<F, u32, ()>::new(100, openings);
assert_eq!(*claim.point(), 100);
assert_eq!(claim.openings().len(), 2);
}
#[test]
fn multi_claim_len_matches_openings_count() {
for n in [0usize, 1, 4] {
let openings: Vec<Opening<F, ()>> = (0..n)
.map(|i| Opening::new(i, F::from_u64(i as u64)))
.collect();
let claim = MultiClaim::<F, u32, ()>::new(0, openings);
assert_eq!(claim.len(), n);
}
}
#[test]
fn multi_claim_is_empty_is_true_iff_no_openings() {
let empty: MultiClaim<F, u32, ()> = MultiClaim::new(0, vec![]);
assert!(empty.is_empty());
let filled = MultiClaim::<F, u32, ()>::new(0, vec![Opening::new(0, F::from_u64(1))]);
assert!(!filled.is_empty());
}
#[test]
fn multi_claim_openings_returns_insertion_order() {
let expected = vec![
Opening::<F, ()>::new(2, F::from_u64(20)),
Opening::<F, ()>::new(0, F::from_u64(0)),
Opening::<F, ()>::new(1, F::from_u64(10)),
];
let claim = MultiClaim::<F, u32, ()>::new(0, expected.clone());
for (i, got) in claim.openings().iter().enumerate() {
assert_eq!(got.poly_idx(), expected[i].poly_idx());
assert_eq!(got.eval(), expected[i].eval());
}
}
#[test]
fn multi_claim_clone_preserves_point_and_openings() {
let claim = MultiClaim::<F, u32, ()>::new(
77,
vec![
Opening::new(1, F::from_u64(5)),
Opening::new(2, F::from_u64(6)),
],
);
let cloned = claim.clone();
assert_eq!(*cloned.point(), *claim.point());
assert_eq!(cloned.len(), claim.len());
for (a, b) in cloned.openings().iter().zip(claim.openings()) {
assert_eq!(a.poly_idx(), b.poly_idx());
assert_eq!(a.eval(), b.eval());
}
}
}