1use alloc::vec::Vec;
4
5use p3_field::{ExtensionField, Field};
6use p3_multilinear_util::point::Point;
7use p3_multilinear_util::poly::Poly;
8
9use crate::Claim;
10use crate::svo::{SvoAccumulators, SvoPoint};
11
12pub type ProverMultiClaim<F, EF> = MultiClaim<EF, SvoPoint<F, EF>, Vec<Poly<EF>>>;
14pub type ProverVirtualClaim<EF> = Claim<EF, Point<EF>, SvoAccumulators<EF>>;
16
17pub type VerifierOpening<EF> = Opening<EF, ()>;
19pub type VerifierMultiClaim<EF> = MultiClaim<EF, Point<EF>, ()>;
21pub type VerifierVirtualClaim<EF> = Claim<EF, Point<EF>, ()>;
23
24#[derive(Debug, Clone)]
32pub struct Opening<EF: Field, Data> {
33 pub(crate) poly_idx: Option<usize>,
35 pub(crate) eval: EF,
37 pub(crate) data: Data,
39}
40
41impl<EF: Field, Data> Opening<EF, Data> {
42 pub const fn eval(&self) -> EF {
44 self.eval
45 }
46
47 pub const fn poly_idx(&self) -> Option<usize> {
49 self.poly_idx
50 }
51
52 pub const fn data(&self) -> &Data {
54 &self.data
55 }
56}
57
58impl<EF: Field> Opening<EF, ()> {
59 pub const fn new(poly_idx: usize, eval: EF) -> Self {
66 Self {
67 poly_idx: Some(poly_idx),
68 eval,
69 data: (),
70 }
71 }
72}
73
74#[derive(Debug, Clone)]
91pub struct MultiClaim<F: ExtensionField<F>, Point, Data> {
92 pub(super) point: Point,
94 pub(super) openings: Vec<Opening<F, Data>>,
96}
97
98impl<EF: Field, Point, Data> MultiClaim<EF, Point, Data> {
99 pub const fn new(point: Point, openings: Vec<Opening<EF, Data>>) -> Self {
101 Self { point, openings }
102 }
103
104 pub const fn point(&self) -> &Point {
106 &self.point
107 }
108
109 pub const fn len(&self) -> usize {
111 self.openings.len()
112 }
113
114 pub const fn is_empty(&self) -> bool {
116 self.openings.is_empty()
117 }
118
119 pub fn openings(&self) -> &[Opening<EF, Data>] {
121 &self.openings
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use alloc::vec;
128 use alloc::vec::Vec;
129
130 use p3_baby_bear::BabyBear;
131 use p3_field::PrimeCharacteristicRing;
132
133 use super::*;
134
135 type F = BabyBear;
136
137 #[test]
138 fn opening_new_sets_poly_idx_eval_and_unit_data() {
139 let opening: Opening<F, ()> = Opening::new(3, F::from_u64(42));
141
142 assert_eq!(opening.poly_idx(), Some(3));
148 assert_eq!(opening.eval(), F::from_u64(42));
149 assert_eq!(opening.data(), &());
150 }
151
152 #[test]
153 fn opening_struct_literal_supports_virtual_form() {
154 let opening: Opening<F, ()> = Opening {
157 poly_idx: None,
158 eval: F::from_u64(7),
159 data: (),
160 };
161
162 assert_eq!(opening.poly_idx(), None);
164 assert_eq!(opening.eval(), F::from_u64(7));
165 }
166
167 #[test]
168 fn opening_accessors_reflect_non_unit_data() {
169 let data = vec![F::from_u64(1), F::from_u64(2), F::from_u64(3)];
171 let opening: Opening<F, Vec<F>> = Opening {
172 poly_idx: Some(0),
173 eval: F::from_u64(99),
174 data: data.clone(),
175 };
176
177 assert_eq!(opening.data(), &data);
179 }
180
181 #[test]
182 fn opening_clone_copies_every_field() {
183 let original: Opening<F, Vec<F>> = Opening {
185 poly_idx: Some(5),
186 eval: F::from_u64(11),
187 data: vec![F::from_u64(10)],
188 };
189 let cloned = original.clone();
190
191 assert_eq!(cloned.poly_idx(), original.poly_idx());
192 assert_eq!(cloned.eval(), original.eval());
193 assert_eq!(cloned.data(), original.data());
194 }
195
196 #[test]
197 fn multi_claim_new_preserves_shared_point() {
198 let openings = vec![
200 Opening::<F, ()>::new(0, F::from_u64(1)),
201 Opening::<F, ()>::new(1, F::from_u64(2)),
202 ];
203 let claim = MultiClaim::<F, u32, ()>::new(100, openings);
204
205 assert_eq!(*claim.point(), 100);
207 assert_eq!(claim.openings().len(), 2);
208 }
209
210 #[test]
211 fn multi_claim_len_matches_openings_count() {
212 for n in [0usize, 1, 4] {
214 let openings: Vec<Opening<F, ()>> = (0..n)
215 .map(|i| Opening::new(i, F::from_u64(i as u64)))
216 .collect();
217 let claim = MultiClaim::<F, u32, ()>::new(0, openings);
218
219 assert_eq!(claim.len(), n);
221 }
222 }
223
224 #[test]
225 fn multi_claim_is_empty_is_true_iff_no_openings() {
226 let empty: MultiClaim<F, u32, ()> = MultiClaim::new(0, vec![]);
228 assert!(empty.is_empty());
229
230 let filled = MultiClaim::<F, u32, ()>::new(0, vec![Opening::new(0, F::from_u64(1))]);
232 assert!(!filled.is_empty());
233 }
234
235 #[test]
236 fn multi_claim_openings_returns_insertion_order() {
237 let expected = vec![
242 Opening::<F, ()>::new(2, F::from_u64(20)),
243 Opening::<F, ()>::new(0, F::from_u64(0)),
244 Opening::<F, ()>::new(1, F::from_u64(10)),
245 ];
246 let claim = MultiClaim::<F, u32, ()>::new(0, expected.clone());
247
248 for (i, got) in claim.openings().iter().enumerate() {
249 assert_eq!(got.poly_idx(), expected[i].poly_idx());
250 assert_eq!(got.eval(), expected[i].eval());
251 }
252 }
253
254 #[test]
255 fn multi_claim_clone_preserves_point_and_openings() {
256 let claim = MultiClaim::<F, u32, ()>::new(
258 77,
259 vec![
260 Opening::new(1, F::from_u64(5)),
261 Opening::new(2, F::from_u64(6)),
262 ],
263 );
264 let cloned = claim.clone();
265
266 assert_eq!(*cloned.point(), *claim.point());
267 assert_eq!(cloned.len(), claim.len());
268 for (a, b) in cloned.openings().iter().zip(claim.openings()) {
269 assert_eq!(a.poly_idx(), b.poly_idx());
270 assert_eq!(a.eval(), b.eval());
271 }
272 }
273}