use crypto::digest::{Digest, OutputSizeUser};
use crypto_common::generic_array::{ArrayLength, GenericArray};
use nexus_common::constants::WORD_SIZE;
use serde::{de::DeserializeOwned, Serialize};
use std::path::Path;
use nexus_core::nvm::internals::*;
use crate::compile::*;
use crate::error::*;
pub trait Compute {}
pub enum Local {}
impl Compute for Local {}
pub trait CheckedView {
fn new_from_expected(
memory_layout: &LinearMemoryLayout,
expected_public_input: &[u8],
expected_exit_code: &[u8],
expected_public_output: &[u8],
expected_elf: &nexus_core::nvm::ElfFile,
expected_ad: &[u8],
) -> Self;
}
impl CheckedView for nexus_core::nvm::View {
fn new_from_expected(
memory_layout: &LinearMemoryLayout,
expected_public_input: &[u8],
expected_exit_code: &[u8],
expected_public_output: &[u8],
expected_elf: &nexus_core::nvm::ElfFile,
expected_ad: &[u8],
) -> Self {
let emulator = LinearEmulator::default();
let instructions = expected_elf
.instructions
.iter()
.map(|instr| convert_instruction(&emulator.executor.instruction_executor, instr))
.collect();
let converted_elf = nexus_core::nvm::ElfFile {
instructions,
..expected_elf.clone()
};
let program_memory = elf_into_program_info(&converted_elf, memory_layout);
let initial_memory = slice_into_io_entries::<MemoryInitializationEntry>(
memory_layout.public_input_start_location(),
&[
memory_layout.public_input_start().to_le_bytes(),
memory_layout.exit_code().to_le_bytes(), ]
.concat(),
)
.iter()
.chain(map_into_io_entries::<MemoryInitializationEntry>(&expected_elf.rom_image).iter())
.chain(map_into_io_entries::<MemoryInitializationEntry>(&expected_elf.ram_image).iter())
.chain(
slice_into_io_entries::<MemoryInitializationEntry>(
memory_layout.public_input_start(),
&[
&(expected_public_input.len() as u32).to_le_bytes(),
expected_public_input,
]
.concat(),
)
.iter(),
)
.copied()
.collect();
let exit_code = slice_into_io_entries::<PublicOutputEntry>(
memory_layout.exit_code(),
expected_exit_code,
);
let output_memory = slice_into_io_entries::<PublicOutputEntry>(
memory_layout.public_output_start(),
expected_public_output,
);
let static_memory_size =
(&expected_elf.rom_image.len() + &expected_elf.ram_image.len()) * WORD_SIZE;
Self::new(
&Some(*memory_layout),
&Vec::new(),
&program_memory,
&initial_memory,
memory_layout.tracked_ram_size(static_memory_size),
&exit_code,
&output_memory,
&expected_ad.to_vec(),
)
}
}
pub trait Viewable {
fn public_input<T: Serialize + DeserializeOwned + Sized>(&self) -> Result<T, IOError>;
fn public_input_digest<T: Serialize + DeserializeOwned + Sized, H: Digest>(
&self,
) -> Result<GenericArray<u8, H::OutputSize>, IOError>
where
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
{
Ok(H::digest(
postcard::to_stdvec_cobs::<T>(&Self::public_input::<T>(self)?)
.map_err(IOError::from)?
.as_slice(),
))
}
fn exit_code(&self) -> Result<u32, IOError>;
fn exit_code_digest<H: Digest>(&self) -> Result<GenericArray<u8, H::OutputSize>, IOError>
where
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
{
Ok(H::digest(Self::exit_code(self)?.to_le_bytes()))
}
fn public_output<U: Serialize + DeserializeOwned + Sized>(&self) -> Result<U, IOError>;
fn public_output_digest<U: Serialize + DeserializeOwned + Sized, H: Digest>(
&self,
) -> Result<GenericArray<u8, H::OutputSize>, IOError>
where
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
{
Ok(H::digest(
postcard::to_stdvec_cobs::<U>(&Self::public_output::<U>(self)?)
.map_err(IOError::from)?
.as_slice(),
))
}
fn associated_data(&self) -> Result<Vec<u8>, IOError>;
fn associated_data_digest<H: Digest>(&self) -> Result<GenericArray<u8, H::OutputSize>, IOError>
where
<H as OutputSizeUser>::OutputSize: ArrayLength<u8>,
{
Ok(H::digest(Self::associated_data(self)?.as_slice()))
}
fn logs(&self) -> Result<Vec<String>, IOError>;
}
impl Viewable for nexus_core::nvm::View {
fn public_input<T: Serialize + DeserializeOwned + Sized>(&self) -> Result<T, IOError> {
if let Some(mut bytes) = self.view_public_input() {
Ok(postcard::from_bytes_cobs::<T>(&mut bytes).map_err(IOError::from)?)
} else {
Err(IOError::NotYetAvailableError)
}
}
fn exit_code(&self) -> Result<u32, IOError> {
if let Some(bytes) = self.view_exit_code() {
Ok(postcard::from_bytes::<u32>(&bytes).map_err(IOError::from)?)
} else {
Err(IOError::NotYetAvailableError)
}
}
fn public_output<U: Serialize + DeserializeOwned + Sized>(&self) -> Result<U, IOError> {
if let Some(mut bytes) = self.view_public_output() {
Ok(postcard::from_bytes_cobs::<U>(&mut bytes).map_err(IOError::from)?)
} else {
Err(IOError::NotYetAvailableError)
}
}
fn associated_data(&self) -> Result<Vec<u8>, IOError> {
if let Some(bytes) = self.view_associated_data() {
Ok(bytes)
} else {
Err(IOError::NotYetAvailableError)
}
}
fn logs(&self) -> Result<Vec<String>, IOError> {
if let Some(bytes_vecs) = self.view_debug_logs() {
Ok(bytes_vecs
.iter()
.map(|raw_log: &Vec<u8>| String::from_utf8_lossy(raw_log).to_string())
.collect())
} else {
Err(IOError::NotYetAvailableError)
}
}
}
pub trait ByGuestCompilation: Prover {
fn compile(compiler: &mut impl Compile) -> Result<Self, Self::Error>;
}
pub trait Prover: Sized {
type Proof: Verifiable;
type View: CheckedView;
type Error: From<nexus_core::nvm::ElfError>;
fn new(elf: &nexus_core::nvm::ElfFile) -> Result<Self, <Self as Prover>::Error>;
fn new_from_bytes(elf_bytes: &[u8]) -> Result<Self, <Self as Prover>::Error> {
Self::new(&nexus_core::nvm::ElfFile::from_bytes(elf_bytes)?)
}
fn new_from_file<P: AsRef<Path> + ?Sized>(path: &P) -> Result<Self, <Self as Prover>::Error> {
Self::new(&nexus_core::nvm::ElfFile::from_path(&path)?)
}
fn set_associated_data(&mut self, ad: &[u8]) -> Result<(), <Self as Prover>::Error>;
fn run(&self) -> Result<Self::View, <Self as Prover>::Error> {
Self::run_with_input::<(), ()>(self, &(), &())
}
fn run_with_input<S: Serialize + Sized, T: Serialize + DeserializeOwned + Sized>(
&self,
private_input: &S,
public_input: &T,
) -> Result<Self::View, <Self as Prover>::Error>;
fn prove(self) -> Result<(Self::View, Self::Proof), <Self as Prover>::Error>
where
Self: Sized,
{
Self::prove_with_input::<(), ()>(self, &(), &())
}
fn prove_with_input<S: Serialize + Sized, T: Serialize + DeserializeOwned + Sized>(
self,
private_input: &S,
public_input: &T,
) -> Result<(Self::View, Self::Proof), <Self as Prover>::Error>;
}
pub trait Setup<'a> {
type Reference;
type Parameters;
type Preprocessing;
type Error;
fn setup_reference<'b: 'a>(
&mut self,
reference: &'b Self::Reference,
) -> Result<(), Self::Error>;
fn setup_parameters<'b: 'a>(
&mut self,
parameters: &'b Self::Parameters,
) -> Result<(), Self::Error>;
fn detach(&mut self);
fn reference(&self) -> Result<&'a Self::Reference, Self::Error>;
fn parameters(&self) -> Result<&'a Self::Parameters, Self::Error>;
fn preprocessing(&self) -> Result<Self::Preprocessing, Self::Error>;
}
pub trait Reference {
type Error;
fn generate() -> Result<Self, Self::Error>
where
Self: Sized;
fn load(path: &Path) -> Result<Self, Self::Error>
where
Self: Sized;
fn save(reference: &Self, path: &Path) -> Result<(), Self::Error>;
}
impl Reference for () {
type Error = ConfigurationError;
fn generate() -> Result<Self, Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
fn load(_path: &Path) -> Result<Self, Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
fn save(_reference: &Self, _path: &Path) -> Result<(), Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
}
pub trait Parameters {
type Ref: Reference;
type Error;
fn generate(reference: &Self::Ref) -> Result<Self, Self::Error>
where
Self: Sized;
fn load(path: &Path) -> Result<Self, Self::Error>
where
Self: Sized;
fn save(parameters: &Self, path: &Path) -> Result<(), Self::Error>;
}
impl Parameters for () {
type Ref = ();
type Error = ConfigurationError;
fn generate(_reference: &Self::Ref) -> Result<Self, Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
fn load(_path: &Path) -> Result<Self, Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
fn save(_parameters: &Self, _path: &Path) -> Result<(), Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
}
pub trait Preprocessing {
type Ref: Reference;
type Params: Parameters;
type Error;
fn load(path: &Path) -> Result<Self, Self::Error>
where
Self: Sized;
fn save(preprocessing: &Self, path: &Path) -> Result<(), Self::Error>;
}
impl Preprocessing for () {
type Ref = ();
type Params = ();
type Error = ConfigurationError;
fn load(_path: &Path) -> Result<Self, Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
fn save(_preprocessing: &Self, _path: &Path) -> Result<(), Self::Error> {
Err(ConfigurationError::NotApplicableOperation)
}
}
pub trait Verifiable: Serialize + DeserializeOwned {
type View: CheckedView;
type Error: From<nexus_core::nvm::ElfError> + From<IOError>;
fn get_memory_layout(&self) -> &LinearMemoryLayout;
fn verify(&self, expected_view: &Self::View) -> Result<(), <Self as Verifiable>::Error>;
fn verify_expected<
T: Serialize + DeserializeOwned + Sized,
U: Serialize + DeserializeOwned + Sized,
>(
&self,
expected_public_input: &T,
expected_exit_code: u32,
expected_public_output: &U,
expected_elf: &nexus_core::nvm::ElfFile,
expected_ad: &[u8],
) -> Result<(), <Self as Verifiable>::Error> {
let mut input_encoded =
postcard::to_stdvec(&expected_public_input).map_err(IOError::from)?;
if !input_encoded.is_empty() {
let input = expected_public_input.to_owned();
input_encoded = postcard::to_stdvec_cobs(&input).map_err(IOError::from)?;
let input_padded_len = (input_encoded.len() + 3) & !3;
assert!(input_padded_len >= input_encoded.len());
input_encoded.resize(input_padded_len, 0x00); }
let mut output_encoded =
postcard::to_stdvec(&expected_public_output).map_err(IOError::from)?;
if !output_encoded.is_empty() {
let output = expected_public_output.to_owned();
output_encoded = postcard::to_stdvec_cobs(&output).map_err(IOError::from)?;
let output_padded_len = (output_encoded.len() + 3) & !3;
assert!(output_padded_len >= output_encoded.len());
output_encoded.resize(output_padded_len, 0x00); }
let view = Self::View::new_from_expected(
self.get_memory_layout(),
input_encoded.as_slice(),
&expected_exit_code.to_le_bytes(),
output_encoded.as_slice(),
expected_elf,
expected_ad,
);
self.verify(&view)
}
fn verify_expected_from_program_bytes<
T: Serialize + DeserializeOwned + Sized,
U: Serialize + DeserializeOwned + Sized,
>(
&self,
expected_public_input: &T,
expected_exit_code: u32,
expected_public_output: &U,
expected_elf_bytes: &[u8],
expected_ad: &[u8],
) -> Result<(), <Self as Verifiable>::Error> {
self.verify_expected(
expected_public_input,
expected_exit_code,
expected_public_output,
&nexus_core::nvm::ElfFile::from_bytes(expected_elf_bytes)?,
expected_ad,
)
}
fn verify_expected_from_program_path<
P: AsRef<Path> + ?Sized,
T: Serialize + DeserializeOwned + Sized,
U: Serialize + DeserializeOwned + Sized,
>(
&self,
expected_public_input: &T,
expected_exit_code: u32,
expected_public_output: &U,
expected_elf_path: &P,
expected_ad: &[u8],
) -> Result<(), <Self as Verifiable>::Error> {
self.verify_expected(
expected_public_input,
expected_exit_code,
expected_public_output,
&nexus_core::nvm::ElfFile::from_path(expected_elf_path)?,
expected_ad,
)
}
fn size_estimate(&self) -> usize;
}