miden-crypto/crypto/src/hash/rpo/digest.rs
crypto/src/hash/rpo/digest.rsRaw
1use super::DIGEST_SIZE;
2use core::slice;
3use winterfell::crypto::Digest;
4use winterfell::math::{fields::f64::BaseElement, StarkField};
5use winterfell::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
6
7// DIGEST TRAIT IMPLEMENTATIONS
8// ================================================================================================
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq)]
11pub struct ElementDigest([BaseElement; DIGEST_SIZE]);
12
13impl ElementDigest {
14 pub fn new(value: [BaseElement; DIGEST_SIZE]) -> Self {
15 Self(value)
16 }
17
18 pub fn as_elements(&self) -> &[BaseElement] {
19 &self.0
20 }
21
22 pub fn digests_as_elements(digests: &[Self]) -> &[BaseElement] {
23 let p = digests.as_ptr();
24 let len = digests.len() * DIGEST_SIZE;
25 unsafe { slice::from_raw_parts(p as *const BaseElement, len) }
26 }
27}
28
29impl Digest for ElementDigest {
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 ElementDigest {
43 fn default() -> Self {
44 ElementDigest([BaseElement::default(); DIGEST_SIZE])
45 }
46}
47
48impl Serializable for ElementDigest {
49 fn write_into<W: ByteWriter>(&self, target: &mut W) {
50 target.write_u8_slice(&self.as_bytes());
51 }
52}
53
54impl Deserializable for ElementDigest {
55 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
56 // TODO: check if the field elements are valid?
57 let e1 = BaseElement::new(source.read_u64()?);
58 let e2 = BaseElement::new(source.read_u64()?);
59 let e3 = BaseElement::new(source.read_u64()?);
60 let e4 = BaseElement::new(source.read_u64()?);
61
62 Ok(Self([e1, e2, e3, e4]))
63 }
64}
65
66impl From<[BaseElement; DIGEST_SIZE]> for ElementDigest {
67 fn from(value: [BaseElement; DIGEST_SIZE]) -> Self {
68 Self(value)
69 }
70}
71
72impl From<ElementDigest> for [BaseElement; DIGEST_SIZE] {
73 fn from(value: ElementDigest) -> Self {
74 value.0
75 }
76}
77
78impl From<ElementDigest> for [u8; 32] {
79 fn from(value: ElementDigest) -> Self {
80 value.as_bytes()
81 }
82}
83
84// TESTS
85// ================================================================================================
86
87#[cfg(test)]
88mod tests {
89
90 use super::ElementDigest;
91 use rand_utils::rand_value;
92 use winterfell::{math::fields::f64::BaseElement, Deserializable, Serializable, SliceReader};
93
94 #[test]
95 fn digest_serialization() {
96 let e1 = BaseElement::new(rand_value());
97 let e2 = BaseElement::new(rand_value());
98 let e3 = BaseElement::new(rand_value());
99 let e4 = BaseElement::new(rand_value());
100
101 let d1 = ElementDigest([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 = ElementDigest::read_from(&mut reader).unwrap();
109
110 assert_eq!(d1, d2);
111 }
112}