1use std::{fs::File, path::Path};
2
3use anyhow::Result;
4use clap::ValueEnum;
5use p3_baby_bear::BabyBear;
6use p3_bn254_fr::Bn254Fr;
7use p3_commit::{Pcs, TwoAdicMultiplicativeCoset};
8use p3_field::{AbstractField, PrimeField, PrimeField32, TwoAdicField};
9use serde::{de::DeserializeOwned, Deserialize, Serialize};
10use sp1_core_machine::{io::SP1Stdin, reduce::SP1ReduceProof};
11use sp1_primitives::{io::SP1PublicValues, poseidon2_hash};
12
13use sp1_recursion_circuit::machine::{
14 SP1CompressWitnessValues, SP1DeferredWitnessValues, SP1RecursionWitnessValues,
15};
16
17use sp1_recursion_gnark_ffi::proof::{Groth16Bn254Proof, PlonkBn254Proof};
18
19use sp1_stark::{ShardProof, StarkGenericConfig, StarkProvingKey, StarkVerifyingKey, DIGEST_SIZE};
20use thiserror::Error;
21
22use crate::{
23 utils::{babybears_to_bn254, words_to_bytes_be},
24 CoreSC, InnerSC,
25};
26
27#[derive(Clone, Serialize, Deserialize)]
29pub struct SP1ProvingKey {
30 pub pk: StarkProvingKey<CoreSC>,
31 pub elf: Vec<u8>,
32 pub vk: SP1VerifyingKey,
34}
35
36#[derive(Clone, Serialize, Deserialize)]
38pub struct SP1VerifyingKey {
39 pub vk: StarkVerifyingKey<CoreSC>,
40}
41
42pub trait HashableKey {
44 fn hash_babybear(&self) -> [BabyBear; DIGEST_SIZE];
46
47 fn hash_u32(&self) -> [u32; DIGEST_SIZE];
49
50 fn hash_bn254(&self) -> Bn254Fr {
52 babybears_to_bn254(&self.hash_babybear())
53 }
54
55 fn bytes32(&self) -> String {
59 let vkey_digest_bn254 = self.hash_bn254();
60 format!("0x{:0>64}", vkey_digest_bn254.as_canonical_biguint().to_str_radix(16))
61 }
62
63 fn bytes32_raw(&self) -> [u8; 32] {
67 let vkey_digest_bn254 = self.hash_bn254();
68 let vkey_bytes = vkey_digest_bn254.as_canonical_biguint().to_bytes_be();
69 let mut result = [0u8; 32];
70 result[1..].copy_from_slice(&vkey_bytes);
71 result
72 }
73
74 fn hash_bytes(&self) -> [u8; DIGEST_SIZE * 4] {
76 words_to_bytes_be(&self.hash_u32())
77 }
78}
79
80impl HashableKey for SP1VerifyingKey {
81 fn hash_babybear(&self) -> [BabyBear; DIGEST_SIZE] {
82 self.vk.hash_babybear()
83 }
84
85 fn hash_u32(&self) -> [u32; DIGEST_SIZE] {
86 self.vk.hash_u32()
87 }
88}
89
90impl<SC: StarkGenericConfig<Val = BabyBear, Domain = TwoAdicMultiplicativeCoset<BabyBear>>>
91 HashableKey for StarkVerifyingKey<SC>
92where
93 <SC::Pcs as Pcs<SC::Challenge, SC::Challenger>>::Commitment: AsRef<[BabyBear; DIGEST_SIZE]>,
94{
95 fn hash_babybear(&self) -> [BabyBear; DIGEST_SIZE] {
96 let mut num_inputs = DIGEST_SIZE + 1 + 14 + (7 * self.chip_information.len());
97 for (name, _, _) in self.chip_information.iter() {
98 num_inputs += name.len();
99 }
100 let mut inputs = Vec::with_capacity(num_inputs);
101 inputs.extend(self.commit.as_ref());
102 inputs.push(self.pc_start);
103 inputs.extend(self.initial_global_cumulative_sum.0.x.0);
104 inputs.extend(self.initial_global_cumulative_sum.0.y.0);
105 for (name, domain, dimension) in self.chip_information.iter() {
106 inputs.push(BabyBear::from_canonical_usize(domain.log_n));
107 let size = 1 << domain.log_n;
108 inputs.push(BabyBear::from_canonical_usize(size));
109 let g = BabyBear::two_adic_generator(domain.log_n);
110 inputs.push(domain.shift);
111 inputs.push(g);
112 inputs.push(BabyBear::from_canonical_usize(dimension.width));
113 inputs.push(BabyBear::from_canonical_usize(dimension.height));
114 inputs.push(BabyBear::from_canonical_usize(name.len()));
115 for byte in name.as_bytes() {
116 inputs.push(BabyBear::from_canonical_u8(*byte));
117 }
118 }
119
120 poseidon2_hash(inputs)
121 }
122
123 fn hash_u32(&self) -> [u32; 8] {
124 self.hash_babybear()
125 .into_iter()
126 .map(|n| n.as_canonical_u32())
127 .collect::<Vec<_>>()
128 .try_into()
129 .unwrap()
130 }
131}
132
133#[derive(Serialize, Deserialize, Clone)]
135#[serde(bound(serialize = "P: Serialize"))]
136#[serde(bound(deserialize = "P: DeserializeOwned"))]
137pub struct SP1ProofWithMetadata<P: Clone> {
138 pub proof: P,
139 pub stdin: SP1Stdin,
140 pub public_values: SP1PublicValues,
141 pub cycles: u64,
142}
143
144impl<P: Serialize + DeserializeOwned + Clone> SP1ProofWithMetadata<P> {
145 pub fn save(&self, path: impl AsRef<Path>) -> Result<()> {
146 bincode::serialize_into(File::create(path).expect("failed to open file"), self)
147 .map_err(Into::into)
148 }
149
150 pub fn load(path: impl AsRef<Path>) -> Result<Self> {
151 bincode::deserialize_from(File::open(path).expect("failed to open file"))
152 .map_err(Into::into)
153 }
154}
155
156impl<P: std::fmt::Debug + Clone> std::fmt::Debug for SP1ProofWithMetadata<P> {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 f.debug_struct("SP1ProofWithMetadata").field("proof", &self.proof).finish()
159 }
160}
161
162pub type SP1CoreProof = SP1ProofWithMetadata<SP1CoreProofData>;
164
165pub type SP1ReducedProof = SP1ProofWithMetadata<SP1ReducedProofData>;
168
169pub type SP1PlonkBn254Proof = SP1ProofWithMetadata<SP1PlonkBn254ProofData>;
171
172pub type SP1Groth16Bn254Proof = SP1ProofWithMetadata<SP1Groth16Bn254ProofData>;
174
175pub type SP1Proof = SP1ProofWithMetadata<SP1Bn254ProofData>;
177
178#[derive(Serialize, Deserialize, Clone)]
179pub struct SP1CoreProofData(pub Vec<ShardProof<CoreSC>>);
180
181impl SP1CoreProofData {
182 pub fn save(&self, path: &str) -> Result<(), std::io::Error> {
183 let data = serde_json::to_string(self).unwrap();
184 std::fs::write(path, data).unwrap();
185 Ok(())
186 }
187}
188
189#[derive(Serialize, Deserialize, Clone)]
190pub struct SP1ReducedProofData(pub ShardProof<InnerSC>);
191
192#[derive(Serialize, Deserialize, Clone)]
193pub struct SP1PlonkBn254ProofData(pub PlonkBn254Proof);
194
195#[derive(Serialize, Deserialize, Clone)]
196pub struct SP1Groth16Bn254ProofData(pub Groth16Bn254Proof);
197
198#[derive(Serialize, Deserialize, Clone)]
199pub enum SP1Bn254ProofData {
200 Plonk(PlonkBn254Proof),
201 Groth16(Groth16Bn254Proof),
202}
203
204impl SP1Bn254ProofData {
205 pub fn get_proof_system(&self) -> ProofSystem {
206 match self {
207 SP1Bn254ProofData::Plonk(_) => ProofSystem::Plonk,
208 SP1Bn254ProofData::Groth16(_) => ProofSystem::Groth16,
209 }
210 }
211
212 pub fn get_raw_proof(&self) -> &str {
213 match self {
214 SP1Bn254ProofData::Plonk(proof) => &proof.raw_proof,
215 SP1Bn254ProofData::Groth16(proof) => &proof.raw_proof,
216 }
217 }
218}
219
220#[derive(Debug, Default, Clone, ValueEnum, PartialEq, Eq)]
222pub enum ProverMode {
223 #[default]
224 Cpu,
225 Cuda,
226 Network,
227 Mock,
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq)]
231pub enum ProofSystem {
232 Plonk,
233 Groth16,
234}
235
236impl ProofSystem {
237 pub fn as_str(&self) -> &'static str {
238 match self {
239 ProofSystem::Plonk => "Plonk",
240 ProofSystem::Groth16 => "Groth16",
241 }
242 }
243}
244
245#[derive(Serialize, Deserialize, Clone)]
247pub enum SP1ReduceProofWrapper {
248 Core(SP1ReduceProof<CoreSC>),
249 Recursive(SP1ReduceProof<InnerSC>),
250}
251
252#[derive(Error, Debug)]
253pub enum SP1RecursionProverError {
254 #[error("Runtime error: {0}")]
255 RuntimeError(String),
256}
257
258#[allow(clippy::large_enum_variant)]
259pub enum SP1CircuitWitness {
260 Core(SP1RecursionWitnessValues<CoreSC>),
261 Deferred(SP1DeferredWitnessValues<InnerSC>),
262 Compress(SP1CompressWitnessValues<InnerSC>),
263}