sov_rollup_interface/state_machine/zk/mod.rs
1//! Defines the traits that must be implemented by zkVMs. A zkVM like Risc0 consists of two components,
2//! a "guest" and a "host". The guest is the zkVM program itself, and the host is the physical machine on
3//! which the zkVM is running. Both the guest and the host are required to implement the [`Zkvm`] trait, in
4//! addition to the specialized [`ZkvmGuest`] and [`ZkvmHost`] trait which is appropriate to that environment.
5//!
6//! For a detailed example showing how to implement these traits, see the
7//! [risc0 adapter](https://github.com/Sovereign-Labs/sovereign-sdk/tree/main/adapters/risc0)
8//! maintained by the Sovereign Labs team.
9use core::fmt::Debug;
10
11use borsh::{BorshDeserialize, BorshSerialize};
12use digest::Digest;
13use serde::de::DeserializeOwned;
14use serde::{Deserialize, Serialize};
15
16use crate::da::DaSpec;
17use crate::RollupAddress;
18
19/// A trait implemented by the prover ("host") of a zkVM program.
20pub trait ZkvmHost: Zkvm {
21 /// The associated guest type
22 type Guest: ZkvmGuest;
23 /// Give the guest a piece of advice non-deterministically
24 fn add_hint<T: Serialize>(&self, item: T);
25
26 /// Simulate running the guest using the provided hints.
27 ///
28 /// Provides a simulated version of the guest which can be
29 /// accessed in the current process.
30 fn simulate_with_hints(&mut self) -> Self::Guest;
31
32 /// Run the guest in the true zk environment using the provided hints.
33 ///
34 /// This runs the guest binary compiled for the zkVM target, optionally
35 /// creating a SNARK of correct execution. Running the true guest binary comes
36 /// with some mild performance overhead and is not as easy to debug as [`simulate_with_hints`](ZkvmHost::simulate_with_hints).
37 fn run(&mut self, with_proof: bool) -> Result<(), anyhow::Error>;
38}
39
40/// A Zk proof system capable of proving and verifying arbitrary Rust code
41/// Must support recursive proofs.
42pub trait Zkvm {
43 /// A commitment to the zkVM program which is being proven
44 type CodeCommitment: Matches<Self::CodeCommitment>
45 + Clone
46 + Debug
47 + Serialize
48 + DeserializeOwned;
49
50 /// The error type which is returned when a proof fails to verify
51 type Error: Debug + From<std::io::Error>;
52
53 /// Interpret a sequence of a bytes as a proof and attempt to verify it against the code commitment.
54 /// If the proof is valid, return a reference to the public outputs of the proof.
55 fn verify<'a>(
56 serialized_proof: &'a [u8],
57 code_commitment: &Self::CodeCommitment,
58 ) -> Result<&'a [u8], Self::Error>;
59
60 /// Same as [`verify`](Zkvm::verify), except that instead of returning the output
61 /// as a serialized array, it returns a state transition structure.
62 /// TODO: specify a deserializer for the output
63 fn verify_and_extract_output<
64 Add: RollupAddress,
65 Da: DaSpec,
66 Root: Serialize + DeserializeOwned,
67 >(
68 serialized_proof: &[u8],
69 code_commitment: &Self::CodeCommitment,
70 ) -> Result<StateTransition<Da, Add, Root>, Self::Error>;
71}
72
73/// A trait which is accessible from within a zkVM program.
74pub trait ZkvmGuest: Zkvm + Send {
75 /// Obtain "advice" non-deterministically from the host
76 fn read_from_host<T: DeserializeOwned>(&self) -> T;
77 /// Add a public output to the zkVM proof
78 fn commit<T: Serialize>(&self, item: &T);
79}
80
81/// This trait is implemented on the struct/enum which expresses the validity condition
82pub trait ValidityCondition:
83 Serialize
84 + DeserializeOwned
85 + BorshDeserialize
86 + BorshSerialize
87 + Debug
88 + Clone
89 + Copy
90 + PartialEq
91 + Send
92 + Sync
93 + Eq
94{
95 /// The error type returned when two [`ValidityCondition`]s cannot be combined.
96 type Error: Into<anyhow::Error>;
97 /// Combine two conditions into one (typically run inside a recursive proof).
98 /// Returns an error if the two conditions cannot be combined
99 fn combine<H: Digest>(&self, rhs: Self) -> Result<Self, Self::Error>;
100}
101
102/// The public output of a SNARK proof in Sovereign, this struct makes a claim that
103/// the state of the rollup has transitioned from `initial_state_root` to `final_state_root`
104/// if and only if the condition `validity_condition` is satisfied.
105///
106/// The period of time covered by a state transition proof may be a single slot, or a range of slots on the DA layer.
107#[derive(Clone, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
108pub struct StateTransition<Da: DaSpec, Address, Root> {
109 /// The state of the rollup before the transition
110 pub initial_state_root: Root,
111 /// The state of the rollup after the transition
112 pub final_state_root: Root,
113 /// The slot hash of the state transition
114 pub slot_hash: Da::SlotHash,
115
116 /// Rewarded address: the account that has produced the transition proof.
117 pub rewarded_address: Address,
118
119 /// An additional validity condition for the state transition which needs
120 /// to be checked outside of the zkVM circuit. This typically corresponds to
121 /// some claim about the DA layer history, such as (X) is a valid block on the DA layer
122 pub validity_condition: Da::ValidityCondition,
123}
124
125/// This trait expresses that a type can check a validity condition.
126pub trait ValidityConditionChecker<Condition: ValidityCondition>:
127 BorshDeserialize + BorshSerialize + Debug
128{
129 /// The error type returned when a [`ValidityCondition`] is invalid.
130 type Error: Into<anyhow::Error>;
131 /// Check a validity condition
132 fn check(&mut self, condition: &Condition) -> Result<(), Self::Error>;
133}
134
135/// A trait expressing that two items of a type are (potentially fuzzy) matches.
136/// We need a custom trait instead of relying on [`PartialEq`] because we allow fuzzy matches.
137pub trait Matches<T> {
138 /// Check if two items are a match
139 fn matches(&self, other: &T) -> bool;
140}