arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
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}