miden_core/program/
kernel.rs1use alloc::{string::ToString, vec::Vec};
2
3use miden_crypto::Word;
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use crate::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
8
9#[derive(Debug, Clone, Default, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(Serialize))]
18#[cfg_attr(feature = "serde", serde(transparent))]
19#[cfg_attr(
20 all(feature = "arbitrary", test),
21 miden_test_serde_macros::serde_test(binary_serde(true))
22)]
23pub struct Kernel(Vec<Word>);
24
25impl Kernel {
26 pub const MAX_NUM_PROCEDURES: usize = u8::MAX as usize;
28
29 pub fn new(proc_hashes: &[Word]) -> Result<Self, KernelError> {
38 Self::from_hashes(proc_hashes.to_vec())
39 }
40
41 pub fn from_hashes(mut hashes: Vec<Word>) -> Result<Self, KernelError> {
50 if hashes.len() > Self::MAX_NUM_PROCEDURES {
51 return Err(KernelError::TooManyProcedures(Self::MAX_NUM_PROCEDURES, hashes.len()));
52 }
53
54 hashes.sort_by_key(|v| v.as_bytes()); let duplicated = hashes.windows(2).any(|data| data[0] == data[1]);
58
59 if duplicated {
60 Err(KernelError::DuplicatedProcedures)
61 } else {
62 Ok(Self(hashes))
63 }
64 }
65
66 #[cfg(test)]
70 pub(crate) fn from_hashes_unchecked(hashes: Vec<Word>) -> Self {
71 Self(hashes)
72 }
73
74 pub fn is_empty(&self) -> bool {
76 self.0.is_empty()
77 }
78
79 pub fn contains_proc(&self, proc_hash: Word) -> bool {
83 self.0.contains(&proc_hash)
86 }
87
88 pub fn proc_hashes(&self) -> &[Word] {
90 &self.0
91 }
92}
93
94impl Serializable for Kernel {
96 fn write_into<W: ByteWriter>(&self, target: &mut W) {
97 target.write_u8(self.0.len().try_into().expect("too many kernel procedures"));
99 target.write_many(&self.0)
100 }
101}
102
103impl Deserializable for Kernel {
104 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
105 let len = source.read_u8()? as usize;
106 let kernel = source.read_many_iter::<Word>(len)?.collect::<Result<_, _>>()?;
107 Self::from_hashes(kernel).map_err(|err| DeserializationError::InvalidValue(err.to_string()))
108 }
109}
110
111#[cfg(feature = "serde")]
112impl<'de> Deserialize<'de> for Kernel {
113 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114 where
115 D: serde::Deserializer<'de>,
116 {
117 let kernel = Vec::<Word>::deserialize(deserializer)?;
118 Self::from_hashes(kernel).map_err(serde::de::Error::custom)
119 }
120}
121
122#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
126pub enum KernelError {
127 #[error("kernel cannot have duplicated procedures")]
128 DuplicatedProcedures,
129 #[error("kernel can have at most {0} procedures, received {1}")]
130 TooManyProcedures(usize, usize),
131}
132
133#[cfg(test)]
134mod tests {
135 use alloc::vec::Vec;
136
137 use super::Kernel;
138 use crate::{
139 Felt, Word,
140 serde::{ByteWriter, Deserializable, Serializable, SliceReader},
141 };
142
143 #[test]
144 fn kernel_read_from_rejects_duplicate_procedure_hashes() {
145 let a: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into();
146 let b: Word = [Felt::new(5), Felt::new(6), Felt::new(7), Felt::new(8)].into();
147
148 assert!(
149 Kernel::new(&[a, a]).is_err(),
150 "test precondition: Kernel::new must reject duplicates"
151 );
152
153 let mut bytes = Vec::new();
156 bytes.write_u8(3);
157 b.write_into(&mut bytes);
158 a.write_into(&mut bytes);
159 a.write_into(&mut bytes);
160
161 let mut reader = SliceReader::new(&bytes);
162 let result = Kernel::read_from(&mut reader);
163
164 assert!(
165 result.is_err(),
166 "expected Kernel::read_from to reject duplicate procedure hashes"
167 );
168 }
169
170 #[cfg(feature = "serde")]
171 #[test]
172 fn kernel_serde_deserialisation_rejects_duplicate_procedure_hashes() {
173 let a: Word = [Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)].into();
174
175 assert!(
176 Kernel::new(&[a, a]).is_err(),
177 "test precondition: Kernel::new must reject duplicates"
178 );
179
180 let json = serde_json::to_string(&vec![a, a]).unwrap();
182 let result: Result<Kernel, _> = serde_json::from_str(&json);
183 assert!(
184 result.is_err(),
185 "expected serde deserialization to reject duplicate procedure hashes"
186 );
187 }
188
189 #[cfg(feature = "serde")]
190 #[test]
191 fn kernel_serde_deserialisation_rejects_too_many_procedure_hashes() {
192 let proc_hashes: Vec<Word> = (0u64..=255)
193 .map(|n| [Felt::new(n), Felt::new(n + 1), Felt::new(n + 2), Felt::new(n + 3)].into())
194 .collect();
195
196 let json = serde_json::to_string(&proc_hashes).unwrap();
197 let result: Result<Kernel, _> = serde_json::from_str(&json);
198 assert!(
199 result.is_err(),
200 "expected serde deserialization to reject more than MAX_NUM_PROCEDURES hashes"
201 );
202 }
203}