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