miden_air/
proof.rs

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