risc0_zkvm_verify/zkvm/
receipt.rs1use alloc::{vec, vec::Vec};
16
17use risc0_zkp_core::sha::{Digest, Sha, DIGEST_WORDS, DIGEST_WORD_SIZE};
18use serde::{Deserialize, Serialize};
19
20use crate::zkp::verify::{verify, VerificationError};
21use crate::zkvm::verify::circuit::{MethodID, RV32Circuit};
22
23const DIGEST_SIZE_BYTES: usize = DIGEST_WORDS * DIGEST_WORD_SIZE;
24
25#[derive(Deserialize, Serialize)]
26pub struct Receipt {
27 pub journal: Vec<u8>,
28 pub seal: Vec<u32>,
29}
30
31impl Receipt {
32 pub fn new(journal: Vec<u8>, seal: Vec<u32>) -> Self {
33 Receipt { journal, seal }
34 }
35
36 pub fn verify(&self, method_id: &MethodID) -> Result<bool, VerificationError> {
37 let mut circuit = RV32Circuit::new(method_id);
38 let sha = risc0_zkp_core::sha::default_implementation();
39 verify(sha, &mut circuit, &self.seal)?;
40 if self.journal.len() != (self.seal[8] as usize) {
41 return Ok(false);
42 }
43 if self.journal.len() > DIGEST_SIZE_BYTES {
44 let digest = sha.hash_bytes(&self.journal);
45 if (*digest != Digest::from_slice(&self.seal[0..8])) {
46 return Ok(false);
47 }
48 } else {
49 let mut vec = self.journal.clone();
50 vec.resize(DIGEST_SIZE_BYTES, 0);
51 for i in 0..8 {
52 if (self.seal[i]
53 != u32::from_le_bytes(
54 vec[i * DIGEST_WORD_SIZE..i * DIGEST_WORD_SIZE + DIGEST_WORD_SIZE]
55 .try_into()
56 .or(Err(VerificationError::ReceiptFormatError))?,
57 ))
58 {
59 return Ok(false);
60 }
61 }
62 }
63 Ok(true)
64 }
65
66 pub fn get_journal_u32(&self) -> Vec<u32> {
67 let mut as_words: Vec<u32> = vec![];
68 assert!(self.journal.len() % DIGEST_WORD_SIZE == 0);
69 for i in 0..(self.journal.len() / DIGEST_WORD_SIZE) {
70 as_words.push(u32::from_le_bytes(
71 self.journal[i * DIGEST_WORD_SIZE..i * DIGEST_WORD_SIZE + DIGEST_WORD_SIZE]
72 .try_into()
73 .unwrap(),
74 ));
75 }
76 as_words
77 }
78}