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