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 hex_string = std::str::from_utf8(hex_str)
89 .map_err(|e| AptosError::Internal(format!("Invalid UTF-8 in hex string: {e}")))?;
90
91 if hex_string.len() != HASH_LENGTH * 2 {
92 return Err(AptosError::Internal(format!(
93 "Invalid hash length: expected {} hex characters, got {}",
94 HASH_LENGTH * 2,
95 hex_string.len()
96 )));
97 }
98
99 let bytes = hex::decode(hex_string)?;
100 let mut hash = [0u8; HASH_LENGTH];
101 hash.copy_from_slice(&bytes);
102 Ok(Self(hash))
103 }
104
105 pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> AptosResult<Self> {
111 let bytes = bytes.as_ref();
112 if bytes.len() != HASH_LENGTH {
113 return Err(AptosError::Internal(format!(
114 "Invalid hash length: expected {} bytes, got {}",
115 HASH_LENGTH,
116 bytes.len()
117 )));
118 }
119 let mut hash = [0u8; HASH_LENGTH];
120 hash.copy_from_slice(bytes);
121 Ok(Self(hash))
122 }
123
124 pub fn as_bytes(&self) -> &[u8] {
126 &self.0
127 }
128
129 pub fn to_bytes(&self) -> [u8; HASH_LENGTH] {
131 self.0
132 }
133
134 pub fn to_hex(&self) -> String {
136 format!("0x{}", hex::encode(self.0))
137 }
138
139 pub fn is_zero(&self) -> bool {
141 self == &Self::ZERO
142 }
143}
144
145impl Default for HashValue {
146 fn default() -> Self {
147 Self::ZERO
148 }
149}
150
151impl fmt::Debug for HashValue {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "HashValue({})", self.to_hex())
154 }
155}
156
157impl fmt::Display for HashValue {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 write!(f, "{}", self.to_hex())
160 }
161}
162
163impl FromStr for HashValue {
164 type Err = AptosError;
165
166 fn from_str(s: &str) -> Result<Self, Self::Err> {
167 Self::from_hex(s)
168 }
169}
170
171impl Serialize for HashValue {
172 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
173 where
174 S: Serializer,
175 {
176 if serializer.is_human_readable() {
177 serializer.serialize_str(&self.to_hex())
178 } else {
179 self.0.serialize(serializer)
181 }
182 }
183}
184
185impl<'de> Deserialize<'de> for HashValue {
186 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
187 where
188 D: Deserializer<'de>,
189 {
190 if deserializer.is_human_readable() {
191 let s = String::deserialize(deserializer)?;
192 Self::from_hex(&s).map_err(serde::de::Error::custom)
193 } else {
194 let bytes = <[u8; HASH_LENGTH]>::deserialize(deserializer)?;
196 Ok(Self(bytes))
197 }
198 }
199}
200
201impl From<[u8; HASH_LENGTH]> for HashValue {
202 fn from(bytes: [u8; HASH_LENGTH]) -> Self {
203 Self(bytes)
204 }
205}
206
207impl From<HashValue> for [u8; HASH_LENGTH] {
208 fn from(hash: HashValue) -> Self {
209 hash.0
210 }
211}
212
213impl AsRef<[u8]> for HashValue {
214 fn as_ref(&self) -> &[u8] {
215 &self.0
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn test_sha3_256() {
225 let hash = HashValue::sha3_256(b"hello world");
226 assert!(!hash.is_zero());
227
228 let hash2 = HashValue::sha3_256(b"hello world");
230 assert_eq!(hash, hash2);
231
232 let hash3 = HashValue::sha3_256(b"hello world!");
234 assert_ne!(hash, hash3);
235 }
236
237 #[test]
238 fn test_sha3_256_of_multiple() {
239 let hash1 = HashValue::sha3_256_of([b"hello" as &[u8], b" " as &[u8], b"world" as &[u8]]);
240 let hash2 = HashValue::sha3_256(b"hello world");
241 assert_eq!(hash1, hash2);
242 }
243
244 #[test]
245 fn test_from_hex() {
246 let hash = HashValue::sha3_256(b"test");
247 let hex = hash.to_hex();
248 let parsed = HashValue::from_hex(&hex).unwrap();
249 assert_eq!(hash, parsed);
250
251 let parsed2 = HashValue::from_hex(&hex[2..]).unwrap();
253 assert_eq!(hash, parsed2);
254
255 let hex_upper = hex.replace("0x", "0X");
257 let parsed3 = HashValue::from_hex(&hex_upper).unwrap();
258 assert_eq!(hash, parsed3);
259 }
260
261 #[test]
262 fn test_from_hex_invalid_length() {
263 let result = HashValue::from_hex("0x1234");
264 assert!(result.is_err());
265 }
266
267 #[test]
268 fn test_from_hex_invalid_chars() {
269 let result = HashValue::from_hex("0xZZZZ");
270 assert!(result.is_err());
271 }
272
273 #[test]
274 fn test_from_bytes() {
275 let bytes = [1u8; HASH_LENGTH];
276 let hash = HashValue::new(bytes);
277 assert_eq!(hash.as_bytes(), &bytes);
278 }
279
280 #[test]
281 fn test_json_serialization() {
282 let hash = HashValue::sha3_256(b"test");
283 let json = serde_json::to_string(&hash).unwrap();
284 let parsed: HashValue = serde_json::from_str(&json).unwrap();
285 assert_eq!(hash, parsed);
286 }
287
288 #[test]
289 fn test_zero_hash() {
290 assert!(HashValue::ZERO.is_zero());
291 assert!(!HashValue::sha3_256(b"").is_zero());
292 }
293
294 #[test]
295 fn test_new() {
296 let bytes = [42u8; HASH_LENGTH];
297 let hash = HashValue::new(bytes);
298 assert_eq!(hash.as_bytes(), &bytes);
299 }
300
301 #[test]
302 fn test_display() {
303 let hash = HashValue::ZERO;
304 let display = format!("{hash}");
305 assert!(display.starts_with("0x"));
306 assert_eq!(display.len(), 66); }
308
309 #[test]
310 fn test_debug() {
311 let hash = HashValue::ZERO;
312 let debug = format!("{hash:?}");
313 assert!(debug.contains("HashValue"));
314 }
315
316 #[test]
317 fn test_from_str() {
318 let hash = HashValue::sha3_256(b"test");
319 let hex = hash.to_hex();
320 let parsed: HashValue = hex.parse().unwrap();
321 assert_eq!(hash, parsed);
322 }
323
324 #[test]
325 fn test_ordering() {
326 let hash1 = HashValue::new([0u8; HASH_LENGTH]);
327 let hash2 = HashValue::new([1u8; HASH_LENGTH]);
328 assert!(hash1 < hash2);
329 }
330
331 #[test]
332 fn test_as_ref() {
333 let hash = HashValue::sha3_256(b"test");
334 let slice: &[u8] = hash.as_ref();
335 assert_eq!(slice.len(), HASH_LENGTH);
336 }
337
338 #[test]
339 fn test_from_bytes_valid() {
340 let bytes = [42u8; HASH_LENGTH];
341 let hash = HashValue::from_bytes(bytes).unwrap();
342 assert_eq!(hash.as_bytes(), &bytes);
343 }
344
345 #[test]
346 fn test_from_bytes_invalid_length() {
347 let bytes = vec![0u8; 16]; let result = HashValue::from_bytes(&bytes);
349 assert!(result.is_err());
350 }
351
352 #[test]
353 fn test_to_bytes() {
354 let bytes = [42u8; HASH_LENGTH];
355 let hash = HashValue::new(bytes);
356 assert_eq!(hash.to_bytes(), bytes);
357 }
358
359 #[test]
360 fn test_default() {
361 let hash = HashValue::default();
362 assert!(hash.is_zero());
363 assert_eq!(hash, HashValue::ZERO);
364 }
365
366 #[test]
367 fn test_from_array() {
368 let bytes = [1u8; HASH_LENGTH];
369 let hash: HashValue = bytes.into();
370 assert_eq!(hash.as_bytes(), &bytes);
371 }
372
373 #[test]
374 fn test_into_array() {
375 let bytes = [1u8; HASH_LENGTH];
376 let hash = HashValue::new(bytes);
377 let extracted: [u8; HASH_LENGTH] = hash.into();
378 assert_eq!(extracted, bytes);
379 }
380
381 #[test]
382 fn test_hash_equality() {
383 let hash1 = HashValue::sha3_256(b"test");
384 let hash2 = HashValue::sha3_256(b"test");
385 let hash3 = HashValue::sha3_256(b"different");
386
387 assert_eq!(hash1, hash2);
388 assert_ne!(hash1, hash3);
389 }
390
391 #[test]
392 fn test_hash_clone() {
393 let hash = HashValue::sha3_256(b"test");
394 let cloned = hash;
395 assert_eq!(hash, cloned);
396 }
397
398 #[test]
399 fn test_hash_copy() {
400 let hash = HashValue::sha3_256(b"test");
401 let copied = hash;
402 assert_eq!(hash, copied);
403 }
404
405 #[test]
406 fn test_hash_in_hashmap() {
407 use std::collections::HashMap;
408
409 let hash1 = HashValue::sha3_256(b"key1");
410 let hash2 = HashValue::sha3_256(b"key2");
411
412 let mut map = HashMap::new();
413 map.insert(hash1, "value1");
414 map.insert(hash2, "value2");
415
416 assert_eq!(map.get(&hash1), Some(&"value1"));
417 assert_eq!(map.get(&hash2), Some(&"value2"));
418 }
419
420 #[test]
421 fn test_from_hex_with_bytes() {
422 let hash = HashValue::sha3_256(b"test");
423 let hex_bytes = hash.to_hex().into_bytes();
424 let parsed = HashValue::from_hex(&hex_bytes).unwrap();
425 assert_eq!(hash, parsed);
426 }
427
428 #[test]
429 fn test_sha3_256_empty() {
430 let hash = HashValue::sha3_256(b"");
431 assert!(!hash.is_zero()); }
433
434 #[test]
435 fn test_sha3_256_of_empty() {
436 let hash = HashValue::sha3_256_of::<[&[u8]; 0], &[u8]>([]);
437 assert!(!hash.is_zero());
438 }
439
440 #[test]
441 fn test_sha3_256_of_single() {
442 let hash1 = HashValue::sha3_256_of([b"test" as &[u8]]);
443 let hash2 = HashValue::sha3_256(b"test");
444 assert_eq!(hash1, hash2);
445 }
446
447 #[test]
448 fn test_json_human_readable_serialization_roundtrip() {
449 let hash = HashValue::sha3_256(b"test");
451 let json = serde_json::to_string(&hash).unwrap();
452
453 assert!(json.starts_with('"'));
455 assert!(json.contains("0x"));
456
457 let deserialized: HashValue = serde_json::from_str(&json).unwrap();
458 assert_eq!(hash, deserialized);
459 }
460
461 #[test]
462 fn test_bcs_binary_serialization_roundtrip() {
463 let hash = HashValue::sha3_256(b"test");
465 let serialized = aptos_bcs::to_bytes(&hash).unwrap();
466
467 assert_eq!(serialized.len(), HASH_LENGTH);
469
470 let deserialized: HashValue = aptos_bcs::from_bytes(&serialized).unwrap();
471 assert_eq!(hash, deserialized);
472 }
473
474 #[test]
475 fn test_bcs_binary_serialization_zero_hash() {
476 let hash = HashValue::ZERO;
478 let serialized = aptos_bcs::to_bytes(&hash).unwrap();
479 let deserialized: HashValue = aptos_bcs::from_bytes(&serialized).unwrap();
480 assert_eq!(hash, deserialized);
481 assert!(deserialized.is_zero());
482 }
483}