celestia_types/
hash.rs

1//! Celestia hash related types and traits.
2
3/// The hash type used commonly in the Celestia.
4pub type Hash = tendermint::hash::Hash;
5
6/// A trait extending [`Hash`] functionality.
7///
8/// [`Hash`]: crate::hash::Hash
9pub trait HashExt {
10    /// Get the `SHA256` hash of an empty input.
11    ///
12    /// This is equivalent to `sha256sum /dev/null`.
13    fn default_sha256() -> Hash;
14}
15
16impl HashExt for Hash {
17    fn default_sha256() -> Hash {
18        Hash::Sha256([
19            0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
20            0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
21            0x78, 0x52, 0xb8, 0x55,
22        ])
23    }
24}
25
26#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
27pub use wbg::*;
28
29#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
30mod wbg {
31    use super::Hash;
32    use js_sys::Uint8Array;
33    use tendermint::hash::{Algorithm, SHA256_HASH_SIZE};
34
35    /// Hash digest
36    pub struct JsHash {
37        /// Sha256 or empty hash
38        hash: Option<Uint8Array>,
39    }
40
41    impl From<Hash> for JsHash {
42        fn from(value: Hash) -> Self {
43            match value {
44                Hash::None => JsHash { hash: None },
45                Hash::Sha256(digest) => {
46                    let array = Uint8Array::new_with_length(
47                        SHA256_HASH_SIZE.try_into().expect("valid hash size"),
48                    );
49                    array.copy_from(&digest);
50                    JsHash { hash: Some(array) }
51                }
52            }
53        }
54    }
55
56    impl TryFrom<JsHash> for Hash {
57        type Error = tendermint::Error;
58
59        fn try_from(value: JsHash) -> Result<Self, Self::Error> {
60            let Some(digest) = value.hash else {
61                return Ok(Hash::None);
62            };
63
64            Hash::from_bytes(Algorithm::Sha256, &digest.to_vec())
65        }
66    }
67}
68
69/// uniffi conversion types
70#[cfg(feature = "uniffi")]
71pub mod uniffi_types {
72    use super::Hash as TendermintHash;
73    use tendermint::hash::Algorithm;
74    use tendermint::hash::AppHash as TendermintAppHash;
75
76    use uniffi::{Enum, Record};
77
78    use crate::error::UniffiConversionError;
79
80    /// Hash digest
81    #[derive(Enum)]
82    pub enum UniffiHash {
83        /// SHA-256 hash
84        Sha256 {
85            /// hash value
86            hash: Vec<u8>,
87        },
88        /// Empty hash
89        None,
90    }
91
92    impl TryFrom<UniffiHash> for TendermintHash {
93        type Error = UniffiConversionError;
94
95        fn try_from(value: UniffiHash) -> Result<Self, Self::Error> {
96            Ok(match value {
97                UniffiHash::Sha256 { hash } => TendermintHash::from_bytes(Algorithm::Sha256, &hash)
98                    .map_err(|_| UniffiConversionError::InvalidHashLength)?,
99                UniffiHash::None => TendermintHash::None,
100            })
101        }
102    }
103
104    impl From<TendermintHash> for UniffiHash {
105        fn from(value: TendermintHash) -> Self {
106            match value {
107                TendermintHash::Sha256(hash) => UniffiHash::Sha256 {
108                    hash: hash.to_vec(),
109                },
110                TendermintHash::None => UniffiHash::None,
111            }
112        }
113    }
114
115    uniffi::custom_type!(TendermintHash, UniffiHash, {
116        remote,
117        try_lift: |value| Ok(value.try_into()?),
118        lower: |value| value.into()
119    });
120
121    /// AppHash is usually a SHA256 hash, but in reality it can be any kind of data
122    #[derive(Record)]
123    pub struct AppHash {
124        /// AppHash value
125        pub hash: Vec<u8>,
126    }
127
128    impl TryFrom<AppHash> for TendermintAppHash {
129        type Error = UniffiConversionError;
130
131        fn try_from(value: AppHash) -> Result<Self, Self::Error> {
132            Ok(TendermintAppHash::try_from(value.hash).expect("conversion to be infallible"))
133        }
134    }
135
136    impl From<TendermintAppHash> for AppHash {
137        fn from(value: TendermintAppHash) -> Self {
138            AppHash {
139                hash: value.as_bytes().to_vec(),
140            }
141        }
142    }
143
144    uniffi::custom_type!(TendermintAppHash, AppHash, {
145        remote,
146        try_lift: |value| Ok(value.try_into()?),
147        lower: |value| value.into(),
148    });
149}