nexus_sdk/legacy/nova/
seq.rs

1use crate::legacy::compile;
2use crate::legacy::traits::*;
3use crate::legacy::views::UncheckedView;
4use crate::traits::*;
5
6use crate::legacy::ark_serialize_utils::{ark_de, ark_se};
7use serde::{de::DeserializeOwned, Deserialize, Serialize};
8use std::path::Path;
9use thiserror::Error;
10
11use nexus_core_legacy::nvm::interactive::{eval, parse_elf, trace};
12use nexus_core_legacy::nvm::memory::MerkleTrie;
13use nexus_core_legacy::nvm::NexusVM;
14use nexus_core_legacy::prover::nova::pp::{gen_vm_pp, load_pp, save_pp};
15use nexus_core_legacy::prover::nova::prove_seq;
16use nexus_core_legacy::prover::nova::types::IVCProof;
17
18use crate::error::{BuildError, ConfigurationError, IOError, PathError};
19use nexus_core_legacy::prover::nova::error::ProofError;
20
21// re-exports
22/// Public parameters used to prove and verify zkVM executions.
23pub use nexus_core_legacy::prover::nova::types::SeqPP as PP;
24
25use std::marker::PhantomData;
26
27// hard-coded number of vm instructions to pack per recursion step
28const K: usize = 16;
29
30/// Errors that occur while proving using Nova.
31#[derive(Debug, Error)]
32pub enum Error {
33    /// An error occurred during parameter generation, execution, proving, or proof verification for the zkVM.
34    #[error(transparent)]
35    ProofError(#[from] ProofError),
36
37    /// An error occurred building the guest program dynamically.
38    #[error(transparent)]
39    BuildError(#[from] BuildError),
40
41    /// An error occurred reading or writing to the filesystem.
42    #[error(transparent)]
43    HostIOError(#[from] std::io::Error),
44
45    /// An error occurred trying to parse a path for use with the filesystem.
46    #[error(transparent)]
47    PathError(#[from] PathError),
48
49    /// An error occurred reading or writing to the zkVM input/output tapes.
50    #[error(transparent)]
51    GuestIOError(#[from] IOError),
52
53    /// An error occured configuring the prover.
54    #[error(transparent)]
55    ConfigurationError(#[from] ConfigurationError),
56}
57
58/// Prover for the Nexus zkVM using Nova.
59pub struct Nova<'a, C: Compute = Local> {
60    vm: NexusVM<MerkleTrie>,
61    pp: Option<&'a PP>,
62    _compute: PhantomData<C>,
63}
64
65/// A verifiable proof of a zkVM execution. Also contains a view capturing the output of the machine.
66///
67/// **Warning**: The proof contains an _unchecked_ view. Please review [`UncheckedView`].
68#[derive(Serialize, Deserialize)]
69pub struct Proof<'a> {
70    #[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
71    proof: IVCProof,
72    #[serde(skip)]
73    view: UncheckedView,
74    #[serde(skip)]
75    pp: Option<&'a PP>,
76}
77
78macro_rules! setup {
79    ($id:ty) => {
80        impl<'a> Setup<'a> for $id {
81            type Reference = ();
82            type Parameters = PP;
83            type Preprocessing = ();
84            type Error = Error;
85
86            fn setup_reference<'b: 'a>(
87                &mut self,
88                _reference: &'b Self::Reference,
89            ) -> Result<(), Self::Error> {
90                return Err(Error::from(ConfigurationError::NotApplicableOperation));
91            }
92
93            fn setup_parameters<'b: 'a>(
94                &mut self,
95                parameters: &'b Self::Parameters,
96            ) -> Result<(), Self::Error> {
97                self.pp = Some(parameters);
98                Ok(())
99            }
100
101            fn detach(&mut self) {
102                self.pp = None;
103            }
104
105            fn reference(&self) -> Result<&'a Self::Reference, Self::Error> {
106                Ok(&())
107            }
108
109            fn parameters(&self) -> Result<&'a Self::Parameters, Self::Error> {
110                if self.pp.is_none() {
111                    return Err(Error::from(ConfigurationError::NotYetConfigured));
112                } else {
113                    Ok(self.pp.unwrap())
114                }
115            }
116
117            fn preprocessing(&self) -> Result<Self::Preprocessing, Self::Error> {
118                Ok(())
119            }
120        }
121    };
122}
123
124setup!(Nova<'a, Local>);
125setup!(Proof<'a>);
126
127impl<'a> LegacyProver<'a> for Nova<'a, Local> {
128    type Proof = Proof<'a>;
129    type View = UncheckedView;
130
131    fn new(elf_bytes: &[u8]) -> Result<Self, Self::Error> {
132        Ok(Nova::<Local> {
133            vm: parse_elf::<MerkleTrie>(elf_bytes).map_err(ProofError::from)?,
134            pp: None,
135            _compute: PhantomData,
136        })
137    }
138
139    fn compile(opts: &compile::CompileOpts) -> Result<Self, Self::Error> {
140        let mut iopts = opts.to_owned();
141
142        // if the user has not set the memory limit, default to 4mb
143        if iopts.memlimit.is_none() {
144            iopts.set_memlimit(4);
145        }
146
147        let elf_path = iopts.build(&compile::ForProver::Default)?;
148
149        Self::new_from_file(&elf_path)
150    }
151
152    fn run_with_input<S>(mut self, private_input: &S) -> Result<Self::View, Self::Error>
153    where
154        S: Serialize + Sized,
155    {
156        self.vm.syscalls.set_input(
157            postcard::to_stdvec(private_input)
158                .map_err(IOError::from)?
159                .as_slice(),
160        );
161
162        eval(&mut self.vm, false, false).map_err(ProofError::from)?;
163
164        Ok(Self::View {
165            out: self.vm.syscalls.get_output(),
166            logs: self
167                .vm
168                .syscalls
169                .get_log_buffer()
170                .into_iter()
171                .map(String::from_utf8)
172                .collect::<Result<Vec<_>, _>>()
173                .map_err(IOError::from)?,
174        })
175    }
176
177    fn prove_with_input<S>(mut self, private_input: &S) -> Result<Self::Proof, Self::Error>
178    where
179        S: Serialize + Sized,
180    {
181        if self.pp.is_none() {
182            return Err(Error::from(ConfigurationError::NotYetConfigured));
183        }
184
185        self.vm.syscalls.set_input(
186            postcard::to_stdvec(private_input)
187                .map_err(IOError::from)?
188                .as_slice(),
189        );
190
191        let tr = trace(&mut self.vm, K, false).map_err(ProofError::from)?;
192
193        Ok(Self::Proof {
194            proof: prove_seq(self.pp.as_ref().unwrap(), tr)?,
195            pp: self.pp,
196            view: Self::View {
197                out: self.vm.syscalls.get_output(),
198                logs: self
199                    .vm
200                    .syscalls
201                    .get_log_buffer()
202                    .into_iter()
203                    .map(String::from_utf8)
204                    .collect::<Result<Vec<_>, _>>()
205                    .map_err(IOError::from)?,
206            },
207        })
208    }
209}
210
211impl Parameters for PP {
212    type Ref = ();
213    type Error = Error;
214
215    fn generate(_reference: &Self::Ref) -> Result<Self, Self::Error> {
216        eprintln!("Using test parameter generation, not for production use!!!");
217        Ok(gen_vm_pp(K, &())?)
218    }
219
220    fn load(path: &Path) -> Result<Self, Self::Error> {
221        if let Some(path_str) = path.to_str() {
222            return Ok(load_pp(path_str)?);
223        }
224
225        Err(Self::Error::PathError(
226            crate::error::PathError::EncodingError,
227        ))
228    }
229
230    fn save(pp: &Self, path: &Path) -> Result<(), Self::Error> {
231        if let Some(path_str) = path.to_str() {
232            return Ok(save_pp(pp, path_str)?);
233        }
234
235        Err(Self::Error::PathError(
236            crate::error::PathError::EncodingError,
237        ))
238    }
239}
240
241impl<'a> LegacyVerifiable<'a> for Proof<'a> {
242    type View = UncheckedView;
243
244    fn output<U: DeserializeOwned>(&self) -> Result<U, Self::Error> {
245        Ok(Self::View::output::<U>(&self.view)?)
246    }
247
248    fn logs(&self) -> &Vec<String> {
249        Self::View::logs(&self.view)
250    }
251
252    fn detach(&mut self) {
253        self.pp = None;
254    }
255
256    fn verify(&self) -> Result<(), Self::Error> {
257        if self.pp.is_none() {
258            return Err(Error::from(ConfigurationError::NotYetConfigured));
259        }
260
261        Ok(self
262            .proof
263            .verify(self.pp.as_ref().unwrap())
264            .map_err(ProofError::from)?)
265    }
266}