sp1_prover/
types.rs

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/// The information necessary to generate a proof for a given RISC-V program.
28#[derive(Clone, Serialize, Deserialize)]
29pub struct SP1ProvingKey {
30    pub pk: StarkProvingKey<CoreSC>,
31    pub elf: Vec<u8>,
32    /// Verifying key is also included as we need it for recursion
33    pub vk: SP1VerifyingKey,
34}
35
36/// The information necessary to verify a proof for a given RISC-V program.
37#[derive(Clone, Serialize, Deserialize)]
38pub struct SP1VerifyingKey {
39    pub vk: StarkVerifyingKey<CoreSC>,
40}
41
42/// A trait for keys that can be hashed into a digest.
43pub trait HashableKey {
44    /// Hash the key into a digest of BabyBear elements.
45    fn hash_babybear(&self) -> [BabyBear; DIGEST_SIZE];
46
47    /// Hash the key into a digest of u32 elements.
48    fn hash_u32(&self) -> [u32; DIGEST_SIZE];
49
50    /// Hash the key into a Bn254Fr element.
51    fn hash_bn254(&self) -> Bn254Fr {
52        babybears_to_bn254(&self.hash_babybear())
53    }
54
55    /// Hash the key into a 32 byte hex string, prefixed with "0x".
56    ///
57    /// This is ideal for generating a vkey hash for onchain verification.
58    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    /// Hash the key into a 32 byte array.
64    ///
65    /// This has the same value as `bytes32`, but as a raw byte array.
66    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    /// Hash the key into a digest of bytes elements.
75    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 prep_domains = self.chip_information.iter().map(|(_, domain, _)| domain);
97        let num_inputs = DIGEST_SIZE + 1 + 14 + (4 * prep_domains.len());
98        let mut inputs = Vec::with_capacity(num_inputs);
99        inputs.extend(self.commit.as_ref());
100        inputs.push(self.pc_start);
101        inputs.extend(self.initial_global_cumulative_sum.0.x.0);
102        inputs.extend(self.initial_global_cumulative_sum.0.y.0);
103        for domain in prep_domains {
104            inputs.push(BabyBear::from_canonical_usize(domain.log_n));
105            let size = 1 << domain.log_n;
106            inputs.push(BabyBear::from_canonical_usize(size));
107            let g = BabyBear::two_adic_generator(domain.log_n);
108            inputs.push(domain.shift);
109            inputs.push(g);
110        }
111
112        poseidon2_hash(inputs)
113    }
114
115    fn hash_u32(&self) -> [u32; 8] {
116        self.hash_babybear()
117            .into_iter()
118            .map(|n| n.as_canonical_u32())
119            .collect::<Vec<_>>()
120            .try_into()
121            .unwrap()
122    }
123}
124
125/// A proof of a RISCV ELF execution with given inputs and outputs.
126#[derive(Serialize, Deserialize, Clone)]
127#[serde(bound(serialize = "P: Serialize"))]
128#[serde(bound(deserialize = "P: DeserializeOwned"))]
129pub struct SP1ProofWithMetadata<P: Clone> {
130    pub proof: P,
131    pub stdin: SP1Stdin,
132    pub public_values: SP1PublicValues,
133    pub cycles: u64,
134}
135
136impl<P: Serialize + DeserializeOwned + Clone> SP1ProofWithMetadata<P> {
137    pub fn save(&self, path: impl AsRef<Path>) -> Result<()> {
138        bincode::serialize_into(File::create(path).expect("failed to open file"), self)
139            .map_err(Into::into)
140    }
141
142    pub fn load(path: impl AsRef<Path>) -> Result<Self> {
143        bincode::deserialize_from(File::open(path).expect("failed to open file"))
144            .map_err(Into::into)
145    }
146}
147
148impl<P: std::fmt::Debug + Clone> std::fmt::Debug for SP1ProofWithMetadata<P> {
149    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150        f.debug_struct("SP1ProofWithMetadata").field("proof", &self.proof).finish()
151    }
152}
153
154/// A proof of an SP1 program without any wrapping.
155pub type SP1CoreProof = SP1ProofWithMetadata<SP1CoreProofData>;
156
157/// An SP1 proof that has been recursively reduced into a single proof. This proof can be verified
158/// within SP1 programs.
159pub type SP1ReducedProof = SP1ProofWithMetadata<SP1ReducedProofData>;
160
161/// An SP1 proof that has been wrapped into a single PLONK proof and can be verified onchain.
162pub type SP1PlonkBn254Proof = SP1ProofWithMetadata<SP1PlonkBn254ProofData>;
163
164/// An SP1 proof that has been wrapped into a single Groth16 proof and can be verified onchain.
165pub type SP1Groth16Bn254Proof = SP1ProofWithMetadata<SP1Groth16Bn254ProofData>;
166
167/// An SP1 proof that has been wrapped into a single proof and can be verified onchain.
168pub type SP1Proof = SP1ProofWithMetadata<SP1Bn254ProofData>;
169
170#[derive(Serialize, Deserialize, Clone)]
171pub struct SP1CoreProofData(pub Vec<ShardProof<CoreSC>>);
172
173#[derive(Serialize, Deserialize, Clone)]
174pub struct SP1ReducedProofData(pub ShardProof<InnerSC>);
175
176#[derive(Serialize, Deserialize, Clone)]
177pub struct SP1PlonkBn254ProofData(pub PlonkBn254Proof);
178
179#[derive(Serialize, Deserialize, Clone)]
180pub struct SP1Groth16Bn254ProofData(pub Groth16Bn254Proof);
181
182#[derive(Serialize, Deserialize, Clone)]
183pub enum SP1Bn254ProofData {
184    Plonk(PlonkBn254Proof),
185    Groth16(Groth16Bn254Proof),
186}
187
188impl SP1Bn254ProofData {
189    pub fn get_proof_system(&self) -> ProofSystem {
190        match self {
191            SP1Bn254ProofData::Plonk(_) => ProofSystem::Plonk,
192            SP1Bn254ProofData::Groth16(_) => ProofSystem::Groth16,
193        }
194    }
195
196    pub fn get_raw_proof(&self) -> &str {
197        match self {
198            SP1Bn254ProofData::Plonk(proof) => &proof.raw_proof,
199            SP1Bn254ProofData::Groth16(proof) => &proof.raw_proof,
200        }
201    }
202}
203
204/// The mode of the prover.
205#[derive(Debug, Default, Clone, ValueEnum, PartialEq, Eq)]
206pub enum ProverMode {
207    #[default]
208    Cpu,
209    Cuda,
210    Network,
211    Mock,
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
215pub enum ProofSystem {
216    Plonk,
217    Groth16,
218}
219
220impl ProofSystem {
221    pub fn as_str(&self) -> &'static str {
222        match self {
223            ProofSystem::Plonk => "Plonk",
224            ProofSystem::Groth16 => "Groth16",
225        }
226    }
227}
228
229/// A proof that can be reduced along with other proofs into one proof.
230#[derive(Serialize, Deserialize, Clone)]
231pub enum SP1ReduceProofWrapper {
232    Core(SP1ReduceProof<CoreSC>),
233    Recursive(SP1ReduceProof<InnerSC>),
234}
235
236#[derive(Error, Debug)]
237pub enum SP1RecursionProverError {
238    #[error("Runtime error: {0}")]
239    RuntimeError(String),
240}
241
242#[allow(clippy::large_enum_variant)]
243pub enum SP1CircuitWitness {
244    Core(SP1RecursionWitnessValues<CoreSC>),
245    Deferred(SP1DeferredWitnessValues<InnerSC>),
246    Compress(SP1CompressWitnessValues<InnerSC>),
247}