diff --git a/src/lib.rs b/src/lib.rs index a98a0af..1500bbc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,22 @@ impl Cert { hash: h.finalize().into(), } } + pub fn zkvm_serialize(&self) -> Vec { + // First 8 bytes are the length of the message, + // followed by 228 bytes of fields of defined length, + // the rest is membership proof. + (228 + 32 * self.membership.hashes.len()) + .to_le_bytes() // 8 bytes; NOTE: Machine specific! (from usize) + .iter() + .chain(self.salt.iter()) // 32 bytes + .chain(self.subject.serialize().iter()) // 68 bytes + .chain(self.hash.iter()) // 32 bytes + .chain(self.authenticity.signature.iter()) // 64 bytes + .chain(self.membership.root.iter()) // 32 bytes + .chain(self.membership.hashes.iter().flatten()) // tail + .cloned() + .collect::>() + } } #[cfg(test)] @@ -232,4 +248,27 @@ mod tests { assert_eq!(*m.hashes.last().unwrap(), m.root); assert!(m.verify()); } + + #[test] + fn test_zkvm_serialize() { + let nodes = rand::thread_rng().gen_range(0..100); + let o = rand_obligation(); + let mp = MembershipProof::new( + std::iter::from_fn(|| Some(make_address())) + .take(nodes) + .collect(), + ); + let c = Cert { + subject: o.o, + authenticity: AuthCert { + subject: o.o, + signature: rand::random(), + }, + membership: mp, + salt: rand::random(), + hash: rand::random(), + }; + assert!(c.zkvm_serialize().len() > 228); + assert!(c.zkvm_serialize().len() < 228 + (nodes * 32) * 2); + } }