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