1use core::fmt;
2use std::str::FromStr;
3
4use arbitrary::Arbitrary;
5use bfieldcodec_derive::BFieldCodec;
6use get_size2::GetSize;
7use itertools::Itertools;
8use num_bigint::BigUint;
9use num_traits::ConstZero;
10use num_traits::Zero;
11use rand::Rng;
12use rand::distr::Distribution;
13use rand::distr::StandardUniform;
14use serde::Deserialize;
15use serde::Deserializer;
16use serde::Serialize;
17use serde::Serializer;
18
19use crate::error::TryFromDigestError;
20use crate::error::TryFromHexDigestError;
21use crate::math::b_field_element::BFieldElement;
22use crate::prelude::Tip5;
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, GetSize, BFieldCodec, Arbitrary)]
28pub struct Digest(pub [BFieldElement; Digest::LEN]);
29
30impl PartialOrd for Digest {
31 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
32 Some(self.cmp(other))
33 }
34}
35
36impl Ord for Digest {
37 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
38 let Digest(self_inner) = self;
39 let Digest(other_inner) = other;
40 let self_as_u64s = self_inner.iter().rev().map(|bfe| bfe.value());
41 let other_as_u64s = other_inner.iter().rev().map(|bfe| bfe.value());
42 self_as_u64s.cmp(other_as_u64s)
43 }
44}
45
46impl Digest {
47 pub const LEN: usize = 5;
49
50 pub const BYTES: usize = Self::LEN * BFieldElement::BYTES;
52
53 pub(crate) const ALL_ZERO: Self = Self([BFieldElement::ZERO; Self::LEN]);
55
56 pub const fn values(self) -> [BFieldElement; Self::LEN] {
57 self.0
58 }
59
60 pub const fn new(digest: [BFieldElement; Self::LEN]) -> Self {
61 Self(digest)
62 }
63
64 pub const fn reversed(self) -> Digest {
67 let Digest([d0, d1, d2, d3, d4]) = self;
68 Digest([d4, d3, d2, d1, d0])
69 }
70}
71
72impl Default for Digest {
73 fn default() -> Self {
74 Self::ALL_ZERO
75 }
76}
77
78impl fmt::Display for Digest {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "{}", self.0.map(|elem| elem.to_string()).join(","))
81 }
82}
83
84impl fmt::LowerHex for Digest {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 let bytes = <[u8; Self::BYTES]>::from(*self);
87 write!(f, "{}", hex::encode(bytes))
88 }
89}
90
91impl fmt::UpperHex for Digest {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 let bytes = <[u8; Self::BYTES]>::from(*self);
94 write!(f, "{}", hex::encode_upper(bytes))
95 }
96}
97
98impl Distribution<Digest> for StandardUniform {
99 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Digest {
100 Digest::new(rng.random())
101 }
102}
103
104impl FromStr for Digest {
105 type Err = TryFromDigestError;
106
107 fn from_str(string: &str) -> Result<Self, Self::Err> {
108 let bfes: Vec<_> = string
109 .split(',')
110 .map(str::parse::<BFieldElement>)
111 .try_collect()?;
112 let invalid_len_err = Self::Err::InvalidLength(bfes.len());
113 let digest_innards = bfes.try_into().map_err(|_| invalid_len_err)?;
114
115 Ok(Digest(digest_innards))
116 }
117}
118
119impl TryFrom<&[BFieldElement]> for Digest {
120 type Error = TryFromDigestError;
121
122 fn try_from(value: &[BFieldElement]) -> Result<Self, Self::Error> {
123 let len = value.len();
124 let maybe_digest = value.try_into().map(Digest::new);
125 maybe_digest.map_err(|_| Self::Error::InvalidLength(len))
126 }
127}
128
129impl TryFrom<Vec<BFieldElement>> for Digest {
130 type Error = TryFromDigestError;
131
132 fn try_from(value: Vec<BFieldElement>) -> Result<Self, Self::Error> {
133 Digest::try_from(&value as &[BFieldElement])
134 }
135}
136
137impl From<Digest> for Vec<BFieldElement> {
138 fn from(val: Digest) -> Self {
139 val.0.to_vec()
140 }
141}
142
143impl From<Digest> for [u8; Digest::BYTES] {
144 fn from(Digest(innards): Digest) -> Self {
145 innards
146 .map(<[u8; BFieldElement::BYTES]>::from)
147 .concat()
148 .try_into()
149 .unwrap()
150 }
151}
152
153impl TryFrom<[u8; Digest::BYTES]> for Digest {
154 type Error = TryFromDigestError;
155
156 fn try_from(item: [u8; Self::BYTES]) -> Result<Self, Self::Error> {
157 let digest_innards: Vec<_> = item
158 .chunks_exact(BFieldElement::BYTES)
159 .map(BFieldElement::try_from)
160 .try_collect()?;
161
162 Ok(Self(digest_innards.try_into().unwrap()))
163 }
164}
165
166impl TryFrom<&[u8]> for Digest {
167 type Error = TryFromDigestError;
168
169 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
170 let array = <[u8; Self::BYTES]>::try_from(slice)
171 .map_err(|_e| TryFromDigestError::InvalidLength(slice.len()))?;
172 Self::try_from(array)
173 }
174}
175
176impl TryFrom<BigUint> for Digest {
177 type Error = TryFromDigestError;
178
179 fn try_from(value: BigUint) -> Result<Self, Self::Error> {
180 let mut remaining = value;
181 let mut digest_innards = [BFieldElement::ZERO; Self::LEN];
182 let modulus: BigUint = BFieldElement::P.into();
183 for digest_element in digest_innards.iter_mut() {
184 let element = u64::try_from(remaining.clone() % modulus.clone()).unwrap();
185 *digest_element = BFieldElement::new(element);
186 remaining /= modulus.clone();
187 }
188
189 if !remaining.is_zero() {
190 return Err(Self::Error::Overflow);
191 }
192
193 Ok(Digest::new(digest_innards))
194 }
195}
196
197impl From<Digest> for BigUint {
198 fn from(digest: Digest) -> Self {
199 let Digest(digest_innards) = digest;
200 let mut ret = BigUint::zero();
201 let modulus: BigUint = BFieldElement::P.into();
202 for i in (0..Digest::LEN).rev() {
203 ret *= modulus.clone();
204 let digest_element: BigUint = digest_innards[i].value().into();
205 ret += digest_element;
206 }
207
208 ret
209 }
210}
211
212impl Digest {
213 pub fn hash(self) -> Digest {
226 Tip5::hash_pair(self, Self::ALL_ZERO)
227 }
228
229 pub fn to_hex(self) -> String {
237 format!("{self:x}")
238 }
239
240 pub fn try_from_hex(data: impl AsRef<[u8]>) -> Result<Self, TryFromHexDigestError> {
242 let slice = hex::decode(data)?;
243 Ok(Self::try_from(&slice as &[u8])?)
244 }
245}
246
247impl Serialize for Digest {
250 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
251 if serializer.is_human_readable() {
252 self.to_hex().serialize(serializer)
253 } else {
254 self.0.serialize(serializer)
255 }
256 }
257}
258
259impl<'de> Deserialize<'de> for Digest {
262 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
263 where
264 D: Deserializer<'de>,
265 {
266 if deserializer.is_human_readable() {
267 let hex_string = String::deserialize(deserializer)?;
268 Self::try_from_hex(hex_string).map_err(serde::de::Error::custom)
269 } else {
270 <[_; _]>::deserialize(deserializer).map(Self::new)
271 }
272 }
273}
274
275#[cfg(test)]
276#[cfg_attr(coverage_nightly, coverage(off))]
277pub(crate) mod tests {
278 use num_traits::One;
279 use proptest::collection::vec;
280 use proptest::prelude::Arbitrary as ProptestArbitrary;
281 use proptest::prelude::*;
282
283 use super::*;
284 use crate::error::ParseBFieldElementError;
285 use crate::prelude::*;
286 use crate::proptest_arbitrary_interop::arb;
287 use crate::tests::proptest;
288 use crate::tests::test;
289
290 impl ProptestArbitrary for Digest {
291 type Parameters = ();
292 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
293 arb().prop_map(|d| d).no_shrink().boxed()
294 }
295
296 type Strategy = BoxedStrategy<Self>;
297 }
298
299 #[derive(Debug, Clone, PartialEq, Eq, test_strategy::Arbitrary)]
301 pub(crate) struct DigestCorruptor {
302 #[strategy(vec(0..Digest::LEN, 1..=Digest::LEN))]
303 #[filter(#corrupt_indices.iter().all_unique())]
304 corrupt_indices: Vec<usize>,
305
306 #[strategy(vec(arb(), #corrupt_indices.len()))]
307 corrupt_elements: Vec<BFieldElement>,
308 }
309
310 impl DigestCorruptor {
311 pub fn corrupt_digest(&self, digest: Digest) -> Result<Digest, TestCaseError> {
312 let mut corrupt_digest = digest;
313 for (&i, &element) in self.corrupt_indices.iter().zip(&self.corrupt_elements) {
314 corrupt_digest.0[i] = element;
315 }
316 if corrupt_digest == digest {
317 let reject_reason = "corruption must change digest".into();
318 return Err(TestCaseError::Reject(reject_reason));
319 }
320
321 Ok(corrupt_digest)
322 }
323 }
324
325 #[macro_rules_attr::apply(test)]
326 fn digest_corruptor_rejects_uncorrupting_corruption() {
327 let digest = Digest(bfe_array![1, 2, 3, 4, 5]);
328 let corruptor = DigestCorruptor {
329 corrupt_indices: vec![0],
330 corrupt_elements: bfe_vec![1],
331 };
332 let err = corruptor.corrupt_digest(digest).unwrap_err();
333 assert!(matches!(err, TestCaseError::Reject(_)));
334 }
335
336 #[macro_rules_attr::apply(test)]
337 fn display_is_as_expected() {
338 let digest = Digest::new(bfe_array![1, 2, 3, 4, 5]);
339 assert_eq!("1,2,3,4,5", format!("{digest}"));
340
341 let hex_digest =
342 "01000000000000000200000000000000030000000000000004000000000000000500000000000000";
343 assert_eq!(hex_digest, format!("{digest:x}"));
344 }
345
346 #[macro_rules_attr::apply(test)]
347 fn get_size() {
348 let stack = Digest::get_stack_size();
349
350 let bfes = bfe_array![12, 24, 36, 48, 60];
351 let tip5_digest_type_from_array: Digest = Digest::new(bfes);
352 let heap = tip5_digest_type_from_array.get_heap_size();
353 let total = tip5_digest_type_from_array.get_size();
354 println!("stack: {stack} + heap: {heap} = {total}");
355
356 assert_eq!(stack + heap, total)
357 }
358
359 #[macro_rules_attr::apply(test)]
360 fn digest_from_str() {
361 let valid_digest_string = "12063201067205522823,\
362 1529663126377206632,\
363 2090171368883726200,\
364 12975872837767296928,\
365 11492877804687889759";
366 let valid_digest = Digest::from_str(valid_digest_string);
367 assert!(valid_digest.is_ok());
368
369 let invalid_digest_string = "00059361073062755064,05168490802189810700";
370 let invalid_digest = Digest::from_str(invalid_digest_string);
371 assert!(invalid_digest.is_err());
372
373 let second_invalid_digest_string = "this_is_not_a_bfield_element,05168490802189810700";
374 let second_invalid_digest = Digest::from_str(second_invalid_digest_string);
375 assert!(second_invalid_digest.is_err());
376 }
377
378 #[macro_rules_attr::apply(proptest)]
379 fn test_reversed_involution(digest: Digest) {
380 prop_assert_eq!(digest, digest.reversed().reversed())
381 }
382
383 #[macro_rules_attr::apply(test)]
384 fn digest_biguint_conversion_simple_test() {
385 let fourteen: BigUint = 14u128.into();
386 let fourteen_converted_expected = Digest(bfe_array![14, 0, 0, 0, 0]);
387
388 let bfe_max: BigUint = BFieldElement::MAX.into();
389 let bfe_max_converted_expected = Digest(bfe_array![BFieldElement::MAX, 0, 0, 0, 0]);
390
391 let bfe_max_plus_one: BigUint = BFieldElement::P.into();
392 let bfe_max_plus_one_converted_expected = Digest(bfe_array![0, 1, 0, 0, 0]);
393
394 let two_pow_64: BigUint = (1u128 << 64).into();
395 let two_pow_64_converted_expected = Digest(bfe_array![(1u64 << 32) - 1, 1, 0, 0, 0]);
396
397 let two_pow_123: BigUint = (1u128 << 123).into();
398 let two_pow_123_converted_expected =
399 Digest([18446744069280366593, 576460752437641215, 0, 0, 0].map(BFieldElement::new));
400
401 let two_pow_315: BigUint = BigUint::from(2u128).pow(315);
402
403 let two_pow_315_converted_expected = Digest(bfe_array![
405 18446744069280366593_u64,
406 1729382257312923647_u64,
407 13258597298683772929_u64,
408 3458764513015234559_u64,
409 576460752840294400_u64,
410 ]);
411
412 assert_eq!(
414 fourteen_converted_expected,
415 fourteen.clone().try_into().unwrap()
416 );
417 assert_eq!(
418 bfe_max_converted_expected,
419 bfe_max.clone().try_into().unwrap()
420 );
421 assert_eq!(
422 bfe_max_plus_one_converted_expected,
423 bfe_max_plus_one.clone().try_into().unwrap()
424 );
425 assert_eq!(
426 two_pow_64_converted_expected,
427 two_pow_64.clone().try_into().unwrap()
428 );
429 assert_eq!(
430 two_pow_123_converted_expected,
431 two_pow_123.clone().try_into().unwrap()
432 );
433 assert_eq!(
434 two_pow_315_converted_expected,
435 two_pow_315.clone().try_into().unwrap()
436 );
437
438 assert_eq!(fourteen, fourteen_converted_expected.into());
440 assert_eq!(bfe_max, bfe_max_converted_expected.into());
441 assert_eq!(bfe_max_plus_one, bfe_max_plus_one_converted_expected.into());
442 assert_eq!(two_pow_64, two_pow_64_converted_expected.into());
443 assert_eq!(two_pow_123, two_pow_123_converted_expected.into());
444 assert_eq!(two_pow_315, two_pow_315_converted_expected.into());
445 }
446
447 #[macro_rules_attr::apply(proptest)]
448 fn digest_biguint_conversion_pbt(components_0: [u64; 4], component_1: u32) {
449 let big_uint = components_0
450 .into_iter()
451 .fold(BigUint::one(), |acc, x| acc * x);
452 let big_uint = big_uint * component_1;
453
454 let as_digest: Digest = big_uint.clone().try_into().unwrap();
455 let big_uint_again: BigUint = as_digest.into();
456 prop_assert_eq!(big_uint, big_uint_again);
457 }
458
459 #[macro_rules_attr::apply(test)]
460 fn digest_ordering() {
461 let val0 = Digest::new(bfe_array![0; Digest::LEN]);
462 let val1 = Digest::new(bfe_array![14, 0, 0, 0, 0]);
463 assert!(val1 > val0);
464
465 let val2 = Digest::new(bfe_array![14; Digest::LEN]);
466 assert!(val2 > val1);
467 assert!(val2 > val0);
468
469 let val3 = Digest::new(bfe_array![15, 14, 14, 14, 14]);
470 assert!(val3 > val2);
471 assert!(val3 > val1);
472 assert!(val3 > val0);
473
474 let val4 = Digest::new(bfe_array![14, 15, 14, 14, 14]);
475 assert!(val4 > val3);
476 assert!(val4 > val2);
477 assert!(val4 > val1);
478 assert!(val4 > val0);
479 }
480
481 #[macro_rules_attr::apply(test)]
482 fn digest_biguint_overflow_test() {
483 let mut two_pow_384: BigUint = (1u128 << 96).into();
484 two_pow_384 = two_pow_384.pow(4);
485 let err = Digest::try_from(two_pow_384).unwrap_err();
486
487 assert_eq!(TryFromDigestError::Overflow, err);
488 }
489
490 #[macro_rules_attr::apply(proptest)]
491 fn digest_to_bfe_vector_involution(digest: Digest) {
492 let bfes = <Vec<BFieldElement>>::from(digest);
493 let digest_again = Digest::try_from(bfes)?;
494 prop_assert_eq!(digest, digest_again);
495 }
496
497 #[macro_rules_attr::apply(proptest)]
498 fn bfe_vector_of_incorrect_length_cannot_become_a_digest(
499 #[filter(#bfes.len() != Digest::LEN)] bfes: Vec<BFieldElement>,
500 ) {
501 let bfes_len = bfes.len();
502 let Err(TryFromDigestError::InvalidLength(len)) = Digest::try_from(bfes) else {
503 return Err(TestCaseError::Fail("expected an error".into()));
504 };
505 prop_assert_eq!(bfes_len, len);
506 }
507
508 #[macro_rules_attr::apply(proptest)]
509 fn forty_bytes_can_be_converted_to_digest(bytes: [u8; Digest::BYTES]) {
510 let digest = Digest::try_from(bytes).unwrap();
511 let bytes_again: [u8; Digest::BYTES] = digest.into();
512 prop_assert_eq!(bytes, bytes_again);
513 }
514
515 #[macro_rules_attr::apply(test)]
517 fn try_from_bytes_not_canonical() -> Result<(), TryFromDigestError> {
518 let bytes: [u8; Digest::BYTES] = [255; Digest::BYTES];
519
520 assert!(Digest::try_from(bytes).is_err_and(|e| matches!(
521 e,
522 TryFromDigestError::InvalidBFieldElement(ParseBFieldElementError::NotCanonical(_))
523 )));
524
525 Ok(())
526 }
527
528 #[macro_rules_attr::apply(test)]
530 fn from_str_not_canonical() -> Result<(), TryFromDigestError> {
531 let str = format!("0,0,0,0,{}", u64::MAX);
532
533 assert!(Digest::from_str(&str).is_err_and(|e| matches!(
534 e,
535 TryFromDigestError::InvalidBFieldElement(ParseBFieldElementError::NotCanonical(_))
536 )));
537
538 Ok(())
539 }
540
541 #[macro_rules_attr::apply(test)]
542 fn bytes_in_matches_bytes_out() -> Result<(), TryFromDigestError> {
543 let bytes1: [u8; Digest::BYTES] = [254; Digest::BYTES];
544 let d1 = Digest::try_from(bytes1)?;
545
546 let bytes2: [u8; Digest::BYTES] = d1.into();
547 let d2 = Digest::try_from(bytes2)?;
548
549 assert_eq!(d1, d2);
550 assert_eq!(bytes1, bytes2);
551
552 Ok(())
553 }
554
555 #[macro_rules_attr::apply(proptest)]
556 fn any_digest_can_be_hashed(digest: Digest) {
557 digest.hash();
558 }
559
560 mod hex_test {
561 use super::*;
562 use crate::tests::proptest;
563 use crate::tests::test;
564
565 pub(super) fn hex_examples() -> Vec<(Digest, &'static str)> {
566 vec![
567 (
568 Digest::default(),
569 concat!(
570 "0000000000000000000000000000000000000000",
571 "0000000000000000000000000000000000000000"
572 ),
573 ),
574 (
575 Digest::new(bfe_array![0, 1, 10, 15, 255]),
576 concat!(
577 "000000000000000001000000000000000a000000",
578 "000000000f00000000000000ff00000000000000"
579 ),
580 ),
581 ]
588 }
589
590 #[macro_rules_attr::apply(test)]
591 fn digest_to_hex() {
592 for (digest, hex) in hex_examples() {
593 assert_eq!(&digest.to_hex(), hex);
594 }
595 }
596
597 #[macro_rules_attr::apply(proptest)]
598 fn to_hex_and_from_hex_are_reciprocal_proptest(bytes: [u8; Digest::BYTES]) {
599 let digest = Digest::try_from(bytes).unwrap();
600 let hex = digest.to_hex();
601 let digest_again = Digest::try_from_hex(&hex).unwrap();
602 let hex_again = digest_again.to_hex();
603 prop_assert_eq!(digest, digest_again);
604 prop_assert_eq!(hex, hex_again);
605
606 let lower_hex = format!("{digest:x}");
607 let digest_from_lower_hex = Digest::try_from_hex(lower_hex).unwrap();
608 prop_assert_eq!(digest, digest_from_lower_hex);
609
610 let upper_hex = format!("{digest:X}");
611 let digest_from_upper_hex = Digest::try_from_hex(upper_hex).unwrap();
612 prop_assert_eq!(digest, digest_from_upper_hex);
613 }
614
615 #[macro_rules_attr::apply(test)]
616 fn to_hex_and_from_hex_are_reciprocal() -> Result<(), TryFromHexDigestError> {
617 let hex_vals = vec![
618 "00000000000000000000000000000000000000000000000000000000000000000000000000000000",
619 "10000000000000000000000000000000000000000000000000000000000000000000000000000000",
620 "0000000000000000000000000000000000000000000000000000000000000000000000000000000f",
621 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
622 ];
624 for hex in hex_vals {
625 let digest = Digest::try_from_hex(hex)?;
626 assert_eq!(hex, &digest.to_hex())
627 }
628 Ok(())
629 }
630
631 #[macro_rules_attr::apply(test)]
632 fn digest_from_hex() -> Result<(), TryFromHexDigestError> {
633 for (digest, hex) in hex_examples() {
634 assert_eq!(digest, Digest::try_from_hex(hex)?);
635 }
636
637 Ok(())
638 }
639
640 #[macro_rules_attr::apply(test)]
641 fn digest_from_invalid_hex_errors() {
642 use hex::FromHexError;
643
644 assert!(Digest::try_from_hex("taco").is_err_and(|e| matches!(
645 e,
646 TryFromHexDigestError::HexDecode(FromHexError::InvalidHexCharacter { .. })
647 )));
648
649 assert!(Digest::try_from_hex("0").is_err_and(|e| matches!(
650 e,
651 TryFromHexDigestError::HexDecode(FromHexError::OddLength)
652 )));
653
654 assert!(Digest::try_from_hex("00").is_err_and(|e| matches!(
655 e,
656 TryFromHexDigestError::Digest(TryFromDigestError::InvalidLength(_))
657 )));
658
659 assert!(Digest::try_from_hex(
661 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
662 )
663 .is_err_and(|e| matches!(
664 e,
665 TryFromHexDigestError::Digest(TryFromDigestError::InvalidBFieldElement(
666 ParseBFieldElementError::NotCanonical(_)
667 ))
668 )));
669 }
670 }
671
672 mod serde_test {
673 use super::hex_test::hex_examples;
674 use super::*;
675
676 mod json_test {
677 use super::*;
678 use crate::tests::test;
679
680 #[macro_rules_attr::apply(test)]
681 fn serialize() -> Result<(), serde_json::Error> {
682 for (digest, hex) in hex_examples() {
683 assert_eq!(serde_json::to_string(&digest)?, format!("\"{hex}\""));
684 }
685 Ok(())
686 }
687
688 #[macro_rules_attr::apply(test)]
689 fn deserialize() -> Result<(), serde_json::Error> {
690 for (digest, hex) in hex_examples() {
691 let json_hex = format!("\"{hex}\"");
692 let digest_deserialized: Digest = serde_json::from_str::<Digest>(&json_hex)?;
693 assert_eq!(digest_deserialized, digest);
694 }
695 Ok(())
696 }
697 }
698
699 mod bincode_test {
700 use super::*;
701 use crate::tests::test;
702
703 fn bincode_examples() -> Vec<(Digest, [u8; Digest::BYTES])> {
704 vec![
705 (Digest::default(), [0u8; Digest::BYTES]),
706 (
707 Digest::new(bfe_array![0, 1, 10, 15, 255]),
708 [
709 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0,
710 0, 15, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0,
711 ],
712 ),
713 ]
714 }
715
716 #[macro_rules_attr::apply(test)]
717 fn serialize() {
718 for (digest, bytes) in bincode_examples() {
719 assert_eq!(bincode::serialize(&digest).unwrap(), bytes);
720 }
721 }
722
723 #[macro_rules_attr::apply(test)]
724 fn deserialize() {
725 for (digest, bytes) in bincode_examples() {
726 assert_eq!(bincode::deserialize::<Digest>(&bytes).unwrap(), digest);
727 }
728 }
729 }
730 }
731}