use super::ZkProof;
use super::codec::{Reader, Writer};
use super::{Envelope, EnvelopeError as E, Profile};
use crate::execution::private::PrivateStatement;
use crate::execution::state::{MAX_READS, PublicLookup, StateStatement};
use crate::execution::veil::{self, VeilProof};
use crate::execution::zk::{self, PrivateProof};
use crate::execution::{
Certificate, ExecutionStatement, MAX_INPUTS, MAX_OUTPUTS, MAX_PROGRAM_NODES, NounToken,
};
pub const MAX_FREE: usize = 1 << 20;
pub(super) fn encode(envelope: &Envelope, w: &mut Writer) {
match envelope {
Envelope::Public {
statement,
certificate,
} => {
execution(statement, w);
free(certificate, w);
}
Envelope::Zk {
statement,
context,
proof,
} => {
w.raw(&[proof.scheme()]);
execution(&statement.execution, w);
w.raw(context);
w.len(proof.as_bytes().len());
w.raw(proof.as_bytes());
}
Envelope::StatePublic {
statement,
certificate,
} => {
state(statement, w);
free(certificate, w);
}
Envelope::Succinct { statement, proof } => super::succinct::encode(statement, proof, w),
Envelope::Machine {
params,
statement,
proof,
} => super::machine::encode(params, statement, proof, w),
Envelope::Recursive {
params,
statement,
proof,
} => super::recursive::encode(params, statement, proof, w),
Envelope::Wrapped { statement, proof } => super::wrapped::encode(statement, proof, w),
}
}
pub(super) fn state(statement: &StateStatement, w: &mut Writer) {
execution(&statement.execution, w);
for limb in statement.state_root {
w.varint(limb);
}
w.bool(statement.root_in_subject);
w.len(statement.reads.len());
for read in &statement.reads {
w.bool(read.active);
for v in [read.namespace, read.key, read.value] {
w.varint(v);
}
}
}
pub(super) fn decode(
profile: Profile,
r: &mut Reader,
expect: Option<&[u8; 32]>,
) -> Result<Envelope, E> {
match profile {
Profile::Public => Ok(Envelope::Public {
statement: read_execution(r)?,
certificate: read_free(r)?,
}),
Profile::Zk => {
let scheme = r.byte()?;
let execution = read_execution(r)?;
let context = read_context(r)?;
let proof = match scheme {
1 => {
let n = r.len(zk::MAX_BYTES, 1)?;
ZkProof::Mith(PrivateProof::from_bytes(r.raw(n)?).map_err(|_| E::NonCanonical)?)
}
2 => {
let n = r.len(veil::MAX_BYTES, 1)?;
ZkProof::Veil(VeilProof::from_bytes(r.raw(n)?).map_err(|_| E::NonCanonical)?)
}
_ => return Err(E::NonCanonical),
};
Ok(Envelope::Zk {
statement: PrivateStatement { execution },
context,
proof,
})
}
Profile::StatePublic => Ok(Envelope::StatePublic {
statement: read_state(r)?,
certificate: read_free(r)?,
}),
Profile::Succinct => super::succinct::decode(r),
Profile::Machine => super::machine::decode(r, expect),
Profile::Recursive => super::recursive::decode(r, expect),
Profile::Wrapped => super::wrapped::decode(r, expect),
}
}
pub(super) fn read_state(r: &mut Reader) -> Result<StateStatement, E> {
let execution = read_execution(r)?;
let mut state_root = [0u64; 4];
for limb in &mut state_root {
*limb = r.field()?;
}
let root_in_subject = r.bool()?;
let n = r.len(MAX_READS, 4)?;
let mut reads = Vec::with_capacity(n);
for _ in 0..n {
let active = r.bool()?;
let (namespace, key, value) = (r.field()?, r.field()?, r.field()?);
if !active && (namespace, key, value) != (0, 0, 0) {
return Err(E::NonCanonical);
}
reads.push(PublicLookup {
active,
namespace,
key,
value,
});
}
Ok(StateStatement {
execution,
state_root,
root_in_subject,
reads,
})
}
pub(super) fn execution(s: &ExecutionStatement, w: &mut Writer) {
w.len(s.program.len());
for token in &s.program {
match token {
NounToken::Atom(v) => {
w.bool(false);
w.varint(*v);
}
NounToken::Pair => w.bool(true),
}
}
for values in [&s.public_input, &s.public_output] {
w.len(values.len());
for &v in values {
w.varint(v);
}
}
w.varint(s.cycles);
w.varint(s.budget);
}
pub(super) fn read_execution(r: &mut Reader) -> Result<ExecutionStatement, E> {
let n = r.len(MAX_PROGRAM_NODES, 1)?;
let mut program = Vec::with_capacity(n);
for _ in 0..n {
program.push(if r.bool()? {
NounToken::Pair
} else {
NounToken::Atom(r.field()?)
});
}
let public_input = r.fields(MAX_INPUTS)?;
let public_output = r.fields(MAX_OUTPUTS)?;
let cycles = r.field()?;
let budget = r.field()?;
if cycles > budget {
return Err(E::NonCanonical);
}
Ok(ExecutionStatement {
program,
public_input,
public_output,
cycles,
budget,
})
}
fn free(c: &Certificate, w: &mut Writer) {
w.len(c.free.len());
for &v in &c.free {
w.varint(v);
}
}
fn read_free(r: &mut Reader) -> Result<Certificate, E> {
let free = r.fields(MAX_FREE)?;
if free.last() == Some(&0) {
return Err(E::NonCanonical);
}
Ok(Certificate { free })
}
fn read_context(r: &mut Reader) -> Result<[u8; 32], E> {
let mut context = [0u8; 32];
context.copy_from_slice(r.raw(32)?);
Ok(context)
}