use super::DIGEST_SIZE; use core::slice; use winterfell::crypto::Digest; use winterfell::math::{fields::f64::BaseElement, StarkField}; use winterfell::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; // DIGEST TRAIT IMPLEMENTATIONS // ================================================================================================ #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ElementDigest([BaseElement; DIGEST_SIZE]); impl ElementDigest { pub fn new(value: [BaseElement; DIGEST_SIZE]) -> Self { Self(value) } pub fn as_elements(&self) -> &[BaseElement] { &self.0 } pub fn digests_as_elements(digests: &[Self]) -> &[BaseElement] { let p = digests.as_ptr(); let len = digests.len() * DIGEST_SIZE; unsafe { slice::from_raw_parts(p as *const BaseElement, len) } } } impl Digest for ElementDigest { fn as_bytes(&self) -> [u8; 32] { let mut result = [0; 32]; result[..8].copy_from_slice(&self.0[0].as_int().to_le_bytes()); result[8..16].copy_from_slice(&self.0[1].as_int().to_le_bytes()); result[16..24].copy_from_slice(&self.0[2].as_int().to_le_bytes()); result[24..].copy_from_slice(&self.0[3].as_int().to_le_bytes()); result } } impl Default for ElementDigest { fn default() -> Self { ElementDigest([BaseElement::default(); DIGEST_SIZE]) } } impl Serializable for ElementDigest { fn write_into(&self, target: &mut W) { target.write_u8_slice(&self.as_bytes()); } } impl Deserializable for ElementDigest { fn read_from(source: &mut R) -> Result { // TODO: check if the field elements are valid? let e1 = BaseElement::new(source.read_u64()?); let e2 = BaseElement::new(source.read_u64()?); let e3 = BaseElement::new(source.read_u64()?); let e4 = BaseElement::new(source.read_u64()?); Ok(Self([e1, e2, e3, e4])) } } impl From<[BaseElement; DIGEST_SIZE]> for ElementDigest { fn from(value: [BaseElement; DIGEST_SIZE]) -> Self { Self(value) } } impl From for [BaseElement; DIGEST_SIZE] { fn from(value: ElementDigest) -> Self { value.0 } } impl From for [u8; 32] { fn from(value: ElementDigest) -> Self { value.as_bytes() } } // TESTS // ================================================================================================ #[cfg(test)] mod tests { use super::ElementDigest; use rand_utils::rand_value; use winterfell::{math::fields::f64::BaseElement, Deserializable, Serializable, SliceReader}; #[test] fn digest_serialization() { let e1 = BaseElement::new(rand_value()); let e2 = BaseElement::new(rand_value()); let e3 = BaseElement::new(rand_value()); let e4 = BaseElement::new(rand_value()); let d1 = ElementDigest([e1, e2, e3, e4]); let mut bytes = vec![]; d1.write_into(&mut bytes); assert_eq!(32, bytes.len()); let mut reader = SliceReader::new(&bytes); let d2 = ElementDigest::read_from(&mut reader).unwrap(); assert_eq!(d1, d2); } }