1use core::mem;
2use core::ops::Deref;
3
4use serde::{Deserialize, Serialize};
5use std_shims::Vec;
6
7use crate::core::circle::CirclePoint;
8use crate::core::fields::m31::BaseField;
9use crate::core::fields::qm31::{SecureField, SECURE_EXTENSION_DEGREE};
10use crate::core::fri::{FriLayerProof, FriProof};
11use crate::core::pcs::quotients::{CommitmentSchemeProof, CommitmentSchemeProofAux};
12use crate::core::vcs::hash::Hash;
13use crate::core::vcs_lifted::merkle_hasher::MerkleHasherLifted;
14use crate::core::vcs_lifted::verifier::MerkleDecommitmentLifted;
15
16#[derive(Clone, Debug, Serialize, Deserialize)]
17pub struct StarkProof<H: MerkleHasherLifted>(pub CommitmentSchemeProof<H>);
18
19#[derive(Clone, Debug, Serialize, Deserialize)]
20pub struct ExtendedStarkProof<H: MerkleHasherLifted> {
21 pub proof: StarkProof<H>,
22 pub aux: CommitmentSchemeProofAux<H>,
23}
24
25impl<H: MerkleHasherLifted> StarkProof<H> {
26 pub(crate) fn extract_composition_oods_eval(
28 &self,
29 oods_point: CirclePoint<SecureField>,
30 composition_log_size: u32,
31 ) -> Option<SecureField> {
32 let [.., left_and_right_composition_mask] = &**self.sampled_values else {
35 return None;
36 };
37 let left_and_right_coordinate_evals: [SecureField; 2 * SECURE_EXTENSION_DEGREE] =
38 left_and_right_composition_mask
39 .iter()
40 .map(|columns| {
41 let &[eval] = &columns[..] else {
42 return None;
43 };
44 Some(eval)
45 })
46 .collect::<Option<Vec<_>>>()?
47 .try_into()
48 .ok()?;
49
50 let (left_coordinate_evals, right_coordinate_evals) =
51 left_and_right_coordinate_evals.split_at(SECURE_EXTENSION_DEGREE);
52
53 let left_eval = SecureField::from_partial_evals(left_coordinate_evals.try_into().ok()?);
54 let right_eval = SecureField::from_partial_evals(right_coordinate_evals.try_into().ok()?);
55 let value = left_eval + oods_point.repeated_double(composition_log_size - 2).x * right_eval;
56 Some(value)
57 }
58
59 pub fn size_estimate(&self) -> usize {
61 SizeEstimate::size_estimate(self)
62 }
63
64 pub fn size_breakdown_estimate(&self) -> StarkProofSizeBreakdown {
66 let Self(commitment_scheme_proof) = self;
67
68 let CommitmentSchemeProof {
69 commitments,
70 sampled_values,
71 decommitments,
72 queried_values,
73 proof_of_work: _,
74 fri_proof,
75 config: _,
76 } = commitment_scheme_proof;
77
78 let FriProof {
79 first_layer,
80 inner_layers,
81 last_layer_poly,
82 } = fri_proof;
83
84 let mut inner_layers_samples_size = 0;
85 let mut inner_layers_hashes_size = 0;
86
87 for FriLayerProof {
88 fri_witness,
89 decommitment,
90 commitment,
91 } in inner_layers
92 {
93 inner_layers_samples_size += fri_witness.size_estimate();
94 inner_layers_hashes_size += decommitment.size_estimate() + commitment.size_estimate();
95 }
96
97 StarkProofSizeBreakdown {
98 oods_samples: sampled_values.size_estimate(),
99 queries_values: queried_values.size_estimate(),
100 fri_samples: last_layer_poly.size_estimate()
101 + inner_layers_samples_size
102 + first_layer.fri_witness.size_estimate(),
103 fri_decommitments: inner_layers_hashes_size
104 + first_layer.decommitment.size_estimate()
105 + first_layer.commitment.size_estimate(),
106 trace_decommitments: commitments.size_estimate() + decommitments.size_estimate(),
107 }
108 }
109}
110
111impl<H: MerkleHasherLifted> Deref for StarkProof<H> {
112 type Target = CommitmentSchemeProof<H>;
113
114 fn deref(&self) -> &CommitmentSchemeProof<H> {
115 &self.0
116 }
117}
118
119#[derive(Debug)]
121pub struct StarkProofSizeBreakdown {
122 pub oods_samples: usize,
123 pub queries_values: usize,
124 pub fri_samples: usize,
125 pub fri_decommitments: usize,
126 pub trace_decommitments: usize,
127}
128
129trait SizeEstimate {
130 fn size_estimate(&self) -> usize;
131}
132
133impl<T: SizeEstimate> SizeEstimate for [T] {
134 fn size_estimate(&self) -> usize {
135 self.iter().map(|v| v.size_estimate()).sum()
136 }
137}
138
139impl<T: SizeEstimate> SizeEstimate for Vec<T> {
140 fn size_estimate(&self) -> usize {
141 self.iter().map(|v| v.size_estimate()).sum()
142 }
143}
144
145impl<H: Hash> SizeEstimate for H {
146 fn size_estimate(&self) -> usize {
147 mem::size_of::<Self>()
148 }
149}
150
151impl SizeEstimate for BaseField {
152 fn size_estimate(&self) -> usize {
153 mem::size_of::<Self>()
154 }
155}
156
157impl SizeEstimate for SecureField {
158 fn size_estimate(&self) -> usize {
159 mem::size_of::<Self>()
160 }
161}
162
163impl<H: MerkleHasherLifted> SizeEstimate for MerkleDecommitmentLifted<H> {
164 fn size_estimate(&self) -> usize {
165 let Self { hash_witness } = self;
166 hash_witness.size_estimate()
167 }
168}
169
170impl<H: MerkleHasherLifted> SizeEstimate for FriLayerProof<H> {
171 fn size_estimate(&self) -> usize {
172 let Self {
173 fri_witness,
174 decommitment,
175 commitment,
176 } = self;
177 fri_witness.size_estimate() + decommitment.size_estimate() + commitment.size_estimate()
178 }
179}
180
181impl<H: MerkleHasherLifted> SizeEstimate for FriProof<H> {
182 fn size_estimate(&self) -> usize {
183 let Self {
184 first_layer,
185 inner_layers,
186 last_layer_poly,
187 } = self;
188 first_layer.size_estimate() + inner_layers.size_estimate() + last_layer_poly.size_estimate()
189 }
190}
191
192impl<H: MerkleHasherLifted> SizeEstimate for CommitmentSchemeProof<H> {
193 fn size_estimate(&self) -> usize {
194 let Self {
195 commitments,
196 sampled_values,
197 decommitments,
198 queried_values,
199 proof_of_work,
200 fri_proof,
201 config,
202 } = self;
203 commitments.size_estimate()
204 + sampled_values.size_estimate()
205 + decommitments.size_estimate()
206 + queried_values.size_estimate()
207 + mem::size_of_val(proof_of_work)
208 + fri_proof.size_estimate()
209 + mem::size_of_val(config)
210 }
211}
212
213impl<H: MerkleHasherLifted> SizeEstimate for StarkProof<H> {
214 fn size_estimate(&self) -> usize {
215 let Self(commitment_scheme_proof) = self;
216 commitment_scheme_proof.size_estimate()
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use num_traits::One;
223
224 use crate::core::fields::m31::BaseField;
225 use crate::core::fields::qm31::{SecureField, SECURE_EXTENSION_DEGREE};
226 use crate::core::proof::SizeEstimate;
227
228 #[test]
229 fn test_base_field_size_estimate() {
230 assert_eq!(BaseField::one().size_estimate(), 4);
231 }
232
233 #[test]
234 fn test_secure_field_size_estimate() {
235 assert_eq!(
236 SecureField::one().size_estimate(),
237 4 * SECURE_EXTENSION_DEGREE
238 );
239 }
240}