miden-crypto/crypto/src/hash/rpo/digest.rs
crypto/src/hash/rpo/digest.rsRaw
1use super::DIGEST_SIZE;
2use crate::{Digest, Felt, StarkField};
3use core::slice;
4use winterfell::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
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.0
19 }
20
21 pub fn digests_as_elements(digests: &[Self]) -> &[Felt] {
22 let p = digests.as_ptr();
23 let len = digests.len() * DIGEST_SIZE;
24 unsafe { slice::from_raw_parts(p as *const Felt, len) }
25 }
26}
27
28impl Digest for RpoDigest256 {
29 fn as_bytes(&self) -> [u8; 32] {
30 let mut result = [0; 32];
31
32 result[..8].copy_from_slice(&self.0[0].as_int().to_le_bytes());
33 result[8..16].copy_from_slice(&self.0[1].as_int().to_le_bytes());
34 result[16..24].copy_from_slice(&self.0[2].as_int().to_le_bytes());
35 result[24..].copy_from_slice(&self.0[3].as_int().to_le_bytes());
36
37 result
38 }
39}
40
41impl Default for RpoDigest256 {
42 fn default() -> Self {
43 RpoDigest256([Felt::default(); DIGEST_SIZE])
44 }
45}
46
47impl Serializable for RpoDigest256 {
48 fn write_into<W: ByteWriter>(&self, target: &mut W) {
49 target.write_u8_slice(&self.as_bytes());
50 }
51}
52
53impl Deserializable for RpoDigest256 {
54 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
55 // TODO: check if the field elements are valid?
56 let e1 = Felt::new(source.read_u64()?);
57 let e2 = Felt::new(source.read_u64()?);
58 let e3 = Felt::new(source.read_u64()?);
59 let e4 = Felt::new(source.read_u64()?);
60
61 Ok(Self([e1, e2, e3, e4]))
62 }
63}
64
65impl From<[Felt; DIGEST_SIZE]> for RpoDigest256 {
66 fn from(value: [Felt; DIGEST_SIZE]) -> Self {
67 Self(value)
68 }
69}
70
71impl From<RpoDigest256> for [Felt; DIGEST_SIZE] {
72 fn from(value: RpoDigest256) -> Self {
73 value.0
74 }
75}
76
77impl From<RpoDigest256> for [u8; 32] {
78 fn from(value: RpoDigest256) -> Self {
79 value.as_bytes()
80 }
81}
82
83// TESTS
84// ================================================================================================
85
86#[cfg(test)]
87mod tests {
88
89 use super::RpoDigest256;
90 use crate::Felt;
91 use rand_utils::rand_value;
92 use winterfell::{Deserializable, Serializable, SliceReader};
93
94 #[test]
95 fn digest_serialization() {
96 let e1 = Felt::new(rand_value());
97 let e2 = Felt::new(rand_value());
98 let e3 = Felt::new(rand_value());
99 let e4 = Felt::new(rand_value());
100
101 let d1 = RpoDigest256([e1, e2, e3, e4]);
102
103 let mut bytes = vec![];
104 d1.write_into(&mut bytes);
105 assert_eq!(32, bytes.len());
106
107 let mut reader = SliceReader::new(&bytes);
108 let d2 = RpoDigest256::read_from(&mut reader).unwrap();
109
110 assert_eq!(d1, d2);
111 }
112}