openvm_stark_backend/prover/cpu/
opener.rs1use std::fmt::Debug;
2
3use itertools::Itertools;
4use p3_commit::{Pcs, PolynomialSpace};
5
6use crate::{
7 config::{Domain, PcsProof, PcsProverData, StarkGenericConfig},
8 proof::{AdjacentOpenedValues, OpenedValues, OpeningProof},
9};
10
11pub struct OpeningProver<'pcs, SC: StarkGenericConfig> {
12 pcs: &'pcs SC::Pcs,
13 zeta: SC::Challenge,
14}
15
16impl<'pcs, SC: StarkGenericConfig> OpeningProver<'pcs, SC> {
17 pub fn new(pcs: &'pcs SC::Pcs, zeta: SC::Challenge) -> Self {
18 Self { pcs, zeta }
19 }
20
21 pub fn open(
27 &self,
28 challenger: &mut SC::Challenger,
29 preprocessed: Vec<(&PcsProverData<SC>, Domain<SC>)>,
32 main: Vec<(&PcsProverData<SC>, Vec<Domain<SC>>)>,
35 after_challenge: Vec<(&PcsProverData<SC>, Vec<Domain<SC>>)>,
38 quotient_data: &PcsProverData<SC>,
40 quotient_degrees: &[u8],
42 ) -> OpeningProof<PcsProof<SC>, SC::Challenge> {
43 let preprocessed: Vec<_> = preprocessed
44 .into_iter()
45 .map(|(data, domain)| (data, vec![domain]))
46 .collect();
47
48 let zeta = self.zeta;
49 let mut rounds = preprocessed
50 .iter()
51 .chain(main.iter())
52 .chain(after_challenge.iter())
53 .map(|(data, domains)| {
54 let points_per_mat = domains
55 .iter()
56 .map(|domain| vec![zeta, domain.next_point(zeta).unwrap()])
57 .collect_vec();
58 (*data, points_per_mat)
59 })
60 .collect_vec();
61
62 let num_chunks = quotient_degrees.iter().map(|x| *x as usize).sum();
64 let quotient_opening_points = vec![vec![zeta]; num_chunks];
65 rounds.push((quotient_data, quotient_opening_points));
66
67 let (mut opening_values, opening_proof) = self.pcs.open(rounds, challenger);
68
69 let mut quotient_openings = opening_values.pop().expect("Should have quotient opening");
71
72 let num_after_challenge = after_challenge.len();
73 let after_challenge_openings = opening_values
74 .split_off(opening_values.len() - num_after_challenge)
75 .into_iter()
76 .map(collect_trace_openings)
77 .collect_vec();
78 assert_eq!(
79 after_challenge_openings.len(),
80 num_after_challenge,
81 "Incorrect number of after challenge trace openings"
82 );
83
84 let main_openings = opening_values
85 .split_off(preprocessed.len())
86 .into_iter()
87 .map(collect_trace_openings)
88 .collect_vec();
89 assert_eq!(
90 main_openings.len(),
91 main.len(),
92 "Incorrect number of main trace openings"
93 );
94
95 let preprocessed_openings = opening_values
96 .into_iter()
97 .map(|values| {
98 let mut openings = collect_trace_openings(values);
99 openings
100 .pop()
101 .expect("Preprocessed trace should be opened at 1 point")
102 })
103 .collect_vec();
104 assert_eq!(
105 preprocessed_openings.len(),
106 preprocessed.len(),
107 "Incorrect number of preprocessed trace openings"
108 );
109
110 let quotient_openings = quotient_degrees
112 .iter()
113 .map(|&chunk_size| {
114 quotient_openings
115 .drain(..chunk_size as usize)
116 .map(|mut op| {
117 op.pop()
118 .expect("quotient chunk should be opened at 1 point")
119 })
120 .collect_vec()
121 })
122 .collect_vec();
123
124 OpeningProof {
125 proof: opening_proof,
126 values: OpenedValues {
127 preprocessed: preprocessed_openings,
128 main: main_openings,
129 after_challenge: after_challenge_openings,
130 quotient: quotient_openings,
131 },
132 }
133 }
134}
135
136fn collect_trace_openings<Challenge: Debug>(
137 ops: Vec<Vec<Vec<Challenge>>>,
138) -> Vec<AdjacentOpenedValues<Challenge>> {
139 ops.into_iter()
140 .map(|op| {
141 let [local, next] = op.try_into().expect("Should have 2 openings");
142 AdjacentOpenedValues { local, next }
143 })
144 .collect()
145}