miden-crypto/crypto/src/hash/rpo/digest.rs
2022-10-26 07:06:04 +02:00

148 lines
3.6 KiB
Rust

use super::DIGEST_SIZE;
use crate::{Digest, Felt, StarkField};
use core::ops::Deref;
use winterfell::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
// DIGEST TRAIT IMPLEMENTATIONS
// ================================================================================================
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct RpoDigest256([Felt; DIGEST_SIZE]);
impl RpoDigest256 {
pub fn new(value: [Felt; DIGEST_SIZE]) -> Self {
Self(value)
}
pub fn as_elements(&self) -> &[Felt] {
self.as_ref()
}
pub fn digests_as_elements<'a, I>(digests: I) -> impl Iterator<Item = &'a Felt>
where
I: Iterator<Item = &'a Self>,
{
digests.map(|d| d.0.iter()).flatten()
}
}
impl Digest for RpoDigest256 {
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 RpoDigest256 {
fn default() -> Self {
RpoDigest256([Felt::default(); DIGEST_SIZE])
}
}
impl Serializable for RpoDigest256 {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_u8_slice(&self.as_bytes());
}
}
impl Deserializable for RpoDigest256 {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let e1 = Felt::new(source.read_u64()?);
let e2 = Felt::new(source.read_u64()?);
let e3 = Felt::new(source.read_u64()?);
let e4 = Felt::new(source.read_u64()?);
Ok(Self([e1, e2, e3, e4]))
}
}
impl From<[Felt; DIGEST_SIZE]> for RpoDigest256 {
fn from(value: [Felt; DIGEST_SIZE]) -> Self {
Self(value)
}
}
impl From<RpoDigest256> for [Felt; DIGEST_SIZE] {
fn from(value: RpoDigest256) -> Self {
value.0
}
}
impl From<RpoDigest256> for [u8; 32] {
fn from(value: RpoDigest256) -> Self {
value.as_bytes()
}
}
impl Deref for RpoDigest256 {
type Target = [Felt; DIGEST_SIZE];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl RpoDigest256 {
fn iter(&self) -> RpoDigest256Iter<'_> {
RpoDigest256Iter {
values: &self.0,
index: 0,
}
}
}
pub struct RpoDigest256Iter<'a> {
values: &'a [Felt; DIGEST_SIZE],
index: usize,
}
impl<'a> Iterator for RpoDigest256Iter<'a> {
type Item = &'a Felt;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.values.len() {
return None;
}
self.index += 1;
Some(&self.values[self.index - 1])
}
}
// TESTS
// ================================================================================================
#[cfg(test)]
mod tests {
use super::RpoDigest256;
use crate::Felt;
use rand_utils::rand_value;
use winterfell::{Deserializable, Serializable, SliceReader};
#[test]
fn digest_serialization() {
let e1 = Felt::new(rand_value());
let e2 = Felt::new(rand_value());
let e3 = Felt::new(rand_value());
let e4 = Felt::new(rand_value());
let d1 = RpoDigest256([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 = RpoDigest256::read_from(&mut reader).unwrap();
assert_eq!(d1, d2);
}
}