nexus_sdk/
traits.rs

1#![allow(deprecated)]
2
3use crypto::digest::{Digest, OutputSizeUser};
4use crypto_common::generic_array::{ArrayLength, GenericArray};
5use nexus_common::constants::WORD_SIZE;
6use serde::{de::DeserializeOwned, Serialize};
7use std::path::Path;
8
9use nexus_core::nvm::internals::*;
10
11use crate::compile::*;
12use crate::error::*;
13
14/// A compute resource.
15pub trait Compute {}
16
17/// Use local compute to prove the zkVM.
18pub enum Local {}
19impl Compute for Local {}
20
21/// A view of an execution, the correctness of which is guaranteed by the proving and checked by the verification.
22pub trait CheckedView {
23    /// Rebuild from constitutent parts, for use by the verifier during verification.
24    fn new_from_expected(
25        memory_layout: &LinearMemoryLayout,
26        expected_public_input: &[u8],
27        expected_exit_code: &[u8],
28        expected_public_output: &[u8],
29        expected_elf: &nexus_core::nvm::ElfFile,
30        expected_ad: &[u8],
31    ) -> Self;
32}
33
34impl CheckedView for nexus_core::nvm::View {
35    fn new_from_expected(
36        memory_layout: &LinearMemoryLayout,
37        expected_public_input: &[u8],
38        expected_exit_code: &[u8],
39        expected_public_output: &[u8],
40        expected_elf: &nexus_core::nvm::ElfFile,
41        expected_ad: &[u8],
42    ) -> Self {
43        let emulator = LinearEmulator::default();
44
45        // Replace custom instructions `rin` and `wou` with `lw` and `sw`.
46        let instructions = expected_elf
47            .instructions
48            .iter()
49            .map(|instr| convert_instruction(&emulator.executor.instruction_executor, instr))
50            .collect();
51
52        let converted_elf = nexus_core::nvm::ElfFile {
53            instructions,
54            ..expected_elf.clone()
55        };
56
57        let program_memory = elf_into_program_info(&converted_elf, memory_layout);
58
59        let input_memory = slice_into_io_entries::<MemoryInitializationEntry>(
60            memory_layout.public_input_start(),
61            &[
62                &(expected_public_input.len() as u32).to_le_bytes(),
63                expected_public_input,
64            ]
65            .concat(),
66        );
67
68        let ro_initial_memory = slice_into_io_entries::<MemoryInitializationEntry>(
69            memory_layout.public_input_address_location(),
70            &[
71                memory_layout.public_input_start().to_le_bytes(),
72                memory_layout.exit_code().to_le_bytes(), // the exit code is the first word of the output
73            ]
74            .concat(),
75        )
76        .iter()
77        .chain(map_into_io_entries::<MemoryInitializationEntry>(&expected_elf.rom_image).iter())
78        .copied()
79        .collect();
80
81        let rw_initial_memory =
82            map_into_io_entries::<MemoryInitializationEntry>(&expected_elf.ram_image);
83
84        let exit_code = slice_into_io_entries::<PublicOutputEntry>(
85            memory_layout.exit_code(),
86            expected_exit_code,
87        );
88
89        let output_memory = slice_into_io_entries::<PublicOutputEntry>(
90            memory_layout.public_output_start(),
91            expected_public_output,
92        );
93
94        let static_memory_size =
95            (expected_elf.rom_image.len_bytes() + expected_elf.ram_image.len_bytes()) * WORD_SIZE;
96
97        Self::new(
98            &Some(*memory_layout),
99            &Vec::new(),
100            &program_memory,
101            &ro_initial_memory,
102            &rw_initial_memory,
103            &input_memory,
104            memory_layout.tracked_ram_size(static_memory_size),
105            &exit_code,
106            &output_memory,
107            &expected_ad.to_vec(),
108        )
109    }
110}
111
112/// A view of an execution capturing the context needed for proof distribution and verification.
113pub trait Viewable {
114    /// Deserialize the public input used for the execution.
115    fn public_input<T: Serialize + DeserializeOwned + Sized>(&self) -> Result<T, IOError>;
116
117    /// Compute a digest over the public input used for the execution.
118    fn public_input_digest<T: Serialize + DeserializeOwned + Sized, H: Digest>(
119        &self,
120    ) -> Result<GenericArray<u8, H::OutputSize>, IOError>
121    where
122        <H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
123    {
124        Ok(H::digest(
125            postcard::to_stdvec_cobs::<T>(&Self::public_input::<T>(self)?)
126                .map_err(IOError::from)?
127                .as_slice(),
128        ))
129    }
130
131    /// Deserialize the exit code resulting from the execution.
132    fn exit_code(&self) -> Result<u32, IOError>;
133
134    /// Compute a digest over the public output resulting from the execution.
135    fn exit_code_digest<H: Digest>(&self) -> Result<GenericArray<u8, H::OutputSize>, IOError>
136    where
137        <H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
138    {
139        Ok(H::digest(Self::exit_code(self)?.to_le_bytes()))
140    }
141
142    /// Deserialize the public output resulting from the execution.
143    fn public_output<U: Serialize + DeserializeOwned + Sized>(&self) -> Result<U, IOError>;
144
145    /// Compute a digest over the public output resulting from the execution.
146    fn public_output_digest<U: Serialize + DeserializeOwned + Sized, H: Digest>(
147        &self,
148    ) -> Result<GenericArray<u8, H::OutputSize>, IOError>
149    where
150        <H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
151    {
152        Ok(H::digest(
153            postcard::to_stdvec_cobs::<U>(&Self::public_output::<U>(self)?)
154                .map_err(IOError::from)?
155                .as_slice(),
156        ))
157    }
158
159    /// Deserialize the associated data bound into the execution.
160    fn associated_data(&self) -> Result<Vec<u8>, IOError>;
161
162    /// Compute a digest over the associated data bound into the execution.
163    fn associated_data_digest<H: Digest>(&self) -> Result<GenericArray<u8, H::OutputSize>, IOError>
164    where
165        <H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
166    {
167        Ok(H::digest(Self::associated_data(self)?.as_slice()))
168    }
169
170    /// Recover any debug logs produced by the execution.
171    fn logs(&self) -> Result<Vec<String>, IOError>;
172}
173
174impl Viewable for nexus_core::nvm::View {
175    /// Deserialize the public input used for the execution.
176    fn public_input<T: Serialize + DeserializeOwned + Sized>(&self) -> Result<T, IOError> {
177        if let Some(mut bytes) = self.view_public_input() {
178            Ok(postcard::from_bytes_cobs::<T>(&mut bytes).map_err(IOError::from)?)
179        } else {
180            Err(IOError::NotYetAvailableError)
181        }
182    }
183
184    /// Deserialize the exit code resulting from the execution.
185    fn exit_code(&self) -> Result<u32, IOError> {
186        if let Some(bytes) = self.view_exit_code() {
187            Ok(postcard::from_bytes::<u32>(&bytes).map_err(IOError::from)?)
188        } else {
189            Err(IOError::NotYetAvailableError)
190        }
191    }
192
193    /// Deserialize the public output resulting from the execution.
194    fn public_output<U: Serialize + DeserializeOwned + Sized>(&self) -> Result<U, IOError> {
195        if let Some(mut bytes) = self.view_public_output() {
196            Ok(postcard::from_bytes_cobs::<U>(&mut bytes).map_err(IOError::from)?)
197        } else {
198            Err(IOError::NotYetAvailableError)
199        }
200    }
201
202    /// Deserialize the associated data bound into the execution.
203    fn associated_data(&self) -> Result<Vec<u8>, IOError> {
204        if let Some(bytes) = self.view_associated_data() {
205            Ok(bytes)
206        } else {
207            Err(IOError::NotYetAvailableError)
208        }
209    }
210
211    /// Recover any debug logs produced by the execution.
212    fn logs(&self) -> Result<Vec<String>, IOError> {
213        if let Some(bytes_vecs) = self.view_debug_logs() {
214            Ok(bytes_vecs
215                .iter()
216                .map(|raw_log: &Vec<u8>| String::from_utf8_lossy(raw_log).to_string())
217                .collect())
218        } else {
219            Err(IOError::NotYetAvailableError)
220        }
221    }
222}
223
224/// A proving instance that can be constructed through compiling a guest program.
225pub trait ByGuestCompilation: Prover {
226    /// Construct a new proving instance through dynamic compilation (see [`compile`](crate::compile)).
227    fn compile(compiler: &mut impl Compile) -> Result<Self, Self::Error>;
228}
229
230/// A prover for the zkVM.
231pub trait Prover: Sized {
232    type Proof: Verifiable;
233    type View: CheckedView;
234    type Error: From<nexus_core::nvm::VMError>;
235
236    /// Construct a new proving instance.
237    fn new(elf: &nexus_core::nvm::ElfFile) -> Result<Self, <Self as Prover>::Error>;
238
239    /// Construct a new proving instance from raw ELF bytes.
240    fn new_from_bytes(elf_bytes: &[u8]) -> Result<Self, <Self as Prover>::Error> {
241        Self::new(&nexus_core::nvm::ElfFile::from_bytes(elf_bytes)?)
242    }
243
244    /// Construct a new proving instance by reading an ELF file.
245    fn new_from_file<P: AsRef<Path> + ?Sized>(path: &P) -> Result<Self, <Self as Prover>::Error> {
246        Self::new(&nexus_core::nvm::ElfFile::from_path(&path)?)
247    }
248
249    /// Set the associated data bytes to be bound into the proof.
250    fn set_associated_data(&mut self, ad: &[u8]) -> Result<(), <Self as Prover>::Error>;
251
252    /// Run the zkVM and return a view of the execution output.
253    fn run(&self) -> Result<Self::View, <Self as Prover>::Error> {
254        Self::run_with_input::<(), ()>(self, &(), &())
255    }
256
257    /// Run the zkVM on private input of type `S` and public input of type `T` and return a view of the execution output.
258    fn run_with_input<S: Serialize + Sized, T: Serialize + DeserializeOwned + Sized>(
259        &self,
260        private_input: &S,
261        public_input: &T,
262    ) -> Result<Self::View, <Self as Prover>::Error>;
263
264    /// Run the zkVM and return a verifiable proof, along with a view of the execution output.
265    fn prove(self) -> Result<(Self::View, Self::Proof), <Self as Prover>::Error> {
266        Self::prove_with_input::<(), ()>(self, &(), &())
267    }
268
269    /// 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.
270    fn prove_with_input<S: Serialize + Sized, T: Serialize + DeserializeOwned + Sized>(
271        self,
272        private_input: &S,
273        public_input: &T,
274    ) -> Result<(Self::View, Self::Proof), <Self as Prover>::Error>;
275
276    /// Helper function to encode input data with COBS encoding and padding.
277    /// This is a default implementation that can be used by all provers.
278    fn encode_input<T: Serialize>(input: &T) -> Result<Vec<u8>, IOError> {
279        let mut encoded = postcard::to_stdvec(input).map_err(IOError::from)?;
280        if !encoded.is_empty() {
281            encoded = postcard::to_stdvec_cobs(input).map_err(IOError::from)?;
282            let padded_len = (encoded.len() + 3) & !3;
283
284            assert!(padded_len >= encoded.len());
285            encoded.resize(padded_len, 0x00); // cobs ignores 0x00 padding
286        }
287        Ok(encoded)
288    }
289}
290
291/// An object that can be configured with necessary parameters for proving and verification.
292///
293/// Currently only used by the legacy prover integrations.
294pub trait Setup<'a> {
295    /// Global parameters with trust assumptions.
296    type Reference;
297    /// Global parameters without trust assumptions.
298    type Parameters;
299    /// Program-specific parameters.
300    type Preprocessing;
301    type Error;
302
303    /// Configure reference string.
304    fn setup_reference<'b: 'a>(
305        &mut self,
306        reference: &'b Self::Reference,
307    ) -> Result<(), Self::Error>;
308
309    /// Configure parameters string.
310    fn setup_parameters<'b: 'a>(
311        &mut self,
312        parameters: &'b Self::Parameters,
313    ) -> Result<(), Self::Error>;
314
315    /// Detach prover or proof from setup to make it easier to pass around without needing to manage lifetimes.
316    fn detach(&mut self);
317
318    /// Access reference through borrow.
319    fn reference(&self) -> Result<&'a Self::Reference, Self::Error>;
320
321    // todo: add support for reference digest
322
323    /// Access parameters through borrow.
324    fn parameters(&self) -> Result<&'a Self::Parameters, Self::Error>;
325
326    // todo: add support for parameters digest
327
328    /// Return preprocessing.
329    fn preprocessing(&self) -> Result<Self::Preprocessing, Self::Error>;
330
331    // todo: add support for preprocessing digest
332}
333
334/// A global, trust-assumption-reliant parameter set used for proving and verifying, such as a common or structured reference string (CRS/SRS).
335///
336/// Currently only used by the legacy prover integrations.
337pub trait Reference {
338    type Error;
339
340    /// Generate reference.
341    fn generate() -> Result<Self, Self::Error>
342    where
343        Self: Sized;
344
345    /// Load reference from a file.
346    fn load(path: &Path) -> Result<Self, Self::Error>
347    where
348        Self: Sized;
349
350    /// Save reference to a file.
351    fn save(reference: &Self, path: &Path) -> Result<(), Self::Error>;
352}
353
354impl Reference for () {
355    type Error = ConfigurationError;
356
357    fn generate() -> Result<Self, Self::Error> {
358        Err(ConfigurationError::NotApplicableOperation)
359    }
360
361    fn load(_path: &Path) -> Result<Self, Self::Error> {
362        Err(ConfigurationError::NotApplicableOperation)
363    }
364
365    fn save(_reference: &Self, _path: &Path) -> Result<(), Self::Error> {
366        Err(ConfigurationError::NotApplicableOperation)
367    }
368}
369
370/// A global, no-trust-assumption parameter set used for proving and verifying.
371///
372/// Currently only used by the legacy prover integrations.
373pub trait Parameters {
374    type Ref: Reference;
375    type Error;
376
377    /// Generate parameters.
378    fn generate(reference: &Self::Ref) -> Result<Self, Self::Error>
379    where
380        Self: Sized;
381
382    /// Load parameters from a file.
383    fn load(path: &Path) -> Result<Self, Self::Error>
384    where
385        Self: Sized;
386
387    /// Save parameters to a file.
388    fn save(parameters: &Self, path: &Path) -> Result<(), Self::Error>;
389}
390
391impl Parameters for () {
392    type Ref = ();
393    type Error = ConfigurationError;
394
395    fn generate(_reference: &Self::Ref) -> Result<Self, Self::Error> {
396        Err(ConfigurationError::NotApplicableOperation)
397    }
398
399    fn load(_path: &Path) -> Result<Self, Self::Error> {
400        Err(ConfigurationError::NotApplicableOperation)
401    }
402
403    fn save(_parameters: &Self, _path: &Path) -> Result<(), Self::Error> {
404        Err(ConfigurationError::NotApplicableOperation)
405    }
406}
407
408/// A program-specific preprocessing parameter set.
409///
410/// Currently only used by the legacy prover integrations.
411pub trait Preprocessing {
412    type Ref: Reference;
413    type Params: Parameters;
414    type Error;
415
416    /// Load preprocessing from a file.
417    fn load(path: &Path) -> Result<Self, Self::Error>
418    where
419        Self: Sized;
420
421    /// Save preprocessing to a file.
422    fn save(preprocessing: &Self, path: &Path) -> Result<(), Self::Error>;
423}
424
425impl Preprocessing for () {
426    type Ref = ();
427    type Params = ();
428    type Error = ConfigurationError;
429
430    fn load(_path: &Path) -> Result<Self, Self::Error> {
431        Err(ConfigurationError::NotApplicableOperation)
432    }
433
434    fn save(_preprocessing: &Self, _path: &Path) -> Result<(), Self::Error> {
435        Err(ConfigurationError::NotApplicableOperation)
436    }
437}
438
439/// A verifiable proof of a zkVM execution.
440pub trait Verifiable: Serialize + DeserializeOwned {
441    type View: CheckedView;
442    type Error: From<nexus_core::nvm::VMError> + From<IOError>;
443
444    /// Get the memory layout configuration used for proving.
445    fn get_memory_layout(&self) -> &LinearMemoryLayout;
446
447    /// Verify the proof of an execution for a constructed [`CheckedView`](crate::traits::CheckedView).
448    fn verify(&self, expected_view: &Self::View) -> Result<(), <Self as Verifiable>::Error>;
449
450    /// Verify the proof of an execution.
451    fn verify_expected<
452        T: Serialize + DeserializeOwned + Sized,
453        U: Serialize + DeserializeOwned + Sized,
454    >(
455        &self,
456        expected_public_input: &T,
457        expected_exit_code: u32,
458        expected_public_output: &U,
459        expected_elf: &nexus_core::nvm::ElfFile,
460        expected_ad: &[u8],
461    ) -> Result<(), <Self as Verifiable>::Error> {
462        let mut input_encoded =
463            postcard::to_stdvec(&expected_public_input).map_err(IOError::from)?;
464        if !input_encoded.is_empty() {
465            input_encoded =
466                postcard::to_stdvec_cobs(&expected_public_input).map_err(IOError::from)?;
467            let input_padded_len = (input_encoded.len() + 3) & !3;
468
469            assert!(input_padded_len >= input_encoded.len());
470            input_encoded.resize(input_padded_len, 0x00); // cobs ignores 0x00 padding
471        }
472
473        let mut output_encoded =
474            postcard::to_stdvec(&expected_public_output).map_err(IOError::from)?;
475        if !output_encoded.is_empty() {
476            output_encoded =
477                postcard::to_stdvec_cobs(&expected_public_output).map_err(IOError::from)?;
478            let output_padded_len = (output_encoded.len() + 3) & !3;
479
480            assert!(output_padded_len >= output_encoded.len());
481            output_encoded.resize(output_padded_len, 0x00); // cobs ignores 0x00 padding
482        }
483
484        let view = Self::View::new_from_expected(
485            self.get_memory_layout(),
486            input_encoded.as_slice(),
487            &expected_exit_code.to_le_bytes(),
488            output_encoded.as_slice(),
489            expected_elf,
490            expected_ad,
491        );
492
493        self.verify(&view)
494    }
495
496    /// Verify the proof of an execution, with the elf provided as raw bytes.
497    fn verify_expected_from_program_bytes<
498        T: Serialize + DeserializeOwned + Sized,
499        U: Serialize + DeserializeOwned + Sized,
500    >(
501        &self,
502        expected_public_input: &T,
503        expected_exit_code: u32,
504        expected_public_output: &U,
505        expected_elf_bytes: &[u8],
506        expected_ad: &[u8],
507    ) -> Result<(), <Self as Verifiable>::Error> {
508        self.verify_expected(
509            expected_public_input,
510            expected_exit_code,
511            expected_public_output,
512            &nexus_core::nvm::ElfFile::from_bytes(expected_elf_bytes)?,
513            expected_ad,
514        )
515    }
516
517    /// Verify the proof of an execution, sourcing the program elf from a path.
518    fn verify_expected_from_program_path<
519        P: AsRef<Path> + ?Sized,
520        T: Serialize + DeserializeOwned + Sized,
521        U: Serialize + DeserializeOwned + Sized,
522    >(
523        &self,
524        expected_public_input: &T,
525        expected_exit_code: u32,
526        expected_public_output: &U,
527        expected_elf_path: &P,
528        expected_ad: &[u8],
529    ) -> Result<(), <Self as Verifiable>::Error> {
530        self.verify_expected(
531            expected_public_input,
532            expected_exit_code,
533            expected_public_output,
534            &nexus_core::nvm::ElfFile::from_path(expected_elf_path)?,
535            expected_ad,
536        )
537    }
538
539    /// Return a size estimate for the proof, in bytes.
540    fn size_estimate(&self) -> usize;
541}