1use alloc::vec::Vec;
2
3use vm_core::{
4 crypto::hash::{Blake3_192, Blake3_256, Hasher, 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 };
53 conjectured_security.bits()
54 }
55
56 pub fn to_bytes(&self) -> Vec<u8> {
61 let mut bytes = self.proof.to_bytes();
62 assert!(!bytes.is_empty(), "invalid STARK proof");
63 bytes.insert(0, self.hash_fn as u8);
65 bytes
66 }
67
68 pub fn from_bytes(source: &[u8]) -> Result<Self, DeserializationError> {
70 if source.len() < 2 {
71 return Err(DeserializationError::UnexpectedEOF);
72 }
73 let hash_fn = HashFunction::try_from(source[0])?;
74 let proof = Proof::from_bytes(&source[1..])?;
75 Ok(Self::new(proof, hash_fn))
76 }
77
78 pub fn into_parts(self) -> (HashFunction, Proof) {
83 (self.hash_fn, self.proof)
84 }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
92#[repr(u8)]
93pub enum HashFunction {
94 Blake3_192 = 0x00,
96 Blake3_256 = 0x01,
98 Rpo256 = 0x02,
100 Rpx256 = 0x03,
102}
103
104impl Default for HashFunction {
105 fn default() -> Self {
106 Self::Blake3_192
107 }
108}
109
110impl HashFunction {
111 pub const fn collision_resistance(&self) -> u32 {
113 match self {
114 HashFunction::Blake3_192 => Blake3_192::COLLISION_RESISTANCE,
115 HashFunction::Blake3_256 => Blake3_256::COLLISION_RESISTANCE,
116 HashFunction::Rpo256 => Rpo256::COLLISION_RESISTANCE,
117 HashFunction::Rpx256 => Rpx256::COLLISION_RESISTANCE,
118 }
119 }
120}
121
122impl TryFrom<u8> for HashFunction {
123 type Error = DeserializationError;
124
125 fn try_from(repr: u8) -> Result<Self, Self::Error> {
126 match repr {
127 0x00 => Ok(Self::Blake3_192),
128 0x01 => Ok(Self::Blake3_256),
129 0x02 => Ok(Self::Rpo256),
130 0x03 => Ok(Self::Rpx256),
131 _ => Err(DeserializationError::InvalidValue(format!(
132 "the hash function representation {repr} is not valid!"
133 ))),
134 }
135 }
136}
137
138impl Serializable for HashFunction {
142 fn write_into<W: ByteWriter>(&self, target: &mut W) {
143 target.write_u8(*self as u8);
144 }
145}
146
147impl Deserializable for HashFunction {
148 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
149 source.read_u8()?.try_into()
150 }
151}
152
153impl Serializable for ExecutionProof {
154 fn write_into<W: ByteWriter>(&self, target: &mut W) {
155 self.proof.write_into(target);
156 self.hash_fn.write_into(target);
157 }
158}
159
160impl Deserializable for ExecutionProof {
161 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
162 let proof = Proof::read_from(source)?;
163 let hash_fn = HashFunction::read_from(source)?;
164
165 Ok(ExecutionProof { proof, hash_fn })
166 }
167}