miden-crypto/src/hash/rpo/digest.rs
src/hash/rpo/digest.rsRaw
1use super::DIGEST_SIZE;
2use crate::{
3 ByteReader, ByteWriter, Deserializable, DeserializationError, Digest, Felt, Serializable,
4 StarkField, String, ZERO,
5};
6use core::ops::Deref;
7
8// DIGEST TRAIT IMPLEMENTATIONS
9// ================================================================================================
10
11#[derive(Debug, Copy, Clone, Eq, PartialEq)]
12pub struct RpoDigest256([Felt; DIGEST_SIZE]);
13
14impl RpoDigest256 {
15 pub fn new(value: [Felt; DIGEST_SIZE]) -> Self {
16 Self(value)
17 }
18
19 pub fn as_elements(&self) -> &[Felt] {
20 self.as_ref()
21 }
22
23 pub fn digests_as_elements<'a, I>(digests: I) -> impl Iterator<Item = &'a Felt>
24 where
25 I: Iterator<Item = &'a Self>,
26 {
27 digests.flat_map(|d| d.0.iter())
28 }
29}
30
31impl Digest for RpoDigest256 {
32 fn as_bytes(&self) -> [u8; 32] {
33 let mut result = [0; 32];
34
35 result[..8].copy_from_slice(&self.0[0].as_int().to_le_bytes());
36 result[8..16].copy_from_slice(&self.0[1].as_int().to_le_bytes());
37 result[16..24].copy_from_slice(&self.0[2].as_int().to_le_bytes());
38 result[24..].copy_from_slice(&self.0[3].as_int().to_le_bytes());
39
40 result
41 }
42}
43
44impl Default for RpoDigest256 {
45 fn default() -> Self {
46 RpoDigest256([Felt::default(); DIGEST_SIZE])
47 }
48}
49
50impl Serializable for RpoDigest256 {
51 fn write_into<W: ByteWriter>(&self, target: &mut W) {
52 target.write_u8_slice(&self.as_bytes());
53 }
54}
55
56impl Deserializable for RpoDigest256 {
57 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
58 let mut inner: [Felt; DIGEST_SIZE] = [ZERO; DIGEST_SIZE];
59 for inner in inner.iter_mut() {
60 let e = source.read_u64()?;
61 if e >= Felt::MODULUS {
62 return Err(DeserializationError::InvalidValue(String::from(
63 "Value not in the appropriate range",
64 )));
65 }
66 *inner = Felt::new(e);
67 }
68
69 Ok(Self(inner))
70 }
71}
72
73impl From<[Felt; DIGEST_SIZE]> for RpoDigest256 {
74 fn from(value: [Felt; DIGEST_SIZE]) -> Self {
75 Self(value)
76 }
77}
78
79impl From<RpoDigest256> for [Felt; DIGEST_SIZE] {
80 fn from(value: RpoDigest256) -> Self {
81 value.0
82 }
83}
84
85impl From<RpoDigest256> for [u8; 32] {
86 fn from(value: RpoDigest256) -> Self {
87 value.as_bytes()
88 }
89}
90
91impl Deref for RpoDigest256 {
92 type Target = [Felt; DIGEST_SIZE];
93
94 fn deref(&self) -> &Self::Target {
95 &self.0
96 }
97}
98
99// TESTS
100// ================================================================================================
101
102#[cfg(test)]
103mod tests {
104
105 use super::RpoDigest256;
106 use crate::{Deserializable, Felt, Serializable, SliceReader};
107 use rand_utils::rand_value;
108
109 #[test]
110 fn digest_serialization() {
111 let e1 = Felt::new(rand_value());
112 let e2 = Felt::new(rand_value());
113 let e3 = Felt::new(rand_value());
114 let e4 = Felt::new(rand_value());
115
116 let d1 = RpoDigest256([e1, e2, e3, e4]);
117
118 let mut bytes = vec![];
119 d1.write_into(&mut bytes);
120 assert_eq!(32, bytes.len());
121
122 let mut reader = SliceReader::new(&bytes);
123 let d2 = RpoDigest256::read_from(&mut reader).unwrap();
124
125 assert_eq!(d1, d2);
126 }
127}