krypteia-arcana 0.1.0

Pure-Rust classical cryptographic primitives: RSA (PKCS#1 v1.5, OAEP), ECC (NIST P-256/384/521, secp256k1), ECDSA, EdDSA (Ed25519), X25519, AES (128/192/256, GCM/CBC), DES/3DES, SHA-1/2/3, HMAC. Side-channel-aware (Montgomery ladder, branchless point_add_ct). Targets embedded (no_std), STM32 M0/M4/M33, ESP32-C3 RISC-V. Zero runtime dependencies.
Documentation
//! SHA-224 hash function (FIPS 180-4).
//!
//! Same as SHA-256 but with different initial values, truncated to
//! 224 bits (28 bytes). Used in some government profiles and
//! FIPS-constrained environments.

use super::sha256::Sha256;
use crate::Hasher;

const H0_224: [u32; 8] = [
    0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
];

/// SHA-224 hasher (FIPS 180-4). 224-bit output, 64-byte blocks.
///
/// SHA-224 reuses the SHA-256 compression function with different
/// IV constants and a truncated output.
#[derive(Clone)]
pub struct Sha224 {
    inner: Sha256,
}

impl Hasher for Sha224 {
    const OUTPUT_LEN: usize = 28;
    const BLOCK_LEN: usize = 64;

    fn new() -> Self {
        Self {
            inner: Sha256::new_with_iv(H0_224),
        }
    }

    fn update(&mut self, data: &[u8]) {
        self.inner.update(data);
    }

    fn finalize(self) -> Vec<u8> {
        let mut out = vec![0u8; 28];
        self.finalize_into(&mut out);
        out
    }

    fn finalize_into(self, out: &mut [u8]) {
        let mut full = [0u8; 32];
        self.inner.finalize_into(&mut full);
        let len = out.len().min(28);
        out[..len].copy_from_slice(&full[..len]);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Hasher;

    #[test]
    fn test_sha224_empty() {
        let digest = Sha224::hash(b"");
        let expected: [u8; 28] = [
            0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
            0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, 0x2f,
        ];
        assert_eq!(&digest[..], &expected[..]);
    }

    #[test]
    fn test_sha224_abc() {
        let digest = Sha224::hash(b"abc");
        let expected: [u8; 28] = [
            0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8, 0x22, 0x86, 0x42, 0xa4, 0x77, 0xbd, 0xa2, 0x55, 0xb3, 0x2a, 0xad,
            0xbc, 0xe4, 0xbd, 0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d, 0xa7,
        ];
        assert_eq!(&digest[..], &expected[..]);
    }
}