risc0_zkvm_verify/zkvm/
receipt.rs

1// Copyright 2022 Risc0, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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}