nexus_sdk/stwo/
seq.rs

1use crate::compile::Compile;
2use crate::traits::*;
3
4use serde::{de::DeserializeOwned, Deserialize, Serialize};
5use std::marker::PhantomData;
6use thiserror::Error;
7
8use crate::error::{BuildError, ConfigurationError, IOError, PathError};
9
10/// Errors that occur while proving using Stwo.
11#[derive(Debug, Error)]
12pub enum Error {
13    /// An error occurred during proving a zkVM execution.
14    #[error(transparent)]
15    ProvingError(#[from] nexus_core::stwo::ProvingError),
16
17    /// An error occurred verifying a claimed proof of a zkVM execution.
18    #[error(transparent)]
19    VerificationError(#[from] nexus_core::stwo::VerificationError),
20
21    /// An error occurred building the guest program dynamically.
22    #[error(transparent)]
23    BuildError(#[from] BuildError),
24
25    /// An error occurred reading or writing to the filesystem.
26    #[error(transparent)]
27    HostIOError(#[from] std::io::Error),
28
29    /// An error occurred trying to parse a path for use with the filesystem.
30    #[error(transparent)]
31    PathError(#[from] PathError),
32
33    /// An error occurred reading or writing to the zkVM input/output segments.
34    #[error(transparent)]
35    GuestIOError(#[from] IOError),
36
37    /// An error occured executing the zkVM.
38    #[error(transparent)]
39    VMError(#[from] nexus_core::nvm::VMError),
40
41    /// An error occured loading or parsing the ELF.
42    #[error(transparent)]
43    ElfError(#[from] nexus_core::nvm::ElfError),
44
45    /// An error occured configuring the prover.
46    #[error(transparent)]
47    ConfigurationError(#[from] ConfigurationError),
48}
49
50/// Prover for the Nexus zkVM, when using Stwo.
51pub struct Stwo<C: Compute = Local> {
52    /// The program to be proven.
53    pub elf: nexus_core::nvm::ElfFile,
54    /// The associated data to prove with.
55    pub ad: Vec<u8>,
56    _compute: PhantomData<C>,
57}
58
59/// The Stwo proof, alongside machine configuration information needed for verification.
60#[derive(Serialize, Deserialize)]
61pub struct Proof {
62    proof: nexus_core::stwo::Proof,
63    memory_layout: nexus_core::nvm::internals::LinearMemoryLayout,
64}
65
66impl<C: Compute> ByGuestCompilation for Stwo<C>
67where
68    Stwo<C>: Prover,
69    <Stwo<C> as Prover>::Error: From<BuildError>,
70{
71    /// Construct a new proving instance through dynamic compilation (see [`compile`](crate::compile)).
72    fn compile(compiler: &mut impl Compile) -> Result<Self, <Self as Prover>::Error> {
73        let elf_path = compiler.build()?;
74
75        Self::new_from_file(&elf_path.to_string_lossy().to_string())
76    }
77}
78
79impl Prover for Stwo<Local> {
80    type Proof = Proof;
81    type View = nexus_core::nvm::View;
82    type Error = Error;
83
84    /// Construct a new proving instance.
85    fn new(elf: &nexus_core::nvm::ElfFile) -> Result<Self, <Self as Prover>::Error> {
86        Ok(Self {
87            elf: elf.clone(),
88            ad: Vec::new(),
89            _compute: PhantomData,
90        })
91    }
92
93    /// Set the associated data bytes to be bound into the proof.
94    fn set_associated_data(&mut self, ad: &[u8]) -> Result<(), <Self as Prover>::Error> {
95        self.ad = ad.to_vec();
96        Ok(())
97    }
98
99    /// Run the zkVM on private input of type `S` and public input of type `T` and return a view of the execution output.
100    fn run_with_input<S: Serialize + Sized, T: Serialize + DeserializeOwned + Sized>(
101        &self,
102        private_input: &S,
103        public_input: &T,
104    ) -> Result<Self::View, <Self as Prover>::Error> {
105        let mut private_encoded = postcard::to_stdvec(&private_input).map_err(IOError::from)?;
106        if !private_encoded.is_empty() {
107            let private = private_input.to_owned();
108
109            private_encoded = postcard::to_stdvec_cobs(&private).map_err(IOError::from)?;
110            let private_padded_len = (private_encoded.len() + 3) & !3;
111
112            assert!(private_padded_len >= private_encoded.len());
113            private_encoded.resize(private_padded_len, 0x00); // cobs ignores 0x00 padding
114        }
115
116        let mut public_encoded = postcard::to_stdvec(&public_input).map_err(IOError::from)?;
117        if !public_encoded.is_empty() {
118            let public = public_input.to_owned();
119
120            public_encoded = postcard::to_stdvec_cobs(&public).map_err(IOError::from)?;
121            let public_padded_len = (public_encoded.len() + 3) & !3;
122
123            assert!(public_padded_len >= public_encoded.len());
124            public_encoded.resize(public_padded_len, 0x00); // cobs ignores 0x00 padding
125        }
126
127        let (view, _) = nexus_core::nvm::k_trace(
128            self.elf.clone(),
129            self.ad.as_slice(),
130            public_encoded.as_slice(),
131            private_encoded.as_slice(),
132            1,
133        )?; // todo: run without tracing?
134
135        Ok(view)
136    }
137
138    /// Run the zkVM on private input of type `S` and public input of type `T` and return a verifiable proof, along with a view of the execution output.
139    fn prove_with_input<S: Serialize + Sized, T: Serialize + DeserializeOwned + Sized>(
140        self,
141        private_input: &S,
142        public_input: &T,
143    ) -> Result<(Self::View, Self::Proof), <Self as Prover>::Error> {
144        let mut private_encoded = postcard::to_stdvec(&private_input).map_err(IOError::from)?;
145        if !private_encoded.is_empty() {
146            let private = private_input.to_owned();
147
148            private_encoded = postcard::to_stdvec_cobs(&private).map_err(IOError::from)?;
149            let private_padded_len = (private_encoded.len() + 3) & !3;
150
151            assert!(private_padded_len >= private_encoded.len());
152            private_encoded.resize(private_padded_len, 0x00); // cobs ignores 0x00 padding
153        }
154
155        let mut public_encoded = postcard::to_stdvec(&public_input).map_err(IOError::from)?;
156        if !public_encoded.is_empty() {
157            let public = public_input.to_owned();
158
159            public_encoded = postcard::to_stdvec_cobs(&public).map_err(IOError::from)?;
160            let public_padded_len = (public_encoded.len() + 3) & !3;
161
162            assert!(public_padded_len >= public_encoded.len());
163            public_encoded.resize(public_padded_len, 0x00); // cobs ignores 0x00 padding
164        }
165
166        let (view, trace) = nexus_core::nvm::k_trace(
167            self.elf.clone(),
168            self.ad.as_slice(),
169            public_encoded.as_slice(),
170            private_encoded.as_slice(),
171            1,
172        )?;
173        let proof = nexus_core::stwo::prove(&trace, &view)?;
174
175        Ok((
176            view,
177            Proof {
178                proof,
179                memory_layout: trace.memory_layout,
180            },
181        ))
182    }
183}
184
185impl Verifiable for Proof {
186    type View = nexus_core::nvm::View;
187    type Error = Error;
188
189    fn get_memory_layout(&self) -> &nexus_core::nvm::internals::LinearMemoryLayout {
190        &self.memory_layout
191    }
192
193    fn verify(&self, view: &Self::View) -> Result<(), <Self as Verifiable>::Error> {
194        nexus_core::stwo::verify(self.proof.clone(), view)?;
195        Ok(())
196    }
197
198    fn size_estimate(&self) -> usize {
199        self.proof.size_estimate()
200    }
201}