nexus_sdk/legacy/nova/
seq.rsuse crate::legacy::compile;
use crate::legacy::traits::*;
use crate::legacy::views::UncheckedView;
use crate::traits::*;
use crate::legacy::ark_serialize_utils::{ark_de, ark_se};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::path::Path;
use thiserror::Error;
use nexus_core_legacy::nvm::interactive::{eval, parse_elf, trace};
use nexus_core_legacy::nvm::memory::MerkleTrie;
use nexus_core_legacy::nvm::NexusVM;
use nexus_core_legacy::prover::nova::pp::{gen_vm_pp, load_pp, save_pp};
use nexus_core_legacy::prover::nova::prove_seq;
use nexus_core_legacy::prover::nova::types::IVCProof;
use crate::error::{BuildError, ConfigurationError, IOError, PathError};
use nexus_core_legacy::prover::nova::error::ProofError;
pub use nexus_core_legacy::prover::nova::types::SeqPP as PP;
use std::marker::PhantomData;
const K: usize = 16;
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
ProofError(#[from] ProofError),
#[error(transparent)]
BuildError(#[from] BuildError),
#[error(transparent)]
HostIOError(#[from] std::io::Error),
#[error(transparent)]
PathError(#[from] PathError),
#[error(transparent)]
GuestIOError(#[from] IOError),
#[error(transparent)]
ConfigurationError(#[from] ConfigurationError),
}
pub struct Nova<'a, C: Compute = Local> {
vm: NexusVM<MerkleTrie>,
pp: Option<&'a PP>,
_compute: PhantomData<C>,
}
#[derive(Serialize, Deserialize)]
pub struct Proof<'a> {
#[serde(serialize_with = "ark_se", deserialize_with = "ark_de")]
proof: IVCProof,
#[serde(skip)]
view: UncheckedView,
#[serde(skip)]
pp: Option<&'a PP>,
}
macro_rules! setup {
($id:ty) => {
impl<'a> Setup<'a> for $id {
type Reference = ();
type Parameters = PP;
type Preprocessing = ();
type Error = Error;
fn setup_reference<'b: 'a>(
&mut self,
_reference: &'b Self::Reference,
) -> Result<(), Self::Error> {
return Err(Error::from(ConfigurationError::NotApplicableOperation));
}
fn setup_parameters<'b: 'a>(
&mut self,
parameters: &'b Self::Parameters,
) -> Result<(), Self::Error> {
self.pp = Some(parameters);
Ok(())
}
fn detach(&mut self) {
self.pp = None;
}
fn reference(&self) -> Result<&'a Self::Reference, Self::Error> {
Ok(&())
}
fn parameters(&self) -> Result<&'a Self::Parameters, Self::Error> {
if self.pp.is_none() {
return Err(Error::from(ConfigurationError::NotYetConfigured));
} else {
Ok(self.pp.unwrap())
}
}
fn preprocessing(&self) -> Result<Self::Preprocessing, Self::Error> {
Ok(())
}
}
};
}
setup!(Nova<'a, Local>);
setup!(Proof<'a>);
impl<'a> LegacyProver<'a> for Nova<'a, Local> {
type Proof = Proof<'a>;
type View = UncheckedView;
fn new(elf_bytes: &[u8]) -> Result<Self, Self::Error> {
Ok(Nova::<Local> {
vm: parse_elf::<MerkleTrie>(elf_bytes).map_err(ProofError::from)?,
pp: None,
_compute: PhantomData,
})
}
fn compile(opts: &compile::CompileOpts) -> Result<Self, Self::Error> {
let mut iopts = opts.to_owned();
if iopts.memlimit.is_none() {
iopts.set_memlimit(4);
}
let elf_path = iopts.build(&compile::ForProver::Default)?;
Self::new_from_file(&elf_path)
}
fn run_with_input<S>(mut self, private_input: &S) -> Result<Self::View, Self::Error>
where
S: Serialize + Sized,
{
self.vm.syscalls.set_input(
postcard::to_stdvec(private_input)
.map_err(IOError::from)?
.as_slice(),
);
eval(&mut self.vm, false, false).map_err(ProofError::from)?;
Ok(Self::View {
out: self.vm.syscalls.get_output(),
logs: self
.vm
.syscalls
.get_log_buffer()
.into_iter()
.map(String::from_utf8)
.collect::<Result<Vec<_>, _>>()
.map_err(IOError::from)?,
})
}
fn prove_with_input<S>(mut self, private_input: &S) -> Result<Self::Proof, Self::Error>
where
S: Serialize + Sized,
{
if self.pp.is_none() {
return Err(Error::from(ConfigurationError::NotYetConfigured));
}
self.vm.syscalls.set_input(
postcard::to_stdvec(private_input)
.map_err(IOError::from)?
.as_slice(),
);
let tr = trace(&mut self.vm, K, false).map_err(ProofError::from)?;
Ok(Self::Proof {
proof: prove_seq(self.pp.as_ref().unwrap(), tr)?,
pp: self.pp,
view: Self::View {
out: self.vm.syscalls.get_output(),
logs: self
.vm
.syscalls
.get_log_buffer()
.into_iter()
.map(String::from_utf8)
.collect::<Result<Vec<_>, _>>()
.map_err(IOError::from)?,
},
})
}
}
impl Parameters for PP {
type Ref = ();
type Error = Error;
fn generate(_reference: &Self::Ref) -> Result<Self, Self::Error> {
eprintln!("Using test parameter generation, not for production use!!!");
Ok(gen_vm_pp(K, &())?)
}
fn load(path: &Path) -> Result<Self, Self::Error> {
if let Some(path_str) = path.to_str() {
return Ok(load_pp(path_str)?);
}
Err(Self::Error::PathError(
crate::error::PathError::EncodingError,
))
}
fn save(pp: &Self, path: &Path) -> Result<(), Self::Error> {
if let Some(path_str) = path.to_str() {
return Ok(save_pp(pp, path_str)?);
}
Err(Self::Error::PathError(
crate::error::PathError::EncodingError,
))
}
}
impl<'a> LegacyVerifiable<'a> for Proof<'a> {
type View = UncheckedView;
fn output<U: DeserializeOwned>(&self) -> Result<U, Self::Error> {
Ok(Self::View::output::<U>(&self.view)?)
}
fn logs(&self) -> &Vec<String> {
Self::View::logs(&self.view)
}
fn detach(&mut self) {
self.pp = None;
}
fn verify(&self) -> Result<(), Self::Error> {
if self.pp.is_none() {
return Err(Error::from(ConfigurationError::NotYetConfigured));
}
Ok(self
.proof
.verify(self.pp.as_ref().unwrap())
.map_err(ProofError::from)?)
}
}