1#[cfg(feature = "uniffi")]
21use crate::error::UniffiError;
22use base64::prelude::*;
23use blockstore::block::CidError;
24use celestia_proto::serializers::cow_str::CowStr;
25use cid::CidGeneric;
26use multihash::Multihash;
27use serde::{Deserialize, Deserializer, Serialize, Serializer};
28use tendermint::hash::SHA256_HASH_SIZE;
29#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))]
30use wasm_bindgen::prelude::*;
31
32mod namespace_proof;
33mod namespaced_hash;
34mod namespaced_merkle_tree;
35
36pub use self::namespace_proof::{NamespaceProof, EMPTY_LEAVES};
37pub use self::namespaced_hash::{
38 NamespacedHashExt, RawNamespacedHash, HASH_SIZE, NAMESPACED_HASH_SIZE,
39};
40pub use self::namespaced_merkle_tree::{MerkleHash, NamespacedSha2Hasher, Nmt, NmtExt};
41
42use crate::{Error, Result};
43
44pub use nmt_rs::NamespaceMerkleHasher;
45
46pub const NS_VER_SIZE: usize = 1;
48pub const NS_ID_SIZE: usize = 28;
50pub const NS_SIZE: usize = NS_VER_SIZE + NS_ID_SIZE;
52pub const NS_ID_V0_SIZE: usize = 10;
54
55pub const NMT_MULTIHASH_CODE: u64 = 0x7700;
57pub const NMT_CODEC: u64 = 0x7701;
59pub const NMT_ID_SIZE: usize = 2 * NS_SIZE + SHA256_HASH_SIZE;
61
62pub type NamespacedHash = nmt_rs::NamespacedHash<NS_SIZE>;
74pub type Proof = nmt_rs::simple_merkle::proof::Proof<NamespacedSha2Hasher>;
77
78#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
98#[cfg_attr(
99 all(feature = "wasm-bindgen", target_arch = "wasm32"),
100 wasm_bindgen(inspectable)
101)]
102#[cfg_attr(feature = "uniffi", derive(uniffi::Object))]
103pub struct Namespace(nmt_rs::NamespaceId<NS_SIZE>);
104
105impl Namespace {
106 pub const TRANSACTION: Namespace = Namespace::const_v0([0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
111
112 pub const PAY_FOR_BLOB: Namespace = Namespace::const_v0([0, 0, 0, 0, 0, 0, 0, 0, 0, 4]);
117
118 pub const PRIMARY_RESERVED_PADDING: Namespace = Namespace::MAX_PRIMARY_RESERVED;
126
127 pub const MAX_PRIMARY_RESERVED: Namespace =
133 Namespace::const_v0([0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff]);
134
135 pub const MIN_SECONDARY_RESERVED: Namespace = Namespace::const_v255(0);
139
140 pub const TAIL_PADDING: Namespace = Namespace::const_v255(0xfe);
147
148 pub const PARITY_SHARE: Namespace = Namespace::const_v255(0xff);
156
157 pub fn from_raw(bytes: &[u8]) -> Result<Self> {
175 if bytes.len() != NS_SIZE {
176 return Err(Error::InvalidNamespaceSize);
177 }
178
179 Namespace::new(bytes[0], &bytes[1..])
180 }
181
182 pub fn new(version: u8, id: &[u8]) -> Result<Self> {
199 match version {
200 0 => Self::new_v0(id),
201 255 => Self::new_v255(id),
202 n => Err(Error::UnsupportedNamespaceVersion(n)),
203 }
204 }
205
206 pub fn new_v0(id: &[u8]) -> Result<Self> {
237 let id_pos = match id.len() {
238 NS_ID_SIZE => NS_ID_SIZE - NS_ID_V0_SIZE,
240 n if n <= NS_ID_V0_SIZE => 0,
242 _ => return Err(Error::InvalidNamespaceSize),
244 };
245
246 let prefix = &id[..id_pos];
247 let id = &id[id_pos..];
248
249 if prefix.iter().any(|&x| x != 0) {
251 return Err(Error::InvalidNamespaceV0);
252 }
253
254 let mut bytes = [0u8; NS_SIZE];
255 bytes[NS_SIZE - id.len()..].copy_from_slice(id);
256
257 Ok(Namespace(nmt_rs::NamespaceId(bytes)))
258 }
259
260 pub(crate) const fn new_unchecked(bytes: [u8; NS_SIZE]) -> Self {
261 Namespace(nmt_rs::NamespaceId(bytes))
262 }
263
264 pub const fn const_v0(id: [u8; NS_ID_V0_SIZE]) -> Self {
274 let mut bytes = [0u8; NS_SIZE];
275 let start = NS_SIZE - NS_ID_V0_SIZE;
276
277 bytes[start] = id[0];
278 bytes[start + 1] = id[1];
279 bytes[start + 2] = id[2];
280 bytes[start + 3] = id[3];
281 bytes[start + 4] = id[4];
282 bytes[start + 5] = id[5];
283 bytes[start + 6] = id[6];
284 bytes[start + 7] = id[7];
285 bytes[start + 8] = id[8];
286 bytes[start + 9] = id[9];
287
288 Namespace(nmt_rs::NamespaceId(bytes))
289 }
290
291 pub const fn const_v255(id: u8) -> Self {
303 let mut bytes = [255u8; NS_SIZE];
304 bytes[NS_ID_SIZE] = id;
305 Namespace(nmt_rs::NamespaceId(bytes))
306 }
307
308 pub fn new_v255(id: &[u8]) -> Result<Self> {
328 if id.len() != NS_ID_SIZE {
329 return Err(Error::InvalidNamespaceSize);
330 }
331
332 let (id, prefix) = id.split_last().unwrap();
334
335 if prefix.iter().all(|&x| x == 0xff) {
336 Ok(Namespace::const_v255(*id))
337 } else {
338 Err(Error::InvalidNamespaceV255)
339 }
340 }
341
342 pub fn as_bytes(&self) -> &[u8] {
344 &self.0 .0
345 }
346
347 pub fn version(&self) -> u8 {
349 self.as_bytes()[0]
350 }
351
352 pub fn id(&self) -> &[u8] {
354 &self.as_bytes()[1..]
355 }
356
357 pub fn id_v0(&self) -> Option<&[u8]> {
359 if self.version() == 0 {
360 let start = NS_SIZE - NS_ID_V0_SIZE;
361 Some(&self.as_bytes()[start..])
362 } else {
363 None
364 }
365 }
366
367 pub fn is_reserved(&self) -> bool {
381 *self <= Namespace::MAX_PRIMARY_RESERVED || *self >= Namespace::MIN_SECONDARY_RESERVED
382 }
383}
384
385#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))]
386#[wasm_bindgen]
387impl Namespace {
388 #[wasm_bindgen(js_name = NS_SIZE, getter)]
390 pub fn js_ns_size() -> usize {
391 NS_SIZE
392 }
393
394 #[wasm_bindgen(js_name = TRANSACTION, getter)]
396 pub fn js_transaction() -> Namespace {
397 Namespace::TRANSACTION
398 }
399
400 #[wasm_bindgen(js_name = PAY_FOR_BLOB, getter)]
402 pub fn js_pay_for_blob() -> Namespace {
403 Namespace::PAY_FOR_BLOB
404 }
405
406 #[wasm_bindgen(js_name = PRIMARY_RESERVED_PADDING, getter)]
411 pub fn js_primary_reserved_padding() -> Namespace {
412 Namespace::PRIMARY_RESERVED_PADDING
413 }
414
415 #[wasm_bindgen(js_name = MAX_PRIMARY_RESERVED, getter)]
419 pub fn js_max_primary_reserved() -> Namespace {
420 Namespace::MAX_PRIMARY_RESERVED
421 }
422
423 #[wasm_bindgen(js_name = MIN_SECONDARY_RESERVED, getter)]
427 pub fn js_min_secondary_reserved() -> Namespace {
428 Namespace::MIN_SECONDARY_RESERVED
429 }
430
431 #[wasm_bindgen(js_name = TAIL_PADDING, getter)]
436 pub fn js_tail_padding() -> Namespace {
437 Namespace::TAIL_PADDING
438 }
439
440 #[wasm_bindgen(js_name = PARITY_SHARE, getter)]
446 pub fn js_parity_share() -> Namespace {
447 Namespace::PARITY_SHARE
448 }
449
450 #[wasm_bindgen(js_name = newV0)]
456 pub fn js_new_v0(id: Vec<u8>) -> Result<Self> {
457 Self::new_v0(&id.to_vec())
458 }
459
460 #[wasm_bindgen(js_name = fromRaw)]
468 pub fn js_from_raw(raw: Vec<u8>) -> Result<Self> {
469 Self::from_raw(&raw.to_vec())
470 }
471
472 #[wasm_bindgen(js_name = asBytes)]
474 pub fn js_as_bytes(&self) -> Vec<u8> {
475 self.as_bytes().to_vec()
476 }
477
478 #[wasm_bindgen(js_name = version, getter)]
480 pub fn js_version(&self) -> u8 {
481 self.version()
482 }
483
484 #[wasm_bindgen(js_name = id, getter)]
486 pub fn js_id(&self) -> Vec<u8> {
487 self.id().to_vec()
488 }
489}
490
491#[cfg(feature = "uniffi")]
492#[uniffi::export]
493impl Namespace {
494 #[uniffi::constructor(name = "new")]
504 fn uniffi_new(version: u8, id: Vec<u8>) -> Result<Self, UniffiError> {
505 Ok(Namespace::new(version, &id)?)
506 }
507
508 #[uniffi::constructor(name = "new_v0")]
521 fn uniffi_new_v0(id: Vec<u8>) -> Result<Self, UniffiError> {
522 Ok(Namespace::new_v0(&id)?)
523 }
524
525 #[uniffi::method]
527 pub fn bytes(&self) -> Vec<u8> {
528 self.as_bytes().to_vec()
529 }
530
531 #[uniffi::method(name = "version")]
533 pub fn uniffi_version(&self) -> u8 {
534 self.version()
535 }
536
537 #[uniffi::method(name = "id")]
539 pub fn uniffi_id(&self) -> Vec<u8> {
540 self.id().to_vec()
541 }
542
543 #[uniffi::method(name = "id_v0")]
545 pub fn uniffi_id_v0(&self) -> Option<Vec<u8>> {
546 self.id_v0().map(ToOwned::to_owned)
547 }
548
549 #[uniffi::method(name = "is_reserved")]
551 pub fn uniffi_is_reserved(&self) -> bool {
552 self.is_reserved()
553 }
554}
555
556impl From<Namespace> for nmt_rs::NamespaceId<NS_SIZE> {
557 fn from(value: Namespace) -> Self {
558 value.0
559 }
560}
561
562impl From<nmt_rs::NamespaceId<NS_SIZE>> for Namespace {
563 fn from(value: nmt_rs::NamespaceId<NS_SIZE>) -> Self {
564 Namespace(value)
565 }
566}
567
568impl std::ops::Deref for Namespace {
569 type Target = nmt_rs::NamespaceId<NS_SIZE>;
570
571 fn deref(&self) -> &Self::Target {
572 &self.0
573 }
574}
575
576impl Serialize for Namespace {
577 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
578 where
579 S: Serializer,
580 {
581 let s = BASE64_STANDARD.encode(self.0);
582 serializer.serialize_str(&s)
583 }
584}
585
586impl<'de> Deserialize<'de> for Namespace {
587 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
588 where
589 D: Deserializer<'de>,
590 {
591 let mut buf = [0u8; NS_SIZE * 2];
593
594 let s = CowStr::deserialize(deserializer)?;
595
596 let len = BASE64_STANDARD
597 .decode_slice(s, &mut buf)
598 .map_err(|e| serde::de::Error::custom(e.to_string()))?;
599
600 Namespace::from_raw(&buf[..len]).map_err(|e| serde::de::Error::custom(e.to_string()))
601 }
602}
603
604pub struct NodePair(NamespacedHash, NamespacedHash);
606
607impl NodePair {
608 fn validate_namespace_order(&self) -> Result<()> {
609 let NodePair(left, right) = self;
610
611 left.validate_namespace_order()?;
612 right.validate_namespace_order()?;
613
614 if left.max_namespace() > right.min_namespace() {
615 return Err(Error::InvalidNmtNodeOrder);
616 }
617
618 Ok(())
619 }
620}
621
622impl TryFrom<NodePair> for CidGeneric<NMT_ID_SIZE> {
623 type Error = CidError;
624
625 fn try_from(nodes: NodePair) -> Result<Self, Self::Error> {
626 nodes
627 .validate_namespace_order()
628 .map_err(|e| CidError::InvalidDataFormat(e.to_string()))?;
629
630 let hasher = NamespacedSha2Hasher::with_ignore_max_ns(true);
631 let digest = hasher.hash_nodes(&nodes.0, &nodes.1).to_array();
632
633 let mh = Multihash::wrap(NMT_MULTIHASH_CODE, &digest).unwrap();
634
635 Ok(CidGeneric::new_v1(NMT_CODEC, mh))
636 }
637}
638
639#[cfg(test)]
640mod tests {
641 use super::*;
642
643 #[cfg(target_arch = "wasm32")]
644 use wasm_bindgen_test::wasm_bindgen_test as test;
645
646 #[test]
647 fn namespace_id_8_bytes() {
648 let nid = Namespace::new_v0(&[1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
649
650 let expected_nid = Namespace(nmt_rs::NamespaceId([
651 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ]));
655
656 assert_eq!(nid, expected_nid);
657 }
658
659 #[test]
660 fn namespace_id_8_bytes_with_prefix() {
661 let nid = Namespace::new_v0(&[
662 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ])
665 .unwrap();
666
667 let expected_nid = Namespace(nmt_rs::NamespaceId([
668 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, ]));
672
673 assert_eq!(nid, expected_nid);
674 }
675
676 #[test]
677 fn namespace_id_10_bytes() {
678 let nid = Namespace::new_v0(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).unwrap();
679 let expected_nid = Namespace(nmt_rs::NamespaceId([
680 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ]));
684
685 assert_eq!(nid, expected_nid);
686 }
687
688 #[test]
689 fn namespace_id_max() {
690 let nid = Namespace::new(0xff, &[0xff; 28]).unwrap();
691 let expected_nid = Namespace::PARITY_SHARE;
692
693 assert_eq!(nid, expected_nid);
694 }
695
696 #[test]
697 fn namespace_id_const_v0() {
698 let nid = Namespace::const_v0([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
699 let expected_nid = Namespace(nmt_rs::NamespaceId([
700 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ]));
704
705 assert_eq!(nid, expected_nid);
706 }
707
708 #[test]
709 fn namespace_id_const_v255() {
710 let nid = Namespace::const_v255(0xab);
711 let expected_nid = Namespace(nmt_rs::NamespaceId([
712 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
714 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
715 0xff, 0xab, ]));
718
719 assert_eq!(nid, expected_nid);
720 }
721
722 #[test]
723 fn namespace_id_10_bytes_with_prefix() {
724 let nid = Namespace::new_v0(&[
725 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
727 ])
728 .unwrap();
729
730 let expected_nid = Namespace(nmt_rs::NamespaceId([
731 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ]));
735
736 assert_eq!(nid, expected_nid);
737 }
738
739 #[test]
740 fn namespace_id_with_invalid_prefix() {
741 let e = Namespace::new_v0(&[
742 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
744 ])
745 .unwrap_err();
746
747 assert!(matches!(e, Error::InvalidNamespaceV0));
748 }
749
750 #[test]
751 fn namespace_id_11_bytes() {
752 let e = Namespace::new_v0(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]).unwrap_err();
753
754 assert!(matches!(e, Error::InvalidNamespaceSize));
755 }
756
757 #[test]
758 fn namespace_id_v255_too_long() {
759 let e = Namespace::new_v255(&[0xff; 29]).unwrap_err();
760
761 assert!(matches!(e, Error::InvalidNamespaceSize));
762 }
763
764 #[test]
765 fn namespace_id_v255_too_short() {
766 let e = Namespace::new_v255(&[0xff; 27]).unwrap_err();
767
768 assert!(matches!(e, Error::InvalidNamespaceSize));
769 }
770
771 #[test]
772 fn namespace_id_max_invalid_prefix() {
773 let namespace = &[
774 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
775 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff,
776 ];
777 let e = Namespace::new_v255(namespace).unwrap_err();
778
779 assert!(matches!(e, Error::InvalidNamespaceV255));
780 }
781
782 #[test]
783 fn namespace_id_from_raw_bytes() {
784 let nid = Namespace::from_raw(&[
785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ])
789 .unwrap();
790
791 let expected_nid = Namespace(nmt_rs::NamespaceId([
792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ]));
796
797 assert_eq!(nid, expected_nid);
798 }
799
800 #[test]
801 fn namespace_id_with_28_raw_bytes() {
802 let e = Namespace::from_raw(&[
803 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ])
806 .unwrap_err();
807
808 assert!(matches!(e, Error::InvalidNamespaceSize));
809 }
810
811 #[test]
812 fn namespace_id_with_30_raw_bytes() {
813 let e = Namespace::from_raw(&[
814 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ])
819 .unwrap_err();
820
821 assert!(matches!(e, Error::InvalidNamespaceSize));
822 }
823
824 #[test]
825 fn max_namespace_id_from_raw_bytes() {
826 let nid = Namespace::from_raw(&[
827 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
828 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
829 0xff,
830 ])
831 .unwrap();
832
833 let expected_nid = Namespace::PARITY_SHARE;
834
835 assert_eq!(nid, expected_nid);
836 }
837
838 #[test]
839 fn invalid_max_namespace_id_from_raw_bytes() {
840 let e = Namespace::from_raw(&[
841 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
842 0,
843 ])
844 .unwrap_err();
845
846 assert!(matches!(e, Error::InvalidNamespaceV255));
847
848 let e = Namespace::from_raw(&[
849 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
850 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
851 0xff,
852 ])
853 .unwrap_err();
854
855 assert!(matches!(e, Error::InvalidNamespaceV255));
856 }
857
858 #[test]
859 fn invalid_version() {
860 let e = Namespace::from_raw(&[
861 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
862 ])
863 .unwrap_err();
864
865 assert!(matches!(e, Error::UnsupportedNamespaceVersion(254)));
866 }
867
868 #[test]
869 fn test_generate_inner_multihash() {
870 let ns0 = Namespace::new_v0(&[1]).unwrap();
871 let ns1 = Namespace::new_v0(&[2]).unwrap();
872 let ns2 = Namespace::new_v0(&[3]).unwrap();
873
874 let nodes = NodePair(
875 NamespacedHash::with_min_and_max_ns(*ns0, *ns1),
876 NamespacedHash::with_min_and_max_ns(*ns1, *ns2),
877 );
878
879 let cid = CidGeneric::try_from(nodes).unwrap();
880 assert_eq!(cid.codec(), NMT_CODEC);
881
882 let hash = cid.hash();
883 assert_eq!(hash.code(), NMT_MULTIHASH_CODE);
884 assert_eq!(hash.size(), NAMESPACED_HASH_SIZE as u8);
885
886 let hash = NamespacedHash::from_raw(hash.digest()).unwrap();
887 assert_eq!(hash.min_namespace(), *ns0);
888 assert_eq!(hash.max_namespace(), *ns2);
889 }
890
891 #[test]
892 fn invalid_ns_order_result() {
893 let ns0 = Namespace::new_v0(&[1]).unwrap();
894 let ns1 = Namespace::new_v0(&[2]).unwrap();
895 let ns2 = Namespace::new_v0(&[3]).unwrap();
896
897 let nodes = NodePair(
898 NamespacedHash::with_min_and_max_ns(*ns1, *ns2),
899 NamespacedHash::with_min_and_max_ns(*ns0, *ns0),
900 );
901 let result = CidGeneric::try_from(nodes).unwrap_err();
902
903 assert_eq!(
904 result,
905 CidError::InvalidDataFormat("Invalid nmt node order".to_string())
906 );
907 }
908
909 #[test]
910 fn test_read_multihash() {
911 let multihash = [
912 0x81, 0xEE, 0x01, 0x5A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
915 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
917 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
919 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
920 0xFF, 0xFF, 0xFF, 0xFF, ];
922
923 let mh = Multihash::<NAMESPACED_HASH_SIZE>::from_bytes(&multihash).unwrap();
924 assert_eq!(mh.code(), NMT_CODEC);
925 assert_eq!(mh.size(), NAMESPACED_HASH_SIZE as u8);
926 let hash = NamespacedHash::from_raw(mh.digest()).unwrap();
927 assert_eq!(hash.min_namespace(), *Namespace::new_v0(&[1]).unwrap());
928 assert_eq!(hash.max_namespace(), *Namespace::new_v0(&[9]).unwrap());
929 assert_eq!(hash.hash(), [0xFF; 32]);
930 }
931}