1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use slop_algebra::AbstractField;
5use slop_alloc::{CpuBackend, GLOBAL_CPU_BACKEND};
6use slop_basefold::BasefoldProof;
7use slop_challenger::{GrindingChallenger, IopCtx};
8use slop_commit::Rounds;
9use slop_jagged::{JaggedPcsProof, JaggedSumcheckEvalProof};
10use slop_matrix::dense::RowMajorMatrixView;
11use slop_multilinear::{Mle, MleEval, MultilinearPcsVerifier, Point};
12use slop_sumcheck::PartialSumcheckProof;
13use slop_symmetric::PseudoCompressionFunction;
14use slop_tensor::Tensor;
15use sp1_primitives::{utils::reverse_bits_len, SP1ExtensionField, SP1Field, SP1GlobalContext};
16
17use crate::{
18 LogUpEvaluations, LogUpGkrOutput, LogupGkrProof, MachineVerifyingKey, SP1PcsProof,
19 SP1PcsProofInner, SP1VerifyingKey, ShardContext, DIGEST_SIZE,
20};
21
22pub const PROOF_MAX_NUM_PVS: usize = 187;
26
27#[derive(Clone, Serialize, Deserialize)]
29#[serde(bound(
30 serialize = "GC: IopCtx, GC::Challenger: Serialize",
31 deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>"
32))]
33pub struct TestingData<GC: IopCtx> {
35 pub gkr_points: Vec<Point<GC::EF>>,
37 pub challenger_state: GC::Challenger,
39}
40
41#[derive(Clone, Serialize, Deserialize)]
43#[serde(bound(
44 serialize = "GC: IopCtx, GC::Challenger: Serialize, Proof: Serialize",
45 deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>, Proof: Deserialize<'de>"
46))]
47pub struct ShardProof<GC: IopCtx, Proof> {
48 pub public_values: Vec<GC::F>,
50 pub main_commitment: GC::Digest,
52 pub logup_gkr_proof: LogupGkrProof<<GC::Challenger as GrindingChallenger>::Witness, GC::EF>,
54 pub zerocheck_proof: PartialSumcheckProof<GC::EF>,
56 pub opened_values: ShardOpenedValues<GC::F, GC::EF>,
58 pub evaluation_proof: JaggedPcsProof<GC, Proof>,
60}
61
62pub type ShardContextProof<GC, SC> =
64 ShardProof<GC, <<SC as ShardContext<GC>>::Config as MultilinearPcsVerifier<GC>>::Proof>;
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ShardOpenedValues<F, EF> {
69 pub chips: BTreeMap<String, ChipOpenedValues<F, EF>>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76#[serde(bound(serialize = "F: Serialize, EF: Serialize"))]
77#[serde(bound(deserialize = "F: Deserialize<'de>, EF: Deserialize<'de>"))]
78pub struct ChipOpenedValues<F, EF> {
79 pub preprocessed: AirOpenedValues<EF>,
81 pub main: AirOpenedValues<EF>,
83 pub degree: Point<F>,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89#[serde(bound(serialize = "T: Serialize"))]
90#[serde(bound(deserialize = "T: Deserialize<'de>"))]
91pub struct AirOpenedValues<T> {
92 pub local: Vec<T>,
94}
95
96impl<T> AirOpenedValues<T> {
97 #[must_use]
99 pub fn view(&self) -> RowMajorMatrixView<'_, T>
100 where
101 T: Clone + Send + Sync,
102 {
103 RowMajorMatrixView::new_row(&self.local)
104 }
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct MerkleProof<GC: IopCtx> {
110 pub index: usize,
112 pub path: Vec<GC::Digest>,
114}
115
116#[derive(Debug)]
117pub struct VcsError;
119
120pub fn verify_merkle_proof<GC: IopCtx>(
122 proof: &MerkleProof<GC>,
123 value: GC::Digest,
124 commitment: GC::Digest,
125) -> Result<(), VcsError> {
126 let MerkleProof { index, path } = proof;
127
128 let mut value = value;
129
130 let mut index = reverse_bits_len(*index, path.len());
131
132 for sibling in path {
133 let new_pair = if index.is_multiple_of(2) { [value, *sibling] } else { [*sibling, value] };
135 let (_, compressor) = GC::default_hasher_and_compressor();
136 value = compressor.compress(new_pair);
137 index >>= 1;
138 }
139 if value != commitment {
140 Err(VcsError)
141 } else {
142 Ok(())
143 }
144}
145
146#[derive(Serialize, Deserialize, Clone)]
148#[serde(bound(
149 serialize = "GC: IopCtx, GC::Challenger: Serialize, Proof: Serialize",
150 deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>, Proof: Deserialize<'de>"
151))]
152pub struct SP1RecursionProof<GC: IopCtx, Proof> {
153 pub vk: MachineVerifyingKey<GC>,
155 pub proof: ShardProof<GC, Proof>,
157 pub vk_merkle_proof: MerkleProof<SP1GlobalContext>,
159}
160
161impl<GC: IopCtx, Proof> std::fmt::Debug for SP1RecursionProof<GC, Proof> {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 let mut debug_struct = f.debug_struct("SP1ReduceProof");
164 debug_struct.finish()
168 }
169}
170
171#[derive(Serialize, Deserialize, Clone)]
173#[serde(bound(
174 serialize = "GC: IopCtx, GC::Challenger: Serialize, Proof: Serialize",
175 deserialize = "GC: IopCtx, GC::Challenger: Deserialize<'de>, Proof: Deserialize<'de>"
176))]
177pub struct SP1WrapProof<GC: IopCtx, Proof> {
178 pub vk: MachineVerifyingKey<GC>,
180 pub proof: ShardProof<GC, Proof>,
182}
183
184#[must_use]
190pub fn create_dummy_recursion_proof(
191 vk: &SP1VerifyingKey,
192) -> SP1RecursionProof<SP1GlobalContext, SP1PcsProofInner> {
193 let dummy_query_proof = Vec::new();
198 let basefold_proof = BasefoldProof::<SP1GlobalContext> {
199 univariate_messages: vec![],
200 fri_commitments: vec![],
201 final_poly: SP1ExtensionField::zero(),
202 pow_witness: SP1Field::zero(),
203 batch_grinding_witness: SP1Field::zero(),
204 component_polynomials_query_openings_and_proofs: vec![],
205 query_phase_openings_and_proofs: dummy_query_proof,
206 };
207
208 let batch_evaluations: Rounds<MleEval<SP1ExtensionField, CpuBackend>> = Rounds::default();
209
210 let stacked_proof = SP1PcsProof { basefold_proof, batch_evaluations };
211
212 let jagged_eval_proof =
213 JaggedSumcheckEvalProof { partial_sumcheck_proof: PartialSumcheckProof::dummy() };
214
215 let evaluation_proof = JaggedPcsProof {
216 pcs_proof: stacked_proof,
217 jagged_eval_proof,
218 sumcheck_proof: PartialSumcheckProof::dummy(),
219 merkle_tree_commitments: Rounds::default(),
220 row_counts_and_column_counts: Rounds::default(),
221 expected_eval: SP1ExtensionField::zero(),
222 max_log_row_count: 1,
223 log_m: 1,
224 };
225
226 let empty_tensor: Tensor<SP1ExtensionField, CpuBackend> =
229 Tensor::zeros_in([1], GLOBAL_CPU_BACKEND);
230 let logup_gkr_proof = LogupGkrProof {
231 circuit_output: LogUpGkrOutput {
232 numerator: Mle::new(empty_tensor.clone()),
233 denominator: Mle::new(empty_tensor),
234 },
235 round_proofs: vec![],
236 logup_evaluations: LogUpEvaluations {
237 point: Point::from_usize(0, 1),
238 chip_openings: BTreeMap::new(),
239 },
240 witness: SP1Field::zero(),
241 };
242
243 let dummy_shard_proof = ShardProof {
245 public_values: Vec::new(),
246 main_commitment: [SP1Field::zero(); DIGEST_SIZE],
247 logup_gkr_proof,
248 zerocheck_proof: PartialSumcheckProof::dummy(),
249 opened_values: ShardOpenedValues { chips: BTreeMap::new() },
250 evaluation_proof,
251 };
252
253 SP1RecursionProof {
254 vk: vk.vk.clone(),
255 proof: dummy_shard_proof,
256 vk_merkle_proof: MerkleProof { index: 0, path: vec![] },
257 }
258}