Skip to main content

miden_core/
proof.rs

1use alloc::{
2    string::{String, ToString},
3    vec::Vec,
4};
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    crypto::hash::{Blake3_256, Poseidon2, Rpo256, Rpx256},
11    precompile::PrecompileRequest,
12    serde::{
13        ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader,
14    },
15};
16
17// EXECUTION PROOF
18// ================================================================================================
19
20/// A proof of correct execution of Miden VM.
21///
22/// The proof contains the STARK proof, the hash function used during proof generation, and a set
23/// of precompile requests deferred during proof generation. However, the proof does not contain
24/// public inputs needed to verify the proof.
25#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27pub struct ExecutionProof {
28    pub proof: Vec<u8>,
29    pub hash_fn: HashFunction,
30    pub pc_requests: Vec<PrecompileRequest>,
31}
32
33impl ExecutionProof {
34    // CONSTRUCTOR
35    // --------------------------------------------------------------------------------------------
36
37    /// Creates a new instance of [ExecutionProof] from the specified STARK proof, hash function,
38    /// and list of all deferred [PrecompileRequest]s.
39    pub const fn new(
40        proof: Vec<u8>,
41        hash_fn: HashFunction,
42        pc_requests: Vec<PrecompileRequest>,
43    ) -> Self {
44        Self { proof, hash_fn, pc_requests }
45    }
46
47    // PUBLIC ACCESSORS
48    // --------------------------------------------------------------------------------------------
49
50    /// Returns the underlying STARK proof.
51    pub fn stark_proof(&self) -> &[u8] {
52        &self.proof
53    }
54
55    /// Returns the hash function used during proof generation process.
56    pub const fn hash_fn(&self) -> HashFunction {
57        self.hash_fn
58    }
59
60    /// Returns the list of precompile requests made during the execution of the program.
61    pub fn precompile_requests(&self) -> &[PrecompileRequest] {
62        &self.pc_requests
63    }
64
65    /// Returns conjectured security level of this proof in bits.
66    ///
67    /// Currently returns a hardcoded 96 bits. Once the security estimator is implemented
68    /// in Plonky3, this should calculate the actual conjectured security level based on:
69    /// - Proof parameters (FRI folding factor, number of queries, etc.)
70    /// - Hash function collision resistance
71    /// - Field size and extension degree
72    pub fn security_level(&self) -> u32 {
73        96
74    }
75
76    // SERIALIZATION / DESERIALIZATION
77    // --------------------------------------------------------------------------------------------
78
79    /// Serializes this proof into a vector of bytes.
80    pub fn to_bytes(&self) -> Vec<u8> {
81        let mut bytes = Vec::new();
82        self.write_into(&mut bytes);
83        bytes
84    }
85
86    /// Reads the source bytes, parsing a new proof instance.
87    ///
88    /// The serialization layout matches the [`Serializable`] implementation of [`ExecutionProof`].
89    pub fn from_bytes(source: &[u8]) -> Result<Self, DeserializationError> {
90        let mut reader = SliceReader::new(source);
91        Self::read_from(&mut reader)
92    }
93
94    // DESTRUCTOR
95    // --------------------------------------------------------------------------------------------
96
97    /// Returns components of this execution proof.
98    pub fn into_parts(self) -> (HashFunction, Vec<u8>, Vec<PrecompileRequest>) {
99        (self.hash_fn, self.proof, self.pc_requests)
100    }
101}
102
103// HASH FUNCTION
104// ================================================================================================
105
106/// A hash function used during STARK proof generation.
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
108#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
109#[repr(u8)]
110pub enum HashFunction {
111    /// BLAKE3 hash function with 256-bit output.
112    Blake3_256 = 0x01,
113    /// RPO hash function with 256-bit output.
114    Rpo256 = 0x02,
115    /// RPX hash function with 256-bit output.
116    Rpx256 = 0x03,
117    /// Poseidon2 hash function with 256-bit output.
118    Poseidon2 = 0x04,
119    /// Keccak hash function with 256-bit output.
120    Keccak = 0x05,
121}
122
123impl HashFunction {
124    /// Returns the collision resistance level (in bits) of this hash function.
125    pub const fn collision_resistance(&self) -> u32 {
126        match self {
127            HashFunction::Blake3_256 => Blake3_256::COLLISION_RESISTANCE,
128            HashFunction::Rpo256 => Rpo256::COLLISION_RESISTANCE,
129            HashFunction::Rpx256 => Rpx256::COLLISION_RESISTANCE,
130            HashFunction::Poseidon2 => Poseidon2::COLLISION_RESISTANCE,
131            HashFunction::Keccak => 128,
132        }
133    }
134}
135
136impl TryFrom<u8> for HashFunction {
137    type Error = DeserializationError;
138
139    fn try_from(repr: u8) -> Result<Self, Self::Error> {
140        match repr {
141            0x01 => Ok(Self::Blake3_256),
142            0x02 => Ok(Self::Rpo256),
143            0x03 => Ok(Self::Rpx256),
144            0x04 => Ok(Self::Poseidon2),
145            0x05 => Ok(Self::Keccak),
146            _ => Err(DeserializationError::InvalidValue(format!(
147                "the hash function representation {repr} is not valid!"
148            ))),
149        }
150    }
151}
152
153impl TryFrom<&str> for HashFunction {
154    type Error = InvalidHashFunctionError;
155
156    fn try_from(hash_fn_str: &str) -> Result<Self, Self::Error> {
157        match hash_fn_str {
158            "blake3-256" => Ok(Self::Blake3_256),
159            "rpo" => Ok(Self::Rpo256),
160            "rpx" => Ok(Self::Rpx256),
161            "poseidon2" => Ok(Self::Poseidon2),
162            "keccak" => Ok(Self::Keccak),
163            _ => Err(InvalidHashFunctionError { hash_function: hash_fn_str.to_string() }),
164        }
165    }
166}
167
168// SERIALIZATION
169// ================================================================================================
170
171impl Serializable for HashFunction {
172    fn write_into<W: ByteWriter>(&self, target: &mut W) {
173        target.write_u8(*self as u8);
174    }
175}
176
177impl Deserializable for HashFunction {
178    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
179        source.read_u8()?.try_into()
180    }
181}
182
183impl Serializable for ExecutionProof {
184    fn write_into<W: ByteWriter>(&self, target: &mut W) {
185        self.proof.write_into(target);
186        self.hash_fn.write_into(target);
187        self.pc_requests.write_into(target);
188    }
189}
190
191impl Deserializable for ExecutionProof {
192    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
193        let proof = Vec::<u8>::read_from(source)?;
194        let hash_fn = HashFunction::read_from(source)?;
195        let pc_requests = Vec::<PrecompileRequest>::read_from(source)?;
196
197        Ok(ExecutionProof { proof, hash_fn, pc_requests })
198    }
199}
200
201// HASH FUNCTION ERROR
202// ================================================================================================
203
204/// Error type for invalid hash function strings.
205#[derive(Debug, thiserror::Error)]
206#[error(
207    "invalid hash function '{hash_function}'. Valid options are: blake3-256, rpo, rpx, poseidon2, keccak"
208)]
209pub struct InvalidHashFunctionError {
210    pub hash_function: String,
211}
212
213// TESTING UTILS
214// ================================================================================================
215
216#[cfg(any(test, feature = "testing"))]
217impl ExecutionProof {
218    /// Creates a dummy `ExecutionProof` for testing purposes only.
219    ///
220    /// A proof created in this way will not be verifiable against any verifier.
221    pub fn new_dummy() -> Self {
222        ExecutionProof {
223            proof: Vec::new(),
224            hash_fn: HashFunction::Blake3_256,
225            pc_requests: Vec::new(),
226        }
227    }
228}