concordium_contracts_common/
hashes.rs1use crate::constants::SHA256;
4#[cfg(all(feature = "derive-serde", not(feature = "std")))]
5use core::str::FromStr;
6#[cfg(not(feature = "std"))]
7use core::{
8 convert::{TryFrom, TryInto},
9 fmt, hash,
10 marker::PhantomData,
11 ops::Deref,
12};
13#[cfg(feature = "derive-serde")]
14use serde;
15#[cfg(all(feature = "derive-serde", feature = "std"))]
16use std::str::FromStr;
17#[cfg(feature = "std")]
18use std::{
19 convert::{TryFrom, TryInto},
20 fmt, hash,
21 marker::PhantomData,
22 ops::Deref,
23};
24
25#[derive(Ord, PartialOrd, Copy)]
26#[cfg_attr(feature = "derive-serde", derive(serde::Serialize))]
27#[cfg_attr(feature = "derive-serde", serde(into = "String"))]
28#[repr(transparent)]
29pub struct HashBytes<Purpose> {
34 pub bytes: [u8; SHA256],
35 #[cfg_attr(feature = "derive-serde", serde(skip))] _phantom: PhantomData<Purpose>,
37}
38
39impl<Purpose> PartialEq for HashBytes<Purpose> {
40 fn eq(&self, other: &Self) -> bool { self.bytes == other.bytes }
41}
42
43impl<Purpose> Eq for HashBytes<Purpose> {}
44
45impl<Purpose> hash::Hash for HashBytes<Purpose> {
46 fn hash<H: hash::Hasher>(&self, state: &mut H) { self.bytes.hash(state); }
47}
48
49impl<Purpose> Clone for HashBytes<Purpose> {
50 fn clone(&self) -> Self {
51 Self {
52 bytes: self.bytes,
53 _phantom: Default::default(),
54 }
55 }
56}
57
58impl<Purpose> crate::Serial for HashBytes<Purpose> {
59 fn serial<W: crate::Write>(&self, out: &mut W) -> Result<(), W::Err> {
60 out.write_all(self.as_ref())
61 }
62}
63
64impl<Purpose> crate::Deserial for HashBytes<Purpose> {
65 fn deserial<R: crate::Read>(source: &mut R) -> crate::ParseResult<Self> {
66 let bytes: [u8; 32] = <[u8; 32]>::deserial(source)?;
67 Ok(bytes.into())
68 }
69}
70
71#[doc(hidden)]
72#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
73pub enum ModuleReferenceMarker {}
75
76pub type ModuleReference = HashBytes<ModuleReferenceMarker>;
78
79#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
80pub enum PureHashMarker {}
83
84pub type Hash = HashBytes<PureHashMarker>;
86
87#[cfg(feature = "derive-serde")]
88#[derive(Debug, thiserror::Error)]
89pub enum HashFromStrError {
92 #[cfg_attr(feature = "derive-serde", error("Not a valid hex string: {0}"))]
93 HexDecodeError(#[from] hex::FromHexError),
94 #[cfg_attr(feature = "derive-serde", error("Incorrect length, found {found}, expected 32."))]
95 IncorrectLength {
96 found: usize,
98 },
99}
100
101impl<Purpose> HashBytes<Purpose> {
102 pub const fn new(bytes: [u8; SHA256]) -> Self {
104 Self {
105 bytes,
106 _phantom: PhantomData,
107 }
108 }
109}
110
111impl<Purpose> From<[u8; 32]> for HashBytes<Purpose> {
112 fn from(array: [u8; 32]) -> Self { Self::new(array) }
113}
114
115impl<Purpose> Deref for HashBytes<Purpose> {
116 type Target = [u8];
117
118 fn deref(&self) -> &Self::Target { &self.bytes }
119}
120
121impl<Purpose> AsRef<[u8]> for HashBytes<Purpose> {
122 fn as_ref(&self) -> &[u8] { self }
123}
124
125#[cfg(feature = "derive-serde")]
126impl<Purpose> FromStr for HashBytes<Purpose> {
127 type Err = HashFromStrError;
128
129 fn from_str(s: &str) -> Result<Self, Self::Err> {
130 let hex_decoded = hex::decode(s)?;
131 let found = hex_decoded.len();
132 let bytes = hex_decoded.try_into().map_err(|_| HashFromStrError::IncorrectLength {
133 found,
134 })?;
135 Ok(HashBytes::new(bytes))
136 }
137}
138
139#[cfg(feature = "derive-serde")]
140impl<Purpose> TryFrom<&str> for HashBytes<Purpose> {
141 type Error = HashFromStrError;
142
143 fn try_from(value: &str) -> Result<Self, Self::Error> { Self::from_str(value) }
144}
145
146#[derive(Debug)]
147#[cfg_attr(feature = "derive-serde", derive(thiserror::Error))]
148#[cfg_attr(feature = "derive-serde", error("Slice has incompatible length with a hash."))]
149pub struct IncorrectLength;
150
151impl<Purpose> TryFrom<&[u8]> for HashBytes<Purpose> {
152 type Error = IncorrectLength;
153
154 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
155 let bytes: [u8; SHA256] = value.try_into().map_err(|_| IncorrectLength)?;
156 Ok(bytes.into())
157 }
158}
159
160#[cfg(feature = "derive-serde")]
166impl<'de, Purpose> serde::Deserialize<'de> for HashBytes<Purpose> {
167 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
168 where
169 D: serde::Deserializer<'de>, {
170 struct HashBytesVisitor<Purpose> {
171 _phantom: PhantomData<Purpose>,
172 }
173
174 impl<'de, Purpose> serde::de::Visitor<'de> for HashBytesVisitor<Purpose> {
175 type Value = HashBytes<Purpose>;
176
177 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
178 write!(formatter, "A hex string.")
179 }
180
181 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
182 HashBytes::try_from(v).map_err(E::custom)
183 }
184 }
185
186 deserializer.deserialize_str(HashBytesVisitor {
187 _phantom: Default::default(),
188 })
189 }
190}
191
192#[cfg(feature = "derive-serde")]
193impl<Purpose> From<HashBytes<Purpose>> for String {
194 fn from(x: HashBytes<Purpose>) -> String { x.to_string() }
195}
196
197impl<Purpose> fmt::Debug for HashBytes<Purpose> {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 for byte in self.iter().take(4) {
201 write!(f, "{:02x}", byte)?;
202 }
203 Ok(())
204 }
205}
206
207impl<Purpose> fmt::Display for HashBytes<Purpose> {
209 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210 for byte in self.iter() {
211 write!(f, "{:02x}", byte)?;
212 }
213 Ok(())
214 }
215}