willow_data_model/test_parameters/
digest.rs

1use arbitrary::Arbitrary;
2
3use anyhash::{Hasher, HasherWrite};
4
5use ufotofu::codec_prelude::*;
6
7/// A payload digest for testing.
8///
9/// To hash a bytestring, add all its bytes modulo 256, and take the result modulo 4,  mapping to the different values as follows:
10///
11/// - 0 -> Clubs
12/// - 1 -> Diamonds
13/// - 2 -> Hearts
14/// - 3 -> Spades
15///
16/// In case you did not notice, **this is not cryptographically secure**.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary)]
18#[allow(missing_docs)]
19pub enum TestDigest {
20    Clubs,
21    Diamonds,
22    Hearts,
23    Spades,
24}
25
26pub use TestDigest::*;
27
28impl Encodable for TestDigest {
29    async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
30    where
31        C: BulkConsumer<Item = u8> + ?Sized,
32    {
33        match self {
34            Clubs => consumer.consume_item(0).await,
35            Diamonds => consumer.consume_item(1).await,
36            Hearts => consumer.consume_item(2).await,
37            Spades => consumer.consume_item(3).await,
38        }
39    }
40}
41
42impl EncodableKnownLength for TestDigest {
43    fn len_of_encoding(&self) -> usize {
44        1
45    }
46}
47
48impl Decodable for TestDigest {
49    type ErrorReason = Blame;
50
51    async fn decode<P>(
52        producer: &mut P,
53    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
54    where
55        P: BulkProducer<Item = u8> + ?Sized,
56        Self: Sized,
57    {
58        let byte = producer.produce_item().await?;
59
60        match byte {
61            0 => Ok(Clubs),
62            1 => Ok(Diamonds),
63            2 => Ok(Hearts),
64            3 => Ok(Spades),
65            _ => Err(DecodeError::Other(Blame::TheirFault)),
66        }
67    }
68}
69
70impl DecodableCanonic for TestDigest {
71    type ErrorCanonic = Blame;
72
73    async fn decode_canonic<P>(
74        producer: &mut P,
75    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
76    where
77        P: BulkProducer<Item = u8> + ?Sized,
78        Self: Sized,
79    {
80        Self::decode(producer).await
81    }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary, Default)]
85/// The state for hashing a bytestring into a [`TestDigest`].
86pub struct TestDigestHasher(u8);
87
88impl HasherWrite for TestDigestHasher {
89    fn write(&mut self, bytes: &[u8]) {
90        for byte in bytes {
91            self.0 = self.0.wrapping_add(*byte)
92        }
93    }
94}
95
96impl Hasher<TestDigest> for TestDigestHasher {
97    fn finish(&self) -> TestDigest {
98        match self.0 % 4 {
99            0 => TestDigest::Clubs,
100            1 => TestDigest::Diamonds,
101            2 => TestDigest::Hearts,
102            3 => TestDigest::Spades,
103            _ => unreachable!(),
104        }
105    }
106}