hashes 0.1.9

Rust implementation of cryptographic hash function algorithms
Documentation
pub trait Functions {
    fn ch(x: Self, y: Self, z: Self) -> Self;
    fn maj(x: Self, y: Self, z: Self) -> Self;

    fn sum0(x: Self) -> Self;
    fn sum1(x: Self) -> Self;

    fn sigma0(x: Self) -> Self;
    fn sigma1(x: Self) -> Self;
}

macro_rules! define_hash_algorithm {
    () => {
        use crate::{digest::Digest, hash_macros::define_hash};

        use super::algorithm::Functions;

        pub const N_INNER_DIGEST_WORDS: usize = 8;
        pub const N_WORD_BYTES: usize = core::mem::size_of::<Word>();

        fn create_message_schedule(chunk: [u8; N_CHUNK_BYTES]) -> [Word; N_ROUNDS] {
            let mut w = [0; N_ROUNDS];

            w.iter_mut()
                .zip(chunk.chunks(N_WORD_BYTES))
                .for_each(|(wi, wi_bytes)| *wi = Word::from_be_bytes(wi_bytes.try_into().unwrap()));

            (16..N_ROUNDS).for_each(|i| {
                let s0 = Word::sigma0(w[i - 15]);
                let s1 = Word::sigma1(w[i - 2]);

                w[i] = w[i - 16]
                    .wrapping_add(s0)
                    .wrapping_add(w[i - 7])
                    .wrapping_add(s1)
            });

            w
        }

        #[inline(always)]
        fn compute_next_digest(
            digest: [Word; N_INNER_DIGEST_WORDS],
            chunk: [u8; N_CHUNK_BYTES],
        ) -> [Word; N_INNER_DIGEST_WORDS] {
            let w = create_message_schedule(chunk);

            let chunk_digest = (0..N_ROUNDS).fold(digest, |[a, b, c, d, e, f, g, h], i| {
                let s0 = Word::sum0(a);
                let s1 = Word::sum1(e);
                let maj = Word::maj(a, b, c);
                let ch = Word::ch(e, f, g);

                let t1 = h
                    .wrapping_add(s1)
                    .wrapping_add(ch)
                    .wrapping_add(K[i])
                    .wrapping_add(w[i]);

                let t2 = s0.wrapping_add(maj);

                [t1.wrapping_add(t2), a, b, c, d.wrapping_add(t1), e, f, g]
            });

            [
                digest[0].wrapping_add(chunk_digest[0]),
                digest[1].wrapping_add(chunk_digest[1]),
                digest[2].wrapping_add(chunk_digest[2]),
                digest[3].wrapping_add(chunk_digest[3]),
                digest[4].wrapping_add(chunk_digest[4]),
                digest[5].wrapping_add(chunk_digest[5]),
                digest[6].wrapping_add(chunk_digest[6]),
                digest[7].wrapping_add(chunk_digest[7]),
            ]
        }

        #[inline(always)]
        fn message_len_into_bytes<const N_MESSAGE_LEN_BYTES: usize>(
            message_len: usize,
        ) -> [u8; N_MESSAGE_LEN_BYTES] {
            (message_len as u128 * 8u128).to_be_bytes()[16 - N_MESSAGE_LEN_BYTES..]
                .try_into()
                .unwrap()
        }

        #[inline(always)]
        fn word_into_bytes(d: Word) -> [u8; N_WORD_BYTES] {
            d.to_be_bytes()
        }

        define_hash!();
    };
}

pub(super) use define_hash_algorithm;