1use std::{borrow::Borrow, fmt, str::FromStr};
4
5use arrayvec::ArrayString;
6use bao_tree::blake3;
7use n0_snafu::SpanTrace;
8use nested_enum_utils::common_fields;
9use postcard::experimental::max_size::MaxSize;
10use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
11use snafu::{Backtrace, ResultExt, Snafu};
12
13use crate::store::util::DD;
14
15#[derive(PartialEq, Eq, Copy, Clone, Hash)]
17pub struct Hash(blake3::Hash);
18
19impl fmt::Debug for Hash {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 f.debug_tuple("Hash").field(&DD(self.to_hex())).finish()
22 }
23}
24
25impl Hash {
26 pub const EMPTY: Hash = Hash::from_bytes([
28 175, 19, 73, 185, 245, 249, 161, 166, 160, 64, 77, 234, 54, 220, 201, 73, 155, 203, 37,
29 201, 173, 193, 18, 183, 204, 154, 147, 202, 228, 31, 50, 98,
30 ]);
31
32 pub fn new(buf: impl AsRef<[u8]>) -> Self {
34 let val = blake3::hash(buf.as_ref());
35 Hash(val)
36 }
37
38 pub fn as_bytes(&self) -> &[u8; 32] {
40 self.0.as_bytes()
41 }
42
43 pub const fn from_bytes(bytes: [u8; 32]) -> Self {
45 Self(blake3::Hash::from_bytes(bytes))
46 }
47
48 pub fn to_hex(&self) -> String {
50 self.0.to_hex().to_string()
51 }
52
53 pub fn fmt_short(&self) -> ArrayString<10> {
56 let mut res = ArrayString::new();
57 data_encoding::HEXLOWER
58 .encode_write(&self.as_bytes()[..5], &mut res)
59 .unwrap();
60 res
61 }
62}
63
64impl AsRef<[u8]> for Hash {
65 fn as_ref(&self) -> &[u8] {
66 self.0.as_bytes()
67 }
68}
69
70impl Borrow<[u8]> for Hash {
71 fn borrow(&self) -> &[u8] {
72 self.0.as_bytes()
73 }
74}
75
76impl Borrow<[u8; 32]> for Hash {
77 fn borrow(&self) -> &[u8; 32] {
78 self.0.as_bytes()
79 }
80}
81
82impl From<Hash> for blake3::Hash {
83 fn from(value: Hash) -> Self {
84 value.0
85 }
86}
87
88impl From<blake3::Hash> for Hash {
89 fn from(value: blake3::Hash) -> Self {
90 Hash(value)
91 }
92}
93
94impl From<[u8; 32]> for Hash {
95 fn from(value: [u8; 32]) -> Self {
96 Hash(blake3::Hash::from(value))
97 }
98}
99
100impl From<Hash> for [u8; 32] {
101 fn from(value: Hash) -> Self {
102 *value.as_bytes()
103 }
104}
105
106impl From<&[u8; 32]> for Hash {
107 fn from(value: &[u8; 32]) -> Self {
108 Hash(blake3::Hash::from(*value))
109 }
110}
111
112impl PartialOrd for Hash {
113 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
114 Some(self.0.as_bytes().cmp(other.0.as_bytes()))
115 }
116}
117
118impl Ord for Hash {
119 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
120 self.0.as_bytes().cmp(other.0.as_bytes())
121 }
122}
123
124impl fmt::Display for Hash {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 f.write_str(&self.to_hex())
127 }
138}
139
140#[common_fields({
141 backtrace: Option<Backtrace>,
142 #[snafu(implicit)]
143 span_trace: SpanTrace,
144})]
145#[allow(missing_docs)]
146#[non_exhaustive]
147#[derive(Debug, Snafu)]
148pub enum HexOrBase32ParseError {
149 #[snafu(display("Invalid length"))]
150 DecodeInvalidLength {},
151 #[snafu(display("Failed to decode {source}"))]
152 Decode { source: data_encoding::DecodeError },
153}
154
155impl FromStr for Hash {
156 type Err = HexOrBase32ParseError;
157
158 fn from_str(s: &str) -> Result<Self, Self::Err> {
159 let mut bytes = [0u8; 32];
160
161 let res = if s.len() == 64 {
162 data_encoding::HEXLOWER.decode_mut(s.as_bytes(), &mut bytes)
164 } else {
165 data_encoding::BASE32_NOPAD.decode_mut(s.to_ascii_uppercase().as_bytes(), &mut bytes)
166 };
167 match res {
168 Ok(len) => {
169 if len != 32 {
170 return Err(DecodeInvalidLengthSnafu.build());
171 }
172 }
173 Err(partial) => return Err(partial.error).context(DecodeSnafu),
174 }
175 Ok(Self(blake3::Hash::from_bytes(bytes)))
176 }
177}
178
179impl Serialize for Hash {
180 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
181 where
182 S: Serializer,
183 {
184 if serializer.is_human_readable() {
185 serializer.serialize_str(self.to_string().as_str())
186 } else {
187 self.0.as_bytes().serialize(serializer)
188 }
189 }
190}
191
192impl<'de> Deserialize<'de> for Hash {
193 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
194 where
195 D: Deserializer<'de>,
196 {
197 if deserializer.is_human_readable() {
198 let s = String::deserialize(deserializer)?;
199 s.parse().map_err(de::Error::custom)
200 } else {
201 let data: [u8; 32] = Deserialize::deserialize(deserializer)?;
202 Ok(Self(blake3::Hash::from(data)))
203 }
204 }
205}
206
207impl MaxSize for Hash {
208 const POSTCARD_MAX_SIZE: usize = 32;
209}
210
211#[derive(
213 Clone,
214 Copy,
215 PartialEq,
216 Eq,
217 PartialOrd,
218 Ord,
219 Serialize,
220 Deserialize,
221 Default,
222 Debug,
223 MaxSize,
224 Hash,
225 derive_more::Display,
226)]
227pub enum BlobFormat {
228 #[default]
230 Raw,
231 HashSeq,
233}
234
235impl From<BlobFormat> for u64 {
236 fn from(value: BlobFormat) -> Self {
237 match value {
238 BlobFormat::Raw => 0,
239 BlobFormat::HashSeq => 1,
240 }
241 }
242}
243
244impl BlobFormat {
245 pub const fn is_raw(&self) -> bool {
247 matches!(self, BlobFormat::Raw)
248 }
249
250 pub const fn is_hash_seq(&self) -> bool {
252 matches!(self, BlobFormat::HashSeq)
253 }
254}
255
256#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, MaxSize, Hash)]
258pub struct HashAndFormat {
259 pub hash: Hash,
261 pub format: BlobFormat,
263}
264
265impl std::fmt::Debug for HashAndFormat {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 std::fmt::Debug::fmt(&(DD(self.hash.to_hex()), self.format), f)
268 }
269}
270
271impl From<(Hash, BlobFormat)> for HashAndFormat {
272 fn from((hash, format): (Hash, BlobFormat)) -> Self {
273 Self { hash, format }
274 }
275}
276
277impl From<Hash> for HashAndFormat {
278 fn from(hash: Hash) -> Self {
279 Self {
280 hash,
281 format: BlobFormat::Raw,
282 }
283 }
284}
285
286mod redb_support {
288 use postcard::experimental::max_size::MaxSize;
289 use redb::{Key as RedbKey, Value as RedbValue};
290
291 use super::{Hash, HashAndFormat};
292
293 impl RedbValue for Hash {
294 type SelfType<'a> = Self;
295
296 type AsBytes<'a> = &'a [u8; 32];
297
298 fn fixed_width() -> Option<usize> {
299 Some(32)
300 }
301
302 fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
303 where
304 Self: 'a,
305 {
306 let contents: &'a [u8; 32] = data.try_into().unwrap();
307 (*contents).into()
308 }
309
310 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
311 where
312 Self: 'a,
313 Self: 'b,
314 {
315 value.as_bytes()
316 }
317
318 fn type_name() -> redb::TypeName {
319 redb::TypeName::new("iroh_blobs::Hash")
320 }
321 }
322
323 impl RedbKey for Hash {
324 fn compare(data1: &[u8], data2: &[u8]) -> std::cmp::Ordering {
325 data1.cmp(data2)
326 }
327 }
328
329 impl RedbValue for HashAndFormat {
330 type SelfType<'a> = Self;
331
332 type AsBytes<'a> = [u8; Self::POSTCARD_MAX_SIZE];
333
334 fn fixed_width() -> Option<usize> {
335 Some(Self::POSTCARD_MAX_SIZE)
336 }
337
338 fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
339 where
340 Self: 'a,
341 {
342 let t: &'a [u8; Self::POSTCARD_MAX_SIZE] = data.try_into().unwrap();
343 postcard::from_bytes(t.as_slice()).unwrap()
344 }
345
346 fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
347 where
348 Self: 'a,
349 Self: 'b,
350 {
351 let mut res = [0u8; 33];
352 postcard::to_slice(&value, &mut res).unwrap();
353 res
354 }
355
356 fn type_name() -> redb::TypeName {
357 redb::TypeName::new("iroh_blobs::HashAndFormat")
358 }
359 }
360}
361
362impl HashAndFormat {
363 pub fn new(hash: Hash, format: BlobFormat) -> Self {
365 Self { hash, format }
366 }
367
368 pub fn raw(hash: Hash) -> Self {
370 Self {
371 hash,
372 format: BlobFormat::Raw,
373 }
374 }
375
376 pub fn hash_seq(hash: Hash) -> Self {
378 Self {
379 hash,
380 format: BlobFormat::HashSeq,
381 }
382 }
383}
384
385impl fmt::Display for HashAndFormat {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 let mut slice = [0u8; 65];
388 hex::encode_to_slice(self.hash.as_bytes(), &mut slice[1..]).unwrap();
389 match self.format {
390 BlobFormat::Raw => {
391 write!(f, "{}", std::str::from_utf8(&slice[1..]).unwrap())
392 }
393 BlobFormat::HashSeq => {
394 slice[0] = b's';
395 write!(f, "{}", std::str::from_utf8(&slice).unwrap())
396 }
397 }
398 }
399}
400
401impl FromStr for HashAndFormat {
402 type Err = anyhow::Error;
403
404 fn from_str(s: &str) -> Result<Self, Self::Err> {
405 let s = s.as_bytes();
406 let mut hash = [0u8; 32];
407 match s.len() {
408 64 => {
409 hex::decode_to_slice(s, &mut hash)?;
410 Ok(Self::raw(hash.into()))
411 }
412 65 if s[0].eq_ignore_ascii_case(&b's') => {
413 hex::decode_to_slice(&s[1..], &mut hash)?;
414 Ok(Self::hash_seq(hash.into()))
415 }
416 _ => anyhow::bail!("invalid hash and format"),
417 }
418 }
419}
420
421impl Serialize for HashAndFormat {
422 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
423 where
424 S: Serializer,
425 {
426 if serializer.is_human_readable() {
427 serializer.serialize_str(self.to_string().as_str())
428 } else {
429 (self.hash, self.format).serialize(serializer)
430 }
431 }
432}
433
434impl<'de> Deserialize<'de> for HashAndFormat {
435 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
436 where
437 D: Deserializer<'de>,
438 {
439 if deserializer.is_human_readable() {
440 let s = String::deserialize(deserializer)?;
441 s.parse().map_err(de::Error::custom)
442 } else {
443 let (hash, format) = <(Hash, BlobFormat)>::deserialize(deserializer)?;
444 Ok(Self { hash, format })
445 }
446 }
447}
448
449#[cfg(test)]
450mod tests {
451
452 use iroh_test::{assert_eq_hex, hexdump::parse_hexdump};
453 use serde_test::{assert_tokens, Configure, Token};
454
455 use super::*;
456
457 #[test]
458 fn test_display_parse_roundtrip() {
459 for i in 0..100 {
460 let hash: Hash = blake3::hash(&[i]).into();
461 let text = hash.to_string();
462 let hash1 = text.parse::<Hash>().unwrap();
463 assert_eq!(hash, hash1);
464
465 let text = hash.to_hex();
466 let hash1 = Hash::from_str(&text).unwrap();
467 assert_eq!(hash, hash1);
468 }
469 }
470
471 #[test]
472 fn test_hash() {
473 let data = b"hello world";
474 let hash = Hash::new(data);
475
476 let encoded = hash.to_string();
477 assert_eq!(encoded.parse::<Hash>().unwrap(), hash);
478 }
479
480 #[test]
481 fn test_empty_hash() {
482 let hash = Hash::new(b"");
483 assert_eq!(hash, Hash::EMPTY);
484 }
485
486 #[test]
487 fn hash_wire_format() {
488 let hash = Hash::from([0xab; 32]);
489 let serialized = postcard::to_stdvec(&hash).unwrap();
490 let expected = parse_hexdump(r"
491 ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab # hash
492 ").unwrap();
493 assert_eq_hex!(serialized, expected);
494 }
495
496 #[test]
498 fn hash_redb() {
499 use redb::Value as RedbValue;
500 let bytes: [u8; 32] = (0..32).collect::<Vec<_>>().as_slice().try_into().unwrap();
501 let hash = Hash::from(bytes);
502 assert_eq!(<Hash as RedbValue>::fixed_width(), Some(32));
503 assert_eq!(
504 <Hash as RedbValue>::type_name(),
505 redb::TypeName::new("iroh_blobs::Hash")
506 );
507 let serialized = <Hash as RedbValue>::as_bytes(&hash);
508 assert_eq!(serialized, &bytes);
509 let deserialized = <Hash as RedbValue>::from_bytes(serialized.as_slice());
510 assert_eq!(deserialized, hash);
511 let expected = parse_hexdump(
512 r"
513 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
514 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f # hash
515 ",
516 )
517 .unwrap();
518 assert_eq_hex!(serialized, expected);
519 }
520
521 #[test]
523 fn hash_and_format_redb() {
524 use redb::Value as RedbValue;
525 let hash_bytes: [u8; 32] = (0..32).collect::<Vec<_>>().as_slice().try_into().unwrap();
526 let hash = Hash::from(hash_bytes);
527 let haf = HashAndFormat::raw(hash);
528 assert_eq!(<HashAndFormat as RedbValue>::fixed_width(), Some(33));
529 assert_eq!(
530 <HashAndFormat as RedbValue>::type_name(),
531 redb::TypeName::new("iroh_blobs::HashAndFormat")
532 );
533 let serialized = <HashAndFormat as RedbValue>::as_bytes(&haf);
534 let mut bytes = [0u8; 33];
535 bytes[0..32].copy_from_slice(&hash_bytes);
536 assert_eq!(serialized, bytes);
537 let deserialized = <HashAndFormat as RedbValue>::from_bytes(serialized.as_slice());
538 assert_eq!(deserialized, haf);
539 let expected = parse_hexdump(
540 r"
541 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
542 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f # hash
543 00 # format (raw)
544 ",
545 )
546 .unwrap();
547 assert_eq_hex!(serialized, expected);
548 }
549
550 #[test]
551 fn test_hash_serde() {
552 let hash = Hash::new("hello");
553
554 let mut tokens = Vec::new();
556 tokens.push(Token::Tuple { len: 32 });
557 for byte in hash.as_bytes() {
558 tokens.push(Token::U8(*byte));
559 }
560 tokens.push(Token::TupleEnd);
561 assert_eq!(tokens.len(), 34);
562
563 assert_tokens(&hash.compact(), &tokens);
564
565 let tokens = vec![Token::String(
566 "ea8f163db38682925e4491c5e58d4bb3506ef8c14eb78a86e908c5624a67200f",
567 )];
568 assert_tokens(&hash.readable(), &tokens);
569 }
570
571 #[test]
572 fn test_hash_postcard() {
573 let hash = Hash::new("hello");
574 let ser = postcard::to_stdvec(&hash).unwrap();
575 let de = postcard::from_bytes(&ser).unwrap();
576 assert_eq!(hash, de);
577
578 assert_eq!(ser.len(), 32);
579 }
580
581 #[test]
582 fn test_hash_json() {
583 let hash = Hash::new("hello");
584 let ser = serde_json::to_string(&hash).unwrap();
585 let de = serde_json::from_str(&ser).unwrap();
586 assert_eq!(hash, de);
587 assert_eq!(ser.len(), 66);
589 }
590
591 #[test]
592 fn test_hash_and_format_parse() {
593 let hash = Hash::new("hello");
594
595 let expected = HashAndFormat::raw(hash);
596 let actual = expected.to_string().parse::<HashAndFormat>().unwrap();
597 assert_eq!(expected, actual);
598
599 let expected = HashAndFormat::hash_seq(hash);
600 let actual = expected.to_string().parse::<HashAndFormat>().unwrap();
601 assert_eq!(expected, actual);
602 }
603
604 #[test]
605 fn test_hash_and_format_postcard() {
606 let haf = HashAndFormat::raw(Hash::new("hello"));
607 let ser = postcard::to_stdvec(&haf).unwrap();
608 let de = postcard::from_bytes(&ser).unwrap();
609 assert_eq!(haf, de);
610 }
611
612 #[test]
613 fn test_hash_and_format_json() {
614 let haf = HashAndFormat::raw(Hash::new("hello"));
615 let ser = serde_json::to_string(&haf).unwrap();
616 let de = serde_json::from_str(&ser).unwrap();
617 assert_eq!(haf, de);
618 }
619}