1use alloc::{string::ToString, vec::Vec};
2
3use miden_core::{
4 crypto::hash::{Blake3_192, Blake3_256, Hasher, Poseidon2, Rpo256, Rpx256},
5 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
6};
7use winter_air::proof::Proof;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ExecutionProof {
18 pub proof: Proof,
19 pub hash_fn: HashFunction,
20}
21
22impl ExecutionProof {
23 pub const fn new(proof: Proof, hash_fn: HashFunction) -> Self {
29 Self { proof, hash_fn }
30 }
31
32 pub const fn stark_proof(&self) -> &Proof {
37 &self.proof
38 }
39
40 pub const fn hash_fn(&self) -> HashFunction {
42 self.hash_fn
43 }
44
45 pub fn security_level(&self) -> u32 {
47 let conjectured_security = match self.hash_fn {
48 HashFunction::Blake3_192 => self.proof.conjectured_security::<Blake3_192>(),
49 HashFunction::Blake3_256 => self.proof.conjectured_security::<Blake3_256>(),
50 HashFunction::Rpo256 => self.proof.conjectured_security::<Rpo256>(),
51 HashFunction::Rpx256 => self.proof.conjectured_security::<Rpx256>(),
52 HashFunction::Poseidon2 => self.proof.conjectured_security::<Poseidon2>(),
53 };
54 conjectured_security.bits()
55 }
56
57 pub fn to_bytes(&self) -> Vec<u8> {
62 let mut bytes = self.proof.to_bytes();
63 assert!(!bytes.is_empty(), "invalid STARK proof");
64 bytes.insert(0, self.hash_fn as u8);
66 bytes
67 }
68
69 pub fn from_bytes(source: &[u8]) -> Result<Self, DeserializationError> {
71 if source.len() < 2 {
72 return Err(DeserializationError::UnexpectedEOF);
73 }
74 let hash_fn = HashFunction::try_from(source[0])?;
75 let proof = Proof::from_bytes(&source[1..])?;
76 Ok(Self::new(proof, hash_fn))
77 }
78
79 pub fn into_parts(self) -> (HashFunction, Proof) {
84 (self.hash_fn, self.proof)
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
93#[repr(u8)]
94pub enum HashFunction {
95 Blake3_192 = 0x00,
97 Blake3_256 = 0x01,
99 Rpo256 = 0x02,
101 Rpx256 = 0x03,
103 Poseidon2 = 0x04,
105}
106
107impl HashFunction {
108 pub const fn collision_resistance(&self) -> u32 {
110 match self {
111 HashFunction::Blake3_192 => Blake3_192::COLLISION_RESISTANCE,
112 HashFunction::Blake3_256 => Blake3_256::COLLISION_RESISTANCE,
113 HashFunction::Rpo256 => Rpo256::COLLISION_RESISTANCE,
114 HashFunction::Rpx256 => Rpx256::COLLISION_RESISTANCE,
115 HashFunction::Poseidon2 => Poseidon2::COLLISION_RESISTANCE,
116 }
117 }
118}
119
120impl TryFrom<u8> for HashFunction {
121 type Error = DeserializationError;
122
123 fn try_from(repr: u8) -> Result<Self, Self::Error> {
124 match repr {
125 0x00 => Ok(Self::Blake3_192),
126 0x01 => Ok(Self::Blake3_256),
127 0x02 => Ok(Self::Rpo256),
128 0x03 => Ok(Self::Rpx256),
129 0x04 => Ok(Self::Poseidon2),
130 _ => Err(DeserializationError::InvalidValue(format!(
131 "the hash function representation {repr} is not valid!"
132 ))),
133 }
134 }
135}
136
137impl TryFrom<&str> for HashFunction {
138 type Error = super::ExecutionOptionsError;
139
140 fn try_from(hash_fn_str: &str) -> Result<Self, Self::Error> {
141 match hash_fn_str {
142 "blake3-192" => Ok(Self::Blake3_192),
143 "blake3-256" => Ok(Self::Blake3_256),
144 "rpo" => Ok(Self::Rpo256),
145 "rpx" => Ok(Self::Rpx256),
146 "poseidon2" => Ok(Self::Poseidon2),
147 _ => Err(super::ExecutionOptionsError::InvalidHashFunction {
148 hash_function: hash_fn_str.to_string(),
149 }),
150 }
151 }
152}
153
154impl Serializable for HashFunction {
158 fn write_into<W: ByteWriter>(&self, target: &mut W) {
159 target.write_u8(*self as u8);
160 }
161}
162
163impl Deserializable for HashFunction {
164 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
165 source.read_u8()?.try_into()
166 }
167}
168
169impl Serializable for ExecutionProof {
170 fn write_into<W: ByteWriter>(&self, target: &mut W) {
171 self.proof.write_into(target);
172 self.hash_fn.write_into(target);
173 }
174}
175
176impl Deserializable for ExecutionProof {
177 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
178 let proof = Proof::read_from(source)?;
179 let hash_fn = HashFunction::read_from(source)?;
180
181 Ok(ExecutionProof { proof, hash_fn })
182 }
183}
184
185#[cfg(any(test, feature = "testing"))]
189impl ExecutionProof {
190 pub fn new_dummy() -> Self {
194 ExecutionProof {
195 proof: Proof::new_dummy(),
196 hash_fn: HashFunction::Blake3_192,
197 }
198 }
199}