winter_crypto/hash/
mod.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use core::{fmt::Debug, slice};
7
8use math::{FieldElement, StarkField};
9use utils::{ByteReader, Deserializable, DeserializationError, Serializable};
10
11mod blake;
12pub use blake::{Blake3_192, Blake3_256};
13
14mod sha;
15pub use sha::Sha3_256;
16
17mod mds;
18
19mod rescue;
20pub use rescue::{Rp62_248, Rp64_256, RpJive64_256};
21
22// HASHER TRAITS
23// ================================================================================================
24
25/// Defines a cryptographic hash function.
26///
27/// This trait defines hash procedures for the following inputs:
28/// * A sequence of bytes.
29/// * Two digests - this is intended for use in Merkle tree constructions.
30/// * A digests and a u64 value - this intended for use in PRNG or PoW contexts.
31pub trait Hasher {
32    /// Specifies a digest type returned by this hasher.
33    type Digest: Digest;
34
35    /// Collision resistance of the hash function measured in bits.
36    const COLLISION_RESISTANCE: u32;
37
38    /// Returns a hash of the provided sequence of bytes.
39    fn hash(bytes: &[u8]) -> Self::Digest;
40
41    /// Returns a hash of two digests. This method is intended for use in construction of
42    /// Merkle trees.
43    fn merge(values: &[Self::Digest; 2]) -> Self::Digest;
44
45    /// Returns a hash of many digests.
46    fn merge_many(values: &[Self::Digest]) -> Self::Digest;
47
48    /// Returns hash(`seed` || `value`). This method is intended for use in PRNG and PoW contexts.
49    fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest;
50}
51
52/// Defines a cryptographic hash function for hashing field elements.
53///
54/// This trait defines a hash procedure for a sequence of field elements. The elements can be
55/// either in the base field specified for this hasher, or in an extension of the base field.
56pub trait ElementHasher: Hasher {
57    /// Specifies a base field for elements which can be hashed with this hasher.
58    type BaseField: StarkField;
59
60    /// Returns a hash of the provided field elements.
61    fn hash_elements<E>(elements: &[E]) -> Self::Digest
62    where
63        E: FieldElement<BaseField = Self::BaseField>;
64}
65
66// DIGEST TRAIT
67// ================================================================================================
68
69/// Defines output type for a cryptographic hash function.
70pub trait Digest:
71    Debug + Default + Copy + Clone + Eq + PartialEq + Send + Sync + Serializable + Deserializable
72{
73    /// Returns this digest serialized into an array of bytes.
74    ///
75    /// Ideally, the length of the returned array should be defined by an associated constant, but
76    /// using associated constants in const generics is not supported by Rust yet. Thus, we put an
77    /// upper limit on the possible digest size. For digests which are smaller than 32 bytes, the
78    /// unused bytes should be set to 0.
79    fn as_bytes(&self) -> [u8; 32];
80}
81
82// BYTE DIGEST
83// ================================================================================================
84
85#[derive(Debug, Copy, Clone, Eq, PartialEq)]
86pub struct ByteDigest<const N: usize>([u8; N]);
87
88impl<const N: usize> ByteDigest<N> {
89    pub fn new(value: [u8; N]) -> Self {
90        Self(value)
91    }
92
93    #[inline(always)]
94    pub fn bytes_as_digests(bytes: &[[u8; N]]) -> &[ByteDigest<N>] {
95        let p = bytes.as_ptr();
96        let len = bytes.len();
97        unsafe { slice::from_raw_parts(p as *const ByteDigest<N>, len) }
98    }
99
100    #[inline(always)]
101    pub fn digests_as_bytes(digests: &[ByteDigest<N>]) -> &[u8] {
102        let p = digests.as_ptr();
103        let len = digests.len() * N;
104        unsafe { slice::from_raw_parts(p as *const u8, len) }
105    }
106}
107
108impl<const N: usize> Digest for ByteDigest<N> {
109    fn as_bytes(&self) -> [u8; 32] {
110        let mut result = [0; 32];
111        result[..N].copy_from_slice(&self.0);
112        result
113    }
114}
115
116impl<const N: usize> Default for ByteDigest<N> {
117    fn default() -> Self {
118        ByteDigest([0; N])
119    }
120}
121
122impl<const N: usize> Serializable for ByteDigest<N> {
123    fn write_into<W: utils::ByteWriter>(&self, target: &mut W) {
124        target.write_bytes(&self.0);
125    }
126}
127
128impl<const N: usize> Deserializable for ByteDigest<N> {
129    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
130        Ok(ByteDigest(source.read_array()?))
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::{ByteDigest, Digest};
137
138    #[test]
139    fn byte_digest_as_bytes() {
140        let d = ByteDigest::new([255_u8; 32]);
141        assert_eq!([255_u8; 32], d.as_bytes());
142
143        let d = ByteDigest::new([255_u8; 31]);
144        let mut expected = [255_u8; 32];
145        expected[31] = 0;
146        assert_eq!(expected, d.as_bytes());
147    }
148}