1use std::fmt;
5
6use crate::error::{NeoError, NeoResult};
7use crate::NeoByteString;
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Hash160([u8; 20]);
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32pub struct Hash256([u8; 32]);
33
34impl Hash160 {
35 pub const LENGTH: usize = 20;
37
38 pub const ZERO: Self = Self([0u8; 20]);
40
41 pub const fn from_bytes(bytes: [u8; 20]) -> Self {
43 Self(bytes)
44 }
45
46 pub fn try_from_slice(slice: &[u8]) -> NeoResult<Self> {
50 let bytes: [u8; 20] = slice.try_into().map_err(|_| {
51 NeoError::Custom(format!(
52 "Hash160 requires exactly 20 bytes, got {}",
53 slice.len()
54 ))
55 })?;
56 Ok(Self(bytes))
57 }
58
59 pub fn as_bytes(&self) -> &[u8; 20] {
61 &self.0
62 }
63
64 pub fn as_slice(&self) -> &[u8] {
66 &self.0
67 }
68
69 pub fn is_zero(&self) -> bool {
71 self.0 == [0u8; 20]
72 }
73
74 pub fn to_byte_string(&self) -> NeoByteString {
76 NeoByteString::from_slice(&self.0)
77 }
78}
79
80impl Hash256 {
81 pub const LENGTH: usize = 32;
83
84 pub const ZERO: Self = Self([0u8; 32]);
86
87 pub const fn from_bytes(bytes: [u8; 32]) -> Self {
89 Self(bytes)
90 }
91
92 pub fn try_from_slice(slice: &[u8]) -> NeoResult<Self> {
96 let bytes: [u8; 32] = slice.try_into().map_err(|_| {
97 NeoError::Custom(format!(
98 "Hash256 requires exactly 32 bytes, got {}",
99 slice.len()
100 ))
101 })?;
102 Ok(Self(bytes))
103 }
104
105 pub fn as_bytes(&self) -> &[u8; 32] {
107 &self.0
108 }
109
110 pub fn as_slice(&self) -> &[u8] {
112 &self.0
113 }
114
115 pub fn is_zero(&self) -> bool {
117 self.0 == [0u8; 32]
118 }
119
120 pub fn to_byte_string(&self) -> NeoByteString {
122 NeoByteString::from_slice(&self.0)
123 }
124}
125
126impl fmt::Display for Hash160 {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(f, "0x")?;
129 for byte in self.0.iter().rev() {
133 write!(f, "{:02x}", byte)?;
134 }
135 Ok(())
136 }
137}
138
139impl fmt::Display for Hash256 {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 write!(f, "0x")?;
142 for byte in self.0.iter().rev() {
143 write!(f, "{:02x}", byte)?;
144 }
145 Ok(())
146 }
147}
148
149impl TryFrom<&[u8]> for Hash160 {
150 type Error = NeoError;
151 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
152 Self::try_from_slice(slice)
153 }
154}
155
156impl TryFrom<Vec<u8>> for Hash160 {
157 type Error = NeoError;
158 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
159 Self::try_from_slice(&vec)
160 }
161}
162
163impl TryFrom<NeoByteString> for Hash160 {
164 type Error = NeoError;
165 fn try_from(bs: NeoByteString) -> Result<Self, Self::Error> {
166 Self::try_from_slice(bs.as_slice())
167 }
168}
169
170impl From<Hash160> for NeoByteString {
171 fn from(h: Hash160) -> Self {
172 h.to_byte_string()
173 }
174}
175
176impl TryFrom<&[u8]> for Hash256 {
177 type Error = NeoError;
178 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
179 Self::try_from_slice(slice)
180 }
181}
182
183impl TryFrom<Vec<u8>> for Hash256 {
184 type Error = NeoError;
185 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
186 Self::try_from_slice(&vec)
187 }
188}
189
190impl TryFrom<NeoByteString> for Hash256 {
191 type Error = NeoError;
192 fn try_from(bs: NeoByteString) -> Result<Self, Self::Error> {
193 Self::try_from_slice(bs.as_slice())
194 }
195}
196
197impl From<Hash256> for NeoByteString {
198 fn from(h: Hash256) -> Self {
199 h.to_byte_string()
200 }
201}
202
203impl AsRef<[u8]> for Hash160 {
204 fn as_ref(&self) -> &[u8] {
205 &self.0
206 }
207}
208
209impl AsRef<[u8]> for Hash256 {
210 fn as_ref(&self) -> &[u8] {
211 &self.0
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 #[test]
220 fn hash160_from_valid_bytes() {
221 let bytes = [0xABu8; 20];
222 let h = Hash160::from_bytes(bytes);
223 assert_eq!(h.as_bytes(), &[0xAB; 20]);
224 }
225
226 #[test]
227 fn hash160_try_from_wrong_length_fails() {
228 assert!(Hash160::try_from_slice(&[0u8; 19]).is_err());
229 assert!(Hash160::try_from_slice(&[0u8; 21]).is_err());
230 assert!(Hash160::try_from_slice(&[0u8; 0]).is_err());
231 }
232
233 #[test]
234 fn hash160_try_from_correct_length_succeeds() {
235 let h = Hash160::try_from_slice(&[0xFFu8; 20]).unwrap();
236 assert_eq!(h.as_bytes(), &[0xFF; 20]);
237 }
238
239 #[test]
240 fn hash160_zero() {
241 assert!(Hash160::ZERO.is_zero());
242 assert!(!Hash160::from_bytes([1; 20]).is_zero());
243 }
244
245 #[test]
246 fn hash256_from_valid_bytes() {
247 let bytes = [0xCDu8; 32];
248 let h = Hash256::from_bytes(bytes);
249 assert_eq!(h.as_bytes(), &[0xCD; 32]);
250 }
251
252 #[test]
253 fn hash256_try_from_wrong_length_fails() {
254 assert!(Hash256::try_from_slice(&[0u8; 31]).is_err());
255 assert!(Hash256::try_from_slice(&[0u8; 33]).is_err());
256 }
257
258 #[test]
259 fn hash256_try_from_correct_length_succeeds() {
260 let h = Hash256::try_from_slice(&[0xEEu8; 32]).unwrap();
261 assert_eq!(h.as_bytes(), &[0xEE; 32]);
262 }
263
264 #[test]
265 fn hash256_zero() {
266 assert!(Hash256::ZERO.is_zero());
267 assert!(!Hash256::from_bytes([1; 32]).is_zero());
268 }
269
270 #[test]
271 fn hash160_roundtrip_bytestring() {
272 let h = Hash160::from_bytes([0x42; 20]);
273 let bs: NeoByteString = h.clone().into();
274 let h2 = Hash160::try_from(bs).unwrap();
275 assert_eq!(h, h2);
276 }
277
278 #[test]
279 fn hash256_roundtrip_bytestring() {
280 let h = Hash256::from_bytes([0x42; 32]);
281 let bs: NeoByteString = h.clone().into();
282 let h2 = Hash256::try_from(bs).unwrap();
283 assert_eq!(h, h2);
284 }
285}