use lens::{Whir, WhirParams};
use super::codec::{Reader, Writer};
use super::{Envelope, EnvelopeError as E};
use crate::execution::NounToken;
use crate::execution::succinct::SuccinctPcs;
use crate::machine::statement::{MAX_INPUTS, MAX_READS, MAX_TOKENS};
use crate::machine::{MachineProof, MachinePublic, MachineState};
pub const MACHINE_FORMAT: u8 = 2;
fn tokens(ts: &[NounToken], w: &mut Writer) {
w.len(ts.len());
for t in ts {
match t {
NounToken::Atom(v) => {
w.bool(false);
w.varint(*v);
}
NounToken::Pair => w.bool(true),
}
}
}
fn read_tokens(r: &mut Reader) -> Result<Vec<NounToken>, E> {
let n = r.len(MAX_TOKENS, 1)?;
(0..n)
.map(|_| {
Ok(if r.bool()? {
NounToken::Pair
} else {
NounToken::Atom(r.field()?)
})
})
.collect()
}
pub(super) fn statement(st: &MachinePublic, w: &mut Writer) {
w.raw(&st.program);
w.len(st.input.len());
for &v in &st.input {
w.varint(v);
}
tokens(&st.output, w);
w.varint(st.cycles);
w.varint(st.budget);
w.bool(st.state.is_some());
if let Some(state) = &st.state {
for v in state.root {
w.varint(v);
}
w.len(state.reads.len());
for &(n, k, v) in &state.reads {
w.varint(n);
w.varint(k);
w.varint(v);
}
}
}
pub(super) fn read_statement(
r: &mut Reader,
expect: Option<&[u8; 32]>,
) -> Result<MachinePublic, E> {
let program: [u8; 32] = r.raw(32)?.try_into().expect("32 bytes");
if expect.is_some_and(|d| *d != program) {
return Err(E::ProgramMismatch);
}
let input = r.fields(MAX_INPUTS)?;
let output = read_tokens(r)?;
let cycles = r.field()?;
let budget = r.field()?;
if cycles > budget {
return Err(E::NonCanonical);
}
let state = if r.bool()? {
let root = [r.field()?, r.field()?, r.field()?, r.field()?];
let n = r.len(MAX_READS, 3)?;
let reads = (0..n)
.map(|_| Ok((r.field()?, r.field()?, r.field()?)))
.collect::<Result<_, E>>()?;
Some(MachineState { root, reads })
} else {
None
};
Ok(MachinePublic {
program,
input,
output,
cycles,
budget,
state,
})
}
pub(super) fn encode(
params: &WhirParams,
st: &MachinePublic,
proof: &MachineProof,
w: &mut Writer,
) {
w.raw(&[MACHINE_FORMAT]);
w.raw(¶ms.header());
statement(st, w);
w.raw(&proof.to_bytes());
}
pub(super) fn decode(r: &mut Reader, expect: Option<&[u8; 32]>) -> Result<Envelope, E> {
if r.byte()? != MACHINE_FORMAT {
return Err(E::NonCanonical);
}
let params = Whir::params_from_header(r.raw(8)?).map_err(|_| E::NonCanonical)?;
let statement = read_statement(r, expect)?;
let proof = MachineProof::from_bytes(r.raw(r.remaining())?).map_err(|_| E::NonCanonical)?;
Ok(Envelope::Machine {
params,
statement,
proof: Box::new(proof),
})
}