use lens::Commitment;
use nebu::Fp3;
use super::hiding::HidingProof;
use super::hiding::proof::{Cursor, write_ext};
use crate::spartan::reduce::CompressedRounds;
pub const MAGIC: &[u8; 8] = b"ZHVEIL01";
pub const MAX_BYTES: usize = 64 << 20;
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Parsed {
pub root: Commitment,
pub g1: Fp3,
pub outer: CompressedRounds<Fp3>,
pub evals: Vec<Fp3>,
pub g2: Fp3,
pub inner: CompressedRounds<Fp3>,
pub opening: HidingProof,
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Shape {
pub log_m: usize,
pub degree: usize,
pub matrices: usize,
pub vars: usize,
pub entries: usize,
}
impl Parsed {
pub fn to_bytes(&self) -> Vec<u8> {
let mut out = MAGIC.to_vec();
out.extend_from_slice(self.root.as_bytes());
write_ext(&mut out, self.g1);
self.outer
.rounds
.iter()
.flatten()
.for_each(|&x| write_ext(&mut out, x));
self.evals.iter().for_each(|&x| write_ext(&mut out, x));
write_ext(&mut out, self.g2);
self.inner
.rounds
.iter()
.flatten()
.for_each(|&x| write_ext(&mut out, x));
self.opening.write(&mut out);
out
}
pub fn from_bytes(bytes: &[u8], shape: Shape) -> Result<Self, String> {
if bytes.len() > MAX_BYTES {
return Err("veil: proof too large".into());
}
let mut r = Cursor { bytes };
if r.take(8)? != MAGIC {
return Err("veil: magic".into());
}
let root = Commitment(hemera::Hash::from_bytes(
r.take(32)?.try_into().expect("32"),
));
let g1 = r.ext()?;
let outer = CompressedRounds {
rounds: (0..shape.log_m)
.map(|_| r.exts(shape.degree))
.collect::<Result<_, _>>()?,
};
let evals = r.exts(shape.matrices)?;
let g2 = r.ext()?;
let inner = CompressedRounds {
rounds: (0..shape.vars)
.map(|_| r.exts(2))
.collect::<Result<_, _>>()?,
};
let opening = HidingProof::read(&mut r, shape.entries)?;
if !r.bytes.is_empty() {
return Err("veil: trailing bytes".into());
}
Ok(Self {
root,
g1,
outer,
evals,
g2,
inner,
opening,
})
}
}