1use crate::maybestd::{cmp, fmt, marker::PhantomData, vec::Vec};
2use sha2::{Digest, Sha256};
3
4use crate::simple_merkle::tree::MerkleHash;
5pub const HASH_LEN: usize = 32;
7pub type DefaultHasher = Sha256;
9
10pub const LEAF_DOMAIN_SEPARATOR: [u8; 1] = [0u8];
12pub const INTERNAL_NODE_DOMAIN_SEPARATOR: [u8; 1] = [1u8];
14
15#[derive(Debug, Clone, PartialEq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub struct NamespacedSha2Hasher<const NS_ID_SIZE: usize> {
19 ignore_max_ns: bool,
20 _data: PhantomData<[u8; NS_ID_SIZE]>,
21}
22
23impl<const NS_ID_SIZE: usize> NamespaceMerkleHasher<NS_ID_SIZE>
24 for NamespacedSha2Hasher<NS_ID_SIZE>
25{
26 fn with_ignore_max_ns(ignore_max_ns: bool) -> Self {
27 Self {
28 ignore_max_ns,
29 _data: PhantomData,
30 }
31 }
32
33 fn ignores_max_ns(&self) -> bool {
34 self.ignore_max_ns
35 }
36
37 fn hash_leaf_with_namespace(
38 &self,
39 data: &[u8],
40 namespace: NamespaceId<NS_ID_SIZE>,
41 ) -> <Self as MerkleHash>::Output {
42 let mut output = NamespacedHash::with_min_and_max_ns(namespace, namespace);
43 let mut hasher = Sha256::new_with_prefix(LEAF_DOMAIN_SEPARATOR);
44 hasher.update(namespace.as_ref());
45 hasher.update(data.as_ref());
46 output.set_hash(hasher.finalize().as_ref());
47 output
48 }
49}
50
51#[cfg(test)]
54impl<const NS_ID_SIZE: usize> Default for NamespacedSha2Hasher<NS_ID_SIZE> {
55 fn default() -> Self {
56 Self {
57 ignore_max_ns: true,
58 _data: PhantomData,
59 }
60 }
61}
62
63pub trait NamespaceMerkleHasher<const NS_ID_SIZE: usize>: MerkleHash {
66 fn with_ignore_max_ns(ignore_max_ns: bool) -> Self;
68 fn ignores_max_ns(&self) -> bool;
70 fn hash_leaf_with_namespace(
72 &self,
73 data: &[u8],
74 namespace: NamespaceId<NS_ID_SIZE>,
75 ) -> <Self as MerkleHash>::Output;
76}
77
78impl<const NS_ID_SIZE: usize> MerkleHash for NamespacedSha2Hasher<NS_ID_SIZE> {
79 type Output = NamespacedHash<NS_ID_SIZE>;
80
81 const EMPTY_ROOT: NamespacedHash<NS_ID_SIZE> = NamespacedHash {
82 min_ns: NamespaceId([0; NS_ID_SIZE]),
83 max_ns: NamespaceId([0; NS_ID_SIZE]),
84 hash: [
85 227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36, 39, 174,
86 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85,
87 ],
88 };
89
90 fn hash_leaf(&self, data: &[u8]) -> Self::Output {
91 let namespace_bytes = data[..NS_ID_SIZE].try_into().expect("Leaf of invalid size");
92 let namespace = NamespaceId(namespace_bytes);
93
94 let mut output = NamespacedHash::with_min_and_max_ns(namespace, namespace);
95 let mut hasher = DefaultHasher::new_with_prefix(LEAF_DOMAIN_SEPARATOR);
96 hasher.update(data.as_ref());
97 output.set_hash(hasher.finalize().as_ref());
98 output
99 }
100
101 fn hash_nodes(&self, left: &Self::Output, right: &Self::Output) -> Self::Output {
102 if left.max_namespace() > right.min_namespace() {
103 panic!("Invalid nodes: left max namespace must be <= right min namespace")
104 }
105 let mut hasher = DefaultHasher::new_with_prefix(INTERNAL_NODE_DOMAIN_SEPARATOR);
106 let max_nsid = NamespaceId::<NS_ID_SIZE>::max_id();
107
108 let min_ns = cmp::min(left.min_namespace(), right.min_namespace());
109 let max_ns = if self.ignore_max_ns && left.min_namespace() == max_nsid {
110 max_nsid
111 } else if self.ignore_max_ns && right.min_namespace() == max_nsid {
112 left.max_namespace()
113 } else {
114 cmp::max(left.max_namespace(), right.max_namespace())
115 };
116
117 let mut output = NamespacedHash::with_min_and_max_ns(min_ns, max_ns);
118
119 hasher.update(left.iter().collect::<Vec<_>>());
120 hasher.update(right.iter().collect::<Vec<_>>());
121
122 output.set_hash(hasher.finalize().as_ref());
123 output
124 }
125}
126
127#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Copy, Clone, Hash)]
129#[cfg_attr(any(test, feature = "borsh"), derive(borsh::BorshSerialize))]
130pub struct NamespaceId<const NS_ID_SIZE: usize>(pub [u8; NS_ID_SIZE]);
131
132impl<const NS_ID_SIZE: usize> Default for NamespaceId<NS_ID_SIZE> {
133 fn default() -> Self {
134 Self([0; NS_ID_SIZE])
135 }
136}
137
138impl<const NS_ID_SIZE: usize> NamespaceId<NS_ID_SIZE> {
139 pub const MAX_ID: NamespaceId<NS_ID_SIZE> = NamespaceId([0xff; NS_ID_SIZE]);
141 pub const MAX_RESERVED_ID_ON_CELESTIA: NamespaceId<NS_ID_SIZE> = {
143 let mut max_reserved = [0; NS_ID_SIZE];
144 max_reserved[NS_ID_SIZE - 1] = 255;
145 Self(max_reserved)
146 };
147
148 pub const fn max_id() -> Self {
150 Self::MAX_ID
151 }
152
153 pub fn is_reserved_on_celestia(&self) -> bool {
155 self <= &Self::MAX_RESERVED_ID_ON_CELESTIA
156 }
157}
158
159impl<const NS_ID_SIZE: usize> AsRef<[u8]> for NamespaceId<NS_ID_SIZE> {
160 fn as_ref(&self) -> &[u8] {
161 self.0.as_ref()
162 }
163}
164
165#[derive(Debug, PartialEq, Copy, Clone)]
167pub struct InvalidNamespace;
168
169impl fmt::Display for InvalidNamespace {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 f.write_str("InvalidNamespace")
172 }
173}
174
175#[cfg(feature = "std")]
176impl std::error::Error for InvalidNamespace {}
177
178impl<const NS_ID_SIZE: usize> TryFrom<&[u8]> for NamespaceId<NS_ID_SIZE> {
179 type Error = InvalidNamespace;
180
181 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
182 if value.len() != NS_ID_SIZE {
183 return Err(InvalidNamespace);
184 }
185 Ok(Self(value.try_into().unwrap()))
186 }
187}
188
189#[derive(Debug, PartialEq, Clone, Eq, Hash, PartialOrd, Ord)]
191#[cfg_attr(any(test, feature = "borsh"), derive(borsh::BorshSerialize))]
192pub struct NamespacedHash<const NS_ID_SIZE: usize> {
193 min_ns: NamespaceId<NS_ID_SIZE>,
194 max_ns: NamespaceId<NS_ID_SIZE>,
195 hash: [u8; HASH_LEN],
196}
197
198#[cfg(any(test, feature = "borsh"))]
199impl<const NS_ID_SIZE: usize> borsh::BorshDeserialize for NamespacedHash<NS_ID_SIZE> {
200 fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> borsh::io::Result<Self> {
201 let mut min_ns = NamespaceId([0u8; NS_ID_SIZE]);
202 reader.read_exact(&mut min_ns.0)?;
203
204 let mut max_ns = NamespaceId([0u8; NS_ID_SIZE]);
205 reader.read_exact(&mut max_ns.0)?;
206
207 let mut hash = [0u8; HASH_LEN];
208 reader.read_exact(&mut hash)?;
209
210 Ok(NamespacedHash {
211 min_ns,
212 max_ns,
213 hash,
214 })
215 }
216}
217
218#[cfg(feature = "serde")]
219impl<const NS_ID_SIZE: usize> serde::Serialize for NamespacedHash<NS_ID_SIZE> {
220 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
221 where
222 S: serde::Serializer,
223 {
224 use serde::ser::SerializeTuple;
225 let mut seq = serializer.serialize_tuple(NamespacedHash::<NS_ID_SIZE>::size())?;
226 for byte in self.iter() {
227 seq.serialize_element(&byte)?;
228 }
229 seq.end()
230 }
231}
232
233#[cfg(feature = "serde")]
234impl<'de, const NS_ID_SIZE: usize> serde::Deserialize<'de> for NamespacedHash<NS_ID_SIZE> {
235 fn deserialize<D>(deserializer: D) -> Result<Self, <D as serde::Deserializer<'de>>::Error>
236 where
237 D: serde::Deserializer<'de>,
238 {
239 struct ArrayVisitor<T, const NS_ID_SIZE: usize> {
240 element: PhantomData<[T; NS_ID_SIZE]>,
241 }
242
243 impl<'de, T, const NS_ID_SIZE: usize> serde::de::Visitor<'de> for ArrayVisitor<T, NS_ID_SIZE>
244 where
245 T: Default + Copy + serde::Deserialize<'de>,
246 {
247 type Value = NamespacedHash<NS_ID_SIZE>;
248
249 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
250 formatter.write_str(&crate::maybestd::format!(
251 "an array of length {}",
252 NamespacedHash::<NS_ID_SIZE>::size()
253 ))
254 }
255
256 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
257 where
258 A: serde::de::SeqAccess<'de>,
259 {
260 let seq: Vec<u8> = (0..NamespacedHash::<NS_ID_SIZE>::size())
261 .map(|i| {
262 seq.next_element()?
263 .ok_or_else(|| serde::de::Error::invalid_length(i, &self))
264 })
265 .collect::<Result<_, _>>()?;
266 let ns_hash = seq
267 .as_slice()
268 .try_into()
269 .map_err(|e: InvalidNamespacedHash| {
270 serde::de::Error::custom(crate::maybestd::string::ToString::to_string(&e))
271 })?;
272 Ok(ns_hash)
273 }
274 }
275
276 let visitor = ArrayVisitor {
277 element: PhantomData::<[u8; NS_ID_SIZE]>,
278 };
279
280 deserializer.deserialize_tuple(NamespacedHash::<NS_ID_SIZE>::size(), visitor)
281 }
282}
283
284impl<const NS_ID_SIZE: usize> Default for NamespacedHash<NS_ID_SIZE> {
285 fn default() -> Self {
286 Self {
287 min_ns: NamespaceId::default(),
288 max_ns: NamespaceId::default(),
289 hash: [0u8; HASH_LEN],
290 }
291 }
292}
293
294impl<const NS_ID_SIZE: usize> NamespacedHash<NS_ID_SIZE> {
295 pub const fn size() -> usize {
297 2 * NS_ID_SIZE + HASH_LEN
298 }
299
300 pub const fn new(
302 min_ns: NamespaceId<NS_ID_SIZE>,
303 max_ns: NamespaceId<NS_ID_SIZE>,
304 hash: [u8; HASH_LEN],
305 ) -> Self {
306 Self {
307 min_ns,
308 max_ns,
309 hash,
310 }
311 }
312
313 pub fn with_min_and_max_ns(
315 min_ns: NamespaceId<NS_ID_SIZE>,
316 max_ns: NamespaceId<NS_ID_SIZE>,
317 ) -> Self {
318 Self {
319 min_ns,
320 max_ns,
321 ..Default::default()
322 }
323 }
324
325 pub fn min_namespace(&self) -> NamespaceId<NS_ID_SIZE> {
327 self.min_ns
328 }
329
330 pub fn max_namespace(&self) -> NamespaceId<NS_ID_SIZE> {
332 self.max_ns
333 }
334
335 pub fn hash(&self) -> [u8; HASH_LEN] {
337 self.hash
338 }
339
340 fn set_hash(&mut self, new_hash: &[u8; HASH_LEN]) {
341 self.hash.copy_from_slice(new_hash)
342 }
343
344 pub fn contains<M: NamespaceMerkleHasher<NS_ID_SIZE, Output = Self>>(
346 &self,
347 namespace: NamespaceId<NS_ID_SIZE>,
348 ) -> bool {
349 self.min_namespace() <= namespace
350 && self.max_namespace() >= namespace
351 && !self.is_empty_root::<M>()
352 }
353
354 pub fn is_empty_root<M: NamespaceMerkleHasher<NS_ID_SIZE, Output = Self>>(&self) -> bool {
356 self == &M::EMPTY_ROOT
357 }
358
359 pub fn iter(&self) -> impl Iterator<Item = u8> {
361 self.min_ns
362 .0
363 .into_iter()
364 .chain(self.max_ns.0)
365 .chain(self.hash)
366 }
367}
368
369#[derive(Debug, PartialEq, Copy, Clone)]
371pub struct InvalidNamespacedHash;
372
373impl fmt::Display for InvalidNamespacedHash {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 f.write_str("InvalidNamespacedHash")
376 }
377}
378#[cfg(feature = "std")]
379impl std::error::Error for InvalidNamespacedHash {}
380
381impl<const NS_ID_SIZE: usize> TryFrom<&[u8]> for NamespacedHash<NS_ID_SIZE> {
382 type Error = InvalidNamespacedHash;
383
384 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
385 if value.len() != NamespacedHash::<NS_ID_SIZE>::size() {
386 return Err(InvalidNamespacedHash);
387 }
388 Ok(Self {
389 min_ns: value[..NS_ID_SIZE].try_into().unwrap(),
390 max_ns: value[NS_ID_SIZE..2 * NS_ID_SIZE].try_into().unwrap(),
391 hash: value[2 * NS_ID_SIZE..].try_into().unwrap(),
392 })
393 }
394}
395
396#[cfg(test)]
397mod tests {
398 use crate::NamespacedHash;
399 use borsh::de::BorshDeserialize;
400
401 #[test]
402 fn test_namespaced_hash_borsh() {
403 let hash = NamespacedHash::<8>::try_from([8u8; 48].as_ref()).unwrap();
404
405 let serialized = borsh::to_vec(&hash).expect("Serialization to vec must succeed");
406
407 let got =
408 NamespacedHash::deserialize(&mut &serialized[..]).expect("serialized hash is correct");
409
410 assert_eq!(got, hash);
411 }
412
413 #[cfg(feature = "serde")]
414 #[test]
415 fn test_namespaced_hash_serde_json() {
416 let hash = NamespacedHash::<8>::try_from([8u8; 48].as_ref()).unwrap();
417
418 let serialized = serde_json::to_vec(&hash).expect("Serialization to vec must succeed");
419
420 let got: NamespacedHash<8> =
421 serde_json::from_slice(&serialized[..]).expect("serialized hash is correct");
422
423 assert_eq!(got, hash);
424 }
425
426 #[cfg(feature = "serde")]
427 #[test]
428 fn test_namespaced_hash_serde_postcard() {
429 use crate::maybestd::vec::Vec;
430
431 let hash = NamespacedHash::<8>::try_from([8u8; 48].as_ref()).unwrap();
432
433 let serialized: Vec<u8> =
434 postcard::to_allocvec(&hash).expect("Serialization to vec must succeed");
435 let got: NamespacedHash<8> =
436 postcard::from_bytes(&serialized[..]).expect("serialized hash is correct");
437
438 assert_eq!(got, hash);
439 }
440}