1use crate::error::{AptosError, AptosResult};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use sha3::{Digest, Sha3_256};
9use std::fmt;
10use std::str::FromStr;
11
12pub const HASH_LENGTH: usize = 32;
14
15#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct HashValue([u8; HASH_LENGTH]);
38
39impl HashValue {
40 pub const ZERO: Self = Self([0u8; HASH_LENGTH]);
42
43 pub const fn new(bytes: [u8; HASH_LENGTH]) -> Self {
45 Self(bytes)
46 }
47
48 pub fn sha3_256<T: AsRef<[u8]>>(data: T) -> Self {
50 let mut hasher = Sha3_256::new();
51 hasher.update(data.as_ref());
52 let result = hasher.finalize();
53 let mut bytes = [0u8; HASH_LENGTH];
54 bytes.copy_from_slice(&result);
55 Self(bytes)
56 }
57
58 pub fn sha3_256_of<I, T>(items: I) -> Self
60 where
61 I: IntoIterator<Item = T>,
62 T: AsRef<[u8]>,
63 {
64 let mut hasher = Sha3_256::new();
65 for item in items {
66 hasher.update(item.as_ref());
67 }
68 let result = hasher.finalize();
69 let mut bytes = [0u8; HASH_LENGTH];
70 bytes.copy_from_slice(&result);
71 Self(bytes)
72 }
73
74 pub fn from_hex<T: AsRef<[u8]>>(hex_str: T) -> AptosResult<Self> {
81 let hex_str = hex_str.as_ref();
82 let hex_str = if hex_str.starts_with(b"0x") || hex_str.starts_with(b"0X") {
83 &hex_str[2..]
84 } else {
85 hex_str
86 };
87
88 let mut hash = [0u8; HASH_LENGTH];
89 const_hex::decode_to_slice(hex_str, &mut hash)?;
90 Ok(Self(hash))
91 }
92
93 pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> AptosResult<Self> {
99 let bytes = bytes.as_ref();
100 if bytes.len() != HASH_LENGTH {
101 return Err(AptosError::Internal(format!(
102 "Invalid hash length: expected {} bytes, got {}",
103 HASH_LENGTH,
104 bytes.len()
105 )));
106 }
107 let mut hash = [0u8; HASH_LENGTH];
108 hash.copy_from_slice(bytes);
109 Ok(Self(hash))
110 }
111
112 pub fn as_bytes(&self) -> &[u8] {
114 &self.0
115 }
116
117 pub fn to_bytes(&self) -> [u8; HASH_LENGTH] {
119 self.0
120 }
121
122 pub fn to_hex(&self) -> String {
124 const_hex::encode_prefixed(self.0)
125 }
126
127 pub fn is_zero(&self) -> bool {
129 self == &Self::ZERO
130 }
131}
132
133impl Default for HashValue {
134 fn default() -> Self {
135 Self::ZERO
136 }
137}
138
139impl fmt::Debug for HashValue {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 write!(f, "HashValue({})", self.to_hex())
142 }
143}
144
145impl fmt::Display for HashValue {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 write!(f, "{}", self.to_hex())
148 }
149}
150
151impl FromStr for HashValue {
152 type Err = AptosError;
153
154 fn from_str(s: &str) -> Result<Self, Self::Err> {
155 Self::from_hex(s)
156 }
157}
158
159impl Serialize for HashValue {
160 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
161 where
162 S: Serializer,
163 {
164 if serializer.is_human_readable() {
165 serializer.serialize_str(&self.to_hex())
166 } else {
167 self.0.serialize(serializer)
169 }
170 }
171}
172
173impl<'de> Deserialize<'de> for HashValue {
174 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
175 where
176 D: Deserializer<'de>,
177 {
178 if deserializer.is_human_readable() {
179 let s = String::deserialize(deserializer)?;
180 Self::from_hex(&s).map_err(serde::de::Error::custom)
181 } else {
182 let bytes = <[u8; HASH_LENGTH]>::deserialize(deserializer)?;
184 Ok(Self(bytes))
185 }
186 }
187}
188
189impl From<[u8; HASH_LENGTH]> for HashValue {
190 fn from(bytes: [u8; HASH_LENGTH]) -> Self {
191 Self(bytes)
192 }
193}
194
195impl From<HashValue> for [u8; HASH_LENGTH] {
196 fn from(hash: HashValue) -> Self {
197 hash.0
198 }
199}
200
201impl AsRef<[u8]> for HashValue {
202 fn as_ref(&self) -> &[u8] {
203 &self.0
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn test_sha3_256() {
213 let hash = HashValue::sha3_256(b"hello world");
214 assert!(!hash.is_zero());
215
216 let hash2 = HashValue::sha3_256(b"hello world");
218 assert_eq!(hash, hash2);
219
220 let hash3 = HashValue::sha3_256(b"hello world!");
222 assert_ne!(hash, hash3);
223 }
224
225 #[test]
226 fn test_sha3_256_of_multiple() {
227 let hash1 = HashValue::sha3_256_of([b"hello" as &[u8], b" " as &[u8], b"world" as &[u8]]);
228 let hash2 = HashValue::sha3_256(b"hello world");
229 assert_eq!(hash1, hash2);
230 }
231
232 #[test]
233 fn test_from_hex() {
234 let hash = HashValue::sha3_256(b"test");
235 let hex = hash.to_hex();
236 let parsed = HashValue::from_hex(&hex).unwrap();
237 assert_eq!(hash, parsed);
238
239 let parsed2 = HashValue::from_hex(&hex[2..]).unwrap();
241 assert_eq!(hash, parsed2);
242
243 let hex_upper = hex.replace("0x", "0X");
245 let parsed3 = HashValue::from_hex(&hex_upper).unwrap();
246 assert_eq!(hash, parsed3);
247 }
248
249 #[test]
250 fn test_from_hex_invalid_length() {
251 let result = HashValue::from_hex("0x1234");
252 assert!(result.is_err());
253 }
254
255 #[test]
256 fn test_from_hex_invalid_chars() {
257 let result = HashValue::from_hex("0xZZZZ");
258 assert!(result.is_err());
259 }
260
261 #[test]
262 fn test_from_bytes() {
263 let bytes = [1u8; HASH_LENGTH];
264 let hash = HashValue::new(bytes);
265 assert_eq!(hash.as_bytes(), &bytes);
266 }
267
268 #[test]
269 fn test_json_serialization() {
270 let hash = HashValue::sha3_256(b"test");
271 let json = serde_json::to_string(&hash).unwrap();
272 let parsed: HashValue = serde_json::from_str(&json).unwrap();
273 assert_eq!(hash, parsed);
274 }
275
276 #[test]
277 fn test_zero_hash() {
278 assert!(HashValue::ZERO.is_zero());
279 assert!(!HashValue::sha3_256(b"").is_zero());
280 }
281
282 #[test]
283 fn test_new() {
284 let bytes = [42u8; HASH_LENGTH];
285 let hash = HashValue::new(bytes);
286 assert_eq!(hash.as_bytes(), &bytes);
287 }
288
289 #[test]
290 fn test_display() {
291 let hash = HashValue::ZERO;
292 let display = format!("{hash}");
293 assert!(display.starts_with("0x"));
294 assert_eq!(display.len(), 66); }
296
297 #[test]
298 fn test_debug() {
299 let hash = HashValue::ZERO;
300 let debug = format!("{hash:?}");
301 assert!(debug.contains("HashValue"));
302 }
303
304 #[test]
305 fn test_from_str() {
306 let hash = HashValue::sha3_256(b"test");
307 let hex = hash.to_hex();
308 let parsed: HashValue = hex.parse().unwrap();
309 assert_eq!(hash, parsed);
310 }
311
312 #[test]
313 fn test_ordering() {
314 let hash1 = HashValue::new([0u8; HASH_LENGTH]);
315 let hash2 = HashValue::new([1u8; HASH_LENGTH]);
316 assert!(hash1 < hash2);
317 }
318
319 #[test]
320 fn test_as_ref() {
321 let hash = HashValue::sha3_256(b"test");
322 let slice: &[u8] = hash.as_ref();
323 assert_eq!(slice.len(), HASH_LENGTH);
324 }
325
326 #[test]
327 fn test_from_bytes_valid() {
328 let bytes = [42u8; HASH_LENGTH];
329 let hash = HashValue::from_bytes(bytes).unwrap();
330 assert_eq!(hash.as_bytes(), &bytes);
331 }
332
333 #[test]
334 fn test_from_bytes_invalid_length() {
335 let bytes = vec![0u8; 16]; let result = HashValue::from_bytes(&bytes);
337 assert!(result.is_err());
338 }
339
340 #[test]
341 fn test_to_bytes() {
342 let bytes = [42u8; HASH_LENGTH];
343 let hash = HashValue::new(bytes);
344 assert_eq!(hash.to_bytes(), bytes);
345 }
346
347 #[test]
348 fn test_default() {
349 let hash = HashValue::default();
350 assert!(hash.is_zero());
351 assert_eq!(hash, HashValue::ZERO);
352 }
353
354 #[test]
355 fn test_from_array() {
356 let bytes = [1u8; HASH_LENGTH];
357 let hash: HashValue = bytes.into();
358 assert_eq!(hash.as_bytes(), &bytes);
359 }
360
361 #[test]
362 fn test_into_array() {
363 let bytes = [1u8; HASH_LENGTH];
364 let hash = HashValue::new(bytes);
365 let extracted: [u8; HASH_LENGTH] = hash.into();
366 assert_eq!(extracted, bytes);
367 }
368
369 #[test]
370 fn test_hash_equality() {
371 let hash1 = HashValue::sha3_256(b"test");
372 let hash2 = HashValue::sha3_256(b"test");
373 let hash3 = HashValue::sha3_256(b"different");
374
375 assert_eq!(hash1, hash2);
376 assert_ne!(hash1, hash3);
377 }
378
379 #[test]
380 fn test_hash_clone() {
381 let hash = HashValue::sha3_256(b"test");
382 let cloned = hash;
383 assert_eq!(hash, cloned);
384 }
385
386 #[test]
387 fn test_hash_copy() {
388 let hash = HashValue::sha3_256(b"test");
389 let copied = hash;
390 assert_eq!(hash, copied);
391 }
392
393 #[test]
394 fn test_hash_in_hashmap() {
395 use std::collections::HashMap;
396
397 let hash1 = HashValue::sha3_256(b"key1");
398 let hash2 = HashValue::sha3_256(b"key2");
399
400 let mut map = HashMap::new();
401 map.insert(hash1, "value1");
402 map.insert(hash2, "value2");
403
404 assert_eq!(map.get(&hash1), Some(&"value1"));
405 assert_eq!(map.get(&hash2), Some(&"value2"));
406 }
407
408 #[test]
409 fn test_from_hex_with_bytes() {
410 let hash = HashValue::sha3_256(b"test");
411 let hex_bytes = hash.to_hex().into_bytes();
412 let parsed = HashValue::from_hex(&hex_bytes).unwrap();
413 assert_eq!(hash, parsed);
414 }
415
416 #[test]
417 fn test_sha3_256_empty() {
418 let hash = HashValue::sha3_256(b"");
419 assert!(!hash.is_zero()); }
421
422 #[test]
423 fn test_sha3_256_of_empty() {
424 let hash = HashValue::sha3_256_of::<[&[u8]; 0], &[u8]>([]);
425 assert!(!hash.is_zero());
426 }
427
428 #[test]
429 fn test_sha3_256_of_single() {
430 let hash1 = HashValue::sha3_256_of([b"test" as &[u8]]);
431 let hash2 = HashValue::sha3_256(b"test");
432 assert_eq!(hash1, hash2);
433 }
434
435 #[test]
436 fn test_json_human_readable_serialization_roundtrip() {
437 let hash = HashValue::sha3_256(b"test");
439 let json = serde_json::to_string(&hash).unwrap();
440
441 assert!(json.starts_with('"'));
443 assert!(json.contains("0x"));
444
445 let deserialized: HashValue = serde_json::from_str(&json).unwrap();
446 assert_eq!(hash, deserialized);
447 }
448
449 #[test]
450 fn test_bcs_binary_serialization_roundtrip() {
451 let hash = HashValue::sha3_256(b"test");
453 let serialized = aptos_bcs::to_bytes(&hash).unwrap();
454
455 assert_eq!(serialized.len(), HASH_LENGTH);
457
458 let deserialized: HashValue = aptos_bcs::from_bytes(&serialized).unwrap();
459 assert_eq!(hash, deserialized);
460 }
461
462 #[test]
463 fn test_bcs_binary_serialization_zero_hash() {
464 let hash = HashValue::ZERO;
466 let serialized = aptos_bcs::to_bytes(&hash).unwrap();
467 let deserialized: HashValue = aptos_bcs::from_bytes(&serialized).unwrap();
468 assert_eq!(hash, deserialized);
469 assert!(deserialized.is_zero());
470 }
471}