use super::Digest;
const K32: [u32; 64] = [
0x428a_2f98,
0x7137_4491,
0xb5c0_fbcf,
0xe9b5_dba5,
0x3956_c25b,
0x59f1_11f1,
0x923f_82a4,
0xab1c_5ed5,
0xd807_aa98,
0x1283_5b01,
0x2431_85be,
0x550c_7dc3,
0x72be_5d74,
0x80de_b1fe,
0x9bdc_06a7,
0xc19b_f174,
0xe49b_69c1,
0xefbe_4786,
0x0fc1_9dc6,
0x240c_a1cc,
0x2de9_2c6f,
0x4a74_84aa,
0x5cb0_a9dc,
0x76f9_88da,
0x983e_5152,
0xa831_c66d,
0xb003_27c8,
0xbf59_7fc7,
0xc6e0_0bf3,
0xd5a7_9147,
0x06ca_6351,
0x1429_2967,
0x27b7_0a85,
0x2e1b_2138,
0x4d2c_6dfc,
0x5338_0d13,
0x650a_7354,
0x766a_0abb,
0x81c2_c92e,
0x9272_2c85,
0xa2bf_e8a1,
0xa81a_664b,
0xc24b_8b70,
0xc76c_51a3,
0xd192_e819,
0xd699_0624,
0xf40e_3585,
0x106a_a070,
0x19a4_c116,
0x1e37_6c08,
0x2748_774c,
0x34b0_bcb5,
0x391c_0cb3,
0x4ed8_aa4a,
0x5b9c_ca4f,
0x682e_6ff3,
0x748f_82ee,
0x78a5_636f,
0x84c8_7814,
0x8cc7_0208,
0x90be_fffa,
0xa450_6ceb,
0xbef9_a3f7,
0xc671_78f2,
];
const K64: [u64; 80] = [
0x428a_2f98_d728_ae22,
0x7137_4491_23ef_65cd,
0xb5c0_fbcf_ec4d_3b2f,
0xe9b5_dba5_8189_dbbc,
0x3956_c25b_f348_b538,
0x59f1_11f1_b605_d019,
0x923f_82a4_af19_4f9b,
0xab1c_5ed5_da6d_8118,
0xd807_aa98_a303_0242,
0x1283_5b01_4570_6fbe,
0x2431_85be_4ee4_b28c,
0x550c_7dc3_d5ff_b4e2,
0x72be_5d74_f27b_896f,
0x80de_b1fe_3b16_96b1,
0x9bdc_06a7_25c7_1235,
0xc19b_f174_cf69_2694,
0xe49b_69c1_9ef1_4ad2,
0xefbe_4786_384f_25e3,
0x0fc1_9dc6_8b8c_d5b5,
0x240c_a1cc_77ac_9c65,
0x2de9_2c6f_592b_0275,
0x4a74_84aa_6ea6_e483,
0x5cb0_a9dc_bd41_fbd4,
0x76f9_88da_8311_53b5,
0x983e_5152_ee66_dfab,
0xa831_c66d_2db4_3210,
0xb003_27c8_98fb_213f,
0xbf59_7fc7_beef_0ee4,
0xc6e0_0bf3_3da8_8fc2,
0xd5a7_9147_930a_a725,
0x06ca_6351_e003_826f,
0x1429_2967_0a0e_6e70,
0x27b7_0a85_46d2_2ffc,
0x2e1b_2138_5c26_c926,
0x4d2c_6dfc_5ac4_2aed,
0x5338_0d13_9d95_b3df,
0x650a_7354_8baf_63de,
0x766a_0abb_3c77_b2a8,
0x81c2_c92e_47ed_aee6,
0x9272_2c85_1482_353b,
0xa2bf_e8a1_4cf1_0364,
0xa81a_664b_bc42_3001,
0xc24b_8b70_d0f8_9791,
0xc76c_51a3_0654_be30,
0xd192_e819_d6ef_5218,
0xd699_0624_5565_a910,
0xf40e_3585_5771_202a,
0x106a_a070_32bb_d1b8,
0x19a4_c116_b8d2_d0c8,
0x1e37_6c08_5141_ab53,
0x2748_774c_df8e_eb99,
0x34b0_bcb5_e19b_48a8,
0x391c_0cb3_c5c9_5a63,
0x4ed8_aa4a_e341_8acb,
0x5b9c_ca4f_7763_e373,
0x682e_6ff3_d6b2_b8a3,
0x748f_82ee_5def_b2fc,
0x78a5_636f_4317_2f60,
0x84c8_7814_a1f0_ab72,
0x8cc7_0208_1a64_39ec,
0x90be_fffa_2363_1e28,
0xa450_6ceb_de82_bde9,
0xbef9_a3f7_b2c6_7915,
0xc671_78f2_e372_532b,
0xca27_3ece_ea26_619c,
0xd186_b8c7_21c0_c207,
0xeada_7dd6_cde0_eb1e,
0xf57d_4f7f_ee6e_d178,
0x06f0_67aa_7217_6fba,
0x0a63_7dc5_a2c8_98a6,
0x113f_9804_bef9_0dae,
0x1b71_0b35_131c_471b,
0x28db_77f5_2304_7d84,
0x32ca_ab7b_40c7_2493,
0x3c9e_be0a_15c9_bebc,
0x431d_67c4_9c10_0d4c,
0x4cc5_d4be_cb3e_42b6,
0x597f_299c_fc65_7e2a,
0x5fcb_6fab_3ad6_faec,
0x6c44_198c_4a47_5817,
];
#[inline]
fn compress32(state: &mut [u32; 8], block: &[u8; 64]) {
let mut schedule = [0u32; 64];
for (i, chunk) in block.chunks_exact(4).enumerate() {
schedule[i] = u32::from_be_bytes(chunk.try_into().unwrap());
}
for word_idx in 16..64 {
let sigma0 = schedule[word_idx - 15].rotate_right(7)
^ schedule[word_idx - 15].rotate_right(18)
^ (schedule[word_idx - 15] >> 3);
let sigma1 = schedule[word_idx - 2].rotate_right(17)
^ schedule[word_idx - 2].rotate_right(19)
^ (schedule[word_idx - 2] >> 10);
schedule[word_idx] = schedule[word_idx - 16]
.wrapping_add(sigma0)
.wrapping_add(schedule[word_idx - 7])
.wrapping_add(sigma1);
}
let mut a_reg = state[0];
let mut b_reg = state[1];
let mut c_reg = state[2];
let mut d_reg = state[3];
let mut e_reg = state[4];
let mut f_reg = state[5];
let mut g_reg = state[6];
let mut h_reg = state[7];
for (round_idx, &schedule_word) in schedule.iter().enumerate() {
let sigma1 = e_reg.rotate_right(6) ^ e_reg.rotate_right(11) ^ e_reg.rotate_right(25);
let choose = (e_reg & f_reg) ^ ((!e_reg) & g_reg);
let temp1 = h_reg
.wrapping_add(sigma1)
.wrapping_add(choose)
.wrapping_add(K32[round_idx])
.wrapping_add(schedule_word);
let sigma0 = a_reg.rotate_right(2) ^ a_reg.rotate_right(13) ^ a_reg.rotate_right(22);
let majority = (a_reg & b_reg) ^ (a_reg & c_reg) ^ (b_reg & c_reg);
let temp2 = sigma0.wrapping_add(majority);
h_reg = g_reg;
g_reg = f_reg;
f_reg = e_reg;
e_reg = d_reg.wrapping_add(temp1);
d_reg = c_reg;
c_reg = b_reg;
b_reg = a_reg;
a_reg = temp1.wrapping_add(temp2);
}
state[0] = state[0].wrapping_add(a_reg);
state[1] = state[1].wrapping_add(b_reg);
state[2] = state[2].wrapping_add(c_reg);
state[3] = state[3].wrapping_add(d_reg);
state[4] = state[4].wrapping_add(e_reg);
state[5] = state[5].wrapping_add(f_reg);
state[6] = state[6].wrapping_add(g_reg);
state[7] = state[7].wrapping_add(h_reg);
}
#[inline]
fn compress64(state: &mut [u64; 8], block: &[u8; 128]) {
let mut schedule = [0u64; 80];
for (i, chunk) in block.chunks_exact(8).enumerate() {
schedule[i] = u64::from_be_bytes(chunk.try_into().unwrap());
}
for word_idx in 16..80 {
let sigma0 = schedule[word_idx - 15].rotate_right(1)
^ schedule[word_idx - 15].rotate_right(8)
^ (schedule[word_idx - 15] >> 7);
let sigma1 = schedule[word_idx - 2].rotate_right(19)
^ schedule[word_idx - 2].rotate_right(61)
^ (schedule[word_idx - 2] >> 6);
schedule[word_idx] = schedule[word_idx - 16]
.wrapping_add(sigma0)
.wrapping_add(schedule[word_idx - 7])
.wrapping_add(sigma1);
}
let mut a_reg = state[0];
let mut b_reg = state[1];
let mut c_reg = state[2];
let mut d_reg = state[3];
let mut e_reg = state[4];
let mut f_reg = state[5];
let mut g_reg = state[6];
let mut h_reg = state[7];
for (round_idx, &schedule_word) in schedule.iter().enumerate() {
let sigma1 = e_reg.rotate_right(14) ^ e_reg.rotate_right(18) ^ e_reg.rotate_right(41);
let choose = (e_reg & f_reg) ^ ((!e_reg) & g_reg);
let temp1 = h_reg
.wrapping_add(sigma1)
.wrapping_add(choose)
.wrapping_add(K64[round_idx])
.wrapping_add(schedule_word);
let sigma0 = a_reg.rotate_right(28) ^ a_reg.rotate_right(34) ^ a_reg.rotate_right(39);
let majority = (a_reg & b_reg) ^ (a_reg & c_reg) ^ (b_reg & c_reg);
let temp2 = sigma0.wrapping_add(majority);
h_reg = g_reg;
g_reg = f_reg;
f_reg = e_reg;
e_reg = d_reg.wrapping_add(temp1);
d_reg = c_reg;
c_reg = b_reg;
b_reg = a_reg;
a_reg = temp1.wrapping_add(temp2);
}
state[0] = state[0].wrapping_add(a_reg);
state[1] = state[1].wrapping_add(b_reg);
state[2] = state[2].wrapping_add(c_reg);
state[3] = state[3].wrapping_add(d_reg);
state[4] = state[4].wrapping_add(e_reg);
state[5] = state[5].wrapping_add(f_reg);
state[6] = state[6].wrapping_add(g_reg);
state[7] = state[7].wrapping_add(h_reg);
}
#[derive(Clone)]
struct Sha2_32Core {
state: [u32; 8],
block: [u8; 64],
pos: usize,
bit_len: u64,
}
impl Sha2_32Core {
fn new(iv: [u32; 8]) -> Self {
Self {
state: iv,
block: [0u8; 64],
pos: 0,
bit_len: 0,
}
}
fn update(&mut self, mut data: &[u8]) {
while !data.is_empty() {
let take = (64 - self.pos).min(data.len());
self.block[self.pos..self.pos + take].copy_from_slice(&data[..take]);
self.pos += take;
data = &data[take..];
if self.pos == 64 {
compress32(&mut self.state, &self.block);
self.block = [0u8; 64];
self.pos = 0;
self.bit_len = self.bit_len.wrapping_add(512);
}
}
}
fn finalize<const OUT: usize>(mut self) -> [u8; OUT] {
self.bit_len = self.bit_len.wrapping_add((self.pos as u64) * 8);
self.block[self.pos] = 0x80;
self.pos += 1;
if self.pos > 56 {
self.block[self.pos..].fill(0);
compress32(&mut self.state, &self.block);
self.block = [0u8; 64];
self.pos = 0;
}
self.block[self.pos..56].fill(0);
self.block[56..].copy_from_slice(&self.bit_len.to_be_bytes());
compress32(&mut self.state, &self.block);
let mut full = [0u8; 32];
for (chunk, word) in full.chunks_exact_mut(4).zip(self.state.iter()) {
chunk.copy_from_slice(&word.to_be_bytes());
}
let mut out = [0u8; OUT];
out.copy_from_slice(&full[..OUT]);
out
}
fn finalize_into_reset<const OUT: usize>(&mut self, out: &mut [u8; OUT]) {
self.bit_len = self.bit_len.wrapping_add((self.pos as u64) * 8);
self.block[self.pos] = 0x80;
self.pos += 1;
if self.pos > 56 {
self.block[self.pos..].fill(0);
compress32(&mut self.state, &self.block);
self.block = [0u8; 64];
self.pos = 0;
}
self.block[self.pos..56].fill(0);
self.block[56..].copy_from_slice(&self.bit_len.to_be_bytes());
compress32(&mut self.state, &self.block);
let mut full = [0u8; 32];
for (chunk, word) in full.chunks_exact_mut(4).zip(self.state.iter()) {
chunk.copy_from_slice(&word.to_be_bytes());
}
out.copy_from_slice(&full[..OUT]);
self.zeroize();
}
fn zeroize(&mut self) {
crate::ct::zeroize_slice(self.state.as_mut_slice());
crate::ct::zeroize_slice(self.block.as_mut_slice());
self.pos = 0;
self.bit_len = 0;
}
}
#[derive(Clone)]
struct Sha2_64Core {
state: [u64; 8],
block: [u8; 128],
pos: usize,
bit_len: u128,
}
impl Sha2_64Core {
fn new(iv: [u64; 8]) -> Self {
Self {
state: iv,
block: [0u8; 128],
pos: 0,
bit_len: 0,
}
}
fn update(&mut self, mut data: &[u8]) {
while !data.is_empty() {
let take = (128 - self.pos).min(data.len());
self.block[self.pos..self.pos + take].copy_from_slice(&data[..take]);
self.pos += take;
data = &data[take..];
if self.pos == 128 {
compress64(&mut self.state, &self.block);
self.block = [0u8; 128];
self.pos = 0;
self.bit_len = self.bit_len.wrapping_add(1024);
}
}
}
fn finalize<const OUT: usize>(mut self) -> [u8; OUT] {
self.bit_len = self.bit_len.wrapping_add((self.pos as u128) * 8);
self.block[self.pos] = 0x80;
self.pos += 1;
if self.pos > 112 {
self.block[self.pos..].fill(0);
compress64(&mut self.state, &self.block);
self.block = [0u8; 128];
self.pos = 0;
}
self.block[self.pos..112].fill(0);
self.block[112..].copy_from_slice(&self.bit_len.to_be_bytes());
compress64(&mut self.state, &self.block);
let mut full = [0u8; 64];
for (chunk, word) in full.chunks_exact_mut(8).zip(self.state.iter()) {
chunk.copy_from_slice(&word.to_be_bytes());
}
let mut out = [0u8; OUT];
out.copy_from_slice(&full[..OUT]);
out
}
fn finalize_into_reset<const OUT: usize>(&mut self, out: &mut [u8; OUT]) {
self.bit_len = self.bit_len.wrapping_add((self.pos as u128) * 8);
self.block[self.pos] = 0x80;
self.pos += 1;
if self.pos > 112 {
self.block[self.pos..].fill(0);
compress64(&mut self.state, &self.block);
self.block = [0u8; 128];
self.pos = 0;
}
self.block[self.pos..112].fill(0);
self.block[112..].copy_from_slice(&self.bit_len.to_be_bytes());
compress64(&mut self.state, &self.block);
let mut full = [0u8; 64];
for (chunk, word) in full.chunks_exact_mut(8).zip(self.state.iter()) {
chunk.copy_from_slice(&word.to_be_bytes());
}
out.copy_from_slice(&full[..OUT]);
self.zeroize();
}
fn zeroize(&mut self) {
crate::ct::zeroize_slice(self.state.as_mut_slice());
crate::ct::zeroize_slice(self.block.as_mut_slice());
self.pos = 0;
self.bit_len = 0;
}
}
macro_rules! define_sha2_32 {
($name:ident, $out_len:expr, $iv:expr) => {
#[derive(Clone)]
pub struct $name {
inner: Sha2_32Core,
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
impl $name {
pub const BLOCK_LEN: usize = 64;
pub const OUTPUT_LEN: usize = $out_len;
#[must_use]
pub fn new() -> Self {
Self {
inner: Sha2_32Core::new($iv),
}
}
pub fn update(&mut self, data: &[u8]) {
self.inner.update(data);
}
#[must_use]
pub fn finalize(self) -> [u8; $out_len] {
self.inner.finalize::<$out_len>()
}
#[must_use]
pub fn digest(data: &[u8]) -> [u8; $out_len] {
let mut h = Self::new();
h.update(data);
h.finalize()
}
}
impl Digest for $name {
const BLOCK_LEN: usize = 64;
const OUTPUT_LEN: usize = $out_len;
fn new() -> Self {
Self::new()
}
fn update(&mut self, data: &[u8]) {
self.inner.update(data);
}
fn finalize_into(self, out: &mut [u8]) {
assert_eq!(out.len(), $out_len, "wrong digest length");
out.copy_from_slice(&self.inner.finalize::<$out_len>());
}
fn finalize_reset(&mut self, out: &mut [u8]) {
let out: &mut [u8; $out_len] = out.try_into().expect("wrong digest length");
self.inner.finalize_into_reset::<$out_len>(out);
}
fn zeroize(&mut self) {
self.inner.zeroize();
}
}
};
}
macro_rules! define_sha2_64 {
($name:ident, $out_len:expr, $iv:expr) => {
#[derive(Clone)]
pub struct $name {
inner: Sha2_64Core,
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
impl $name {
pub const BLOCK_LEN: usize = 128;
pub const OUTPUT_LEN: usize = $out_len;
#[must_use]
pub fn new() -> Self {
Self {
inner: Sha2_64Core::new($iv),
}
}
pub fn update(&mut self, data: &[u8]) {
self.inner.update(data);
}
#[must_use]
pub fn finalize(self) -> [u8; $out_len] {
self.inner.finalize::<$out_len>()
}
#[must_use]
pub fn digest(data: &[u8]) -> [u8; $out_len] {
let mut h = Self::new();
h.update(data);
h.finalize()
}
}
impl Digest for $name {
const BLOCK_LEN: usize = 128;
const OUTPUT_LEN: usize = $out_len;
fn new() -> Self {
Self::new()
}
fn update(&mut self, data: &[u8]) {
self.inner.update(data);
}
fn finalize_into(self, out: &mut [u8]) {
assert_eq!(out.len(), $out_len, "wrong digest length");
out.copy_from_slice(&self.inner.finalize::<$out_len>());
}
fn finalize_reset(&mut self, out: &mut [u8]) {
let out: &mut [u8; $out_len] = out.try_into().expect("wrong digest length");
self.inner.finalize_into_reset::<$out_len>(out);
}
fn zeroize(&mut self) {
self.inner.zeroize();
}
}
};
}
define_sha2_32!(
Sha224,
28,
[
0xc105_9ed8,
0x367c_d507,
0x3070_dd17,
0xf70e_5939,
0xffc0_0b31,
0x6858_1511,
0x64f9_8fa7,
0xbefa_4fa4,
]
);
define_sha2_32!(
Sha256,
32,
[
0x6a09_e667,
0xbb67_ae85,
0x3c6e_f372,
0xa54f_f53a,
0x510e_527f,
0x9b05_688c,
0x1f83_d9ab,
0x5be0_cd19,
]
);
define_sha2_64!(
Sha384,
48,
[
0xcbbb_9d5d_c105_9ed8,
0x629a_292a_367c_d507,
0x9159_015a_3070_dd17,
0x152f_ecd8_f70e_5939,
0x6733_2667_ffc0_0b31,
0x8eb4_4a87_6858_1511,
0xdb0c_2e0d_64f9_8fa7,
0x47b5_481d_befa_4fa4,
]
);
define_sha2_64!(
Sha512,
64,
[
0x6a09_e667_f3bc_c908,
0xbb67_ae85_84ca_a73b,
0x3c6e_f372_fe94_f82b,
0xa54f_f53a_5f1d_36f1,
0x510e_527f_ade6_82d1,
0x9b05_688c_2b3e_6c1f,
0x1f83_d9ab_fb41_bd6b,
0x5be0_cd19_137e_2179,
]
);
define_sha2_64!(
Sha512_224,
28,
[
0x8c3d_37c8_1954_4da2,
0x73e1_9966_89dc_d4d6,
0x1dfa_b7ae_32ff_9c82,
0x679d_d514_582f_9fcf,
0x0f6d_2b69_7bd4_4da8,
0x77e3_6f73_04c4_8942,
0x3f9d_85a8_6a1d_36c8,
0x1112_e6ad_91d6_92a1,
]
);
define_sha2_64!(
Sha512_256,
32,
[
0x2231_2194_fc2b_f72c,
0x9f55_5fa3_c84c_64c2,
0x2393_b86b_6f53_b151,
0x9638_7719_5940_eabd,
0x9628_3ee2_a88e_ffe3,
0xbe5e_1e25_5386_3992,
0x2b01_99fc_2c85_b8aa,
0x0eb7_2ddc_81c5_2ca2,
]
);
#[cfg(test)]
mod tests {
use super::*;
fn hex(bytes: &[u8]) -> String {
let mut out = String::with_capacity(bytes.len() * 2);
for b in bytes {
use core::fmt::Write;
let _ = write!(&mut out, "{b:02x}");
}
out
}
#[test]
fn sha224_empty() {
assert_eq!(
hex(&Sha224::digest(b"")),
"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"
);
}
#[test]
fn sha224_abc_streaming() {
let mut h = Sha224::new();
h.update(b"a");
h.update(b"b");
h.update(b"c");
assert_eq!(
hex(&h.finalize()),
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"
);
}
#[test]
fn sha256_empty() {
assert_eq!(
hex(&Sha256::digest(b"")),
"e3b0c44298fc1c149afbf4c8996fb924".to_owned() + "27ae41e4649b934ca495991b7852b855"
);
}
#[test]
fn sha256_abc_streaming() {
let mut h = Sha256::new();
h.update(b"a");
h.update(b"b");
h.update(b"c");
assert_eq!(
hex(&h.finalize()),
"ba7816bf8f01cfea414140de5dae2223".to_owned() + "b00361a396177a9cb410ff61f20015ad"
);
}
#[test]
fn sha384_empty() {
assert_eq!(
hex(&Sha384::digest(b"")),
"38b060a751ac96384cd9327eb1b1e36a".to_owned()
+ "21fdb71114be07434c0cc7bf63f6e1da"
+ "274edebfe76f65fbd51ad2f14898b95b"
);
}
#[test]
fn sha384_abc_streaming() {
let mut h = Sha384::new();
h.update(b"a");
h.update(b"b");
h.update(b"c");
assert_eq!(
hex(&h.finalize()),
"cb00753f45a35e8bb5a03d699ac65007".to_owned()
+ "272c32ab0eded1631a8b605a43ff5bed"
+ "8086072ba1e7cc2358baeca134c825a7"
);
}
#[test]
fn sha512_empty() {
assert_eq!(
hex(&Sha512::digest(b"")),
"cf83e1357eefb8bdf1542850d66d8007".to_owned()
+ "d620e4050b5715dc83f4a921d36ce9ce"
+ "47d0d13c5d85f2b0ff8318d2877eec2f"
+ "63b931bd47417a81a538327af927da3e"
);
}
#[test]
fn sha512_abc_streaming() {
let mut h = Sha512::new();
h.update(b"a");
h.update(b"b");
h.update(b"c");
assert_eq!(
hex(&h.finalize()),
"ddaf35a193617abacc417349ae204131".to_owned()
+ "12e6fa4e89a97ea20a9eeee64b55d39a"
+ "2192992a274fc1a836ba3c23a3feebbd"
+ "454d4423643ce80e2a9ac94fa54ca49f"
);
}
#[test]
fn sha512_224_empty() {
assert_eq!(
hex(&Sha512_224::digest(b"")),
"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"
);
}
#[test]
fn sha512_224_abc_streaming() {
let mut h = Sha512_224::new();
h.update(b"a");
h.update(b"b");
h.update(b"c");
assert_eq!(
hex(&h.finalize()),
"4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"
);
}
#[test]
fn sha512_256_empty() {
assert_eq!(
hex(&Sha512_256::digest(b"")),
"c672b8d1ef56ed28ab87c3622c511406".to_owned() + "9bdd3ad7b8f9737498d0c01ecef0967a"
);
}
#[test]
fn sha512_256_abc_streaming() {
let mut h = Sha512_256::new();
h.update(b"a");
h.update(b"b");
h.update(b"c");
assert_eq!(
hex(&h.finalize()),
"53048e2681941ef99b2e29b76b4c7dab".to_owned() + "e4c2d0c634fc6d46e0e2f13107e7af23"
);
}
#[test]
fn sha256_matches_openssl() {
let msg = b"The quick brown fox jumps over the lazy dog";
let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha256", "-binary"], msg) else {
return;
};
assert_eq!(Sha256::digest(msg).as_slice(), expected.as_slice());
}
#[test]
fn sha224_matches_openssl() {
let msg = b"The quick brown fox jumps over the lazy dog";
let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha224", "-binary"], msg) else {
return;
};
assert_eq!(Sha224::digest(msg).as_slice(), expected.as_slice());
}
#[test]
fn sha384_matches_openssl() {
let msg = b"The quick brown fox jumps over the lazy dog";
let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha384", "-binary"], msg) else {
return;
};
assert_eq!(Sha384::digest(msg).as_slice(), expected.as_slice());
}
#[test]
fn sha512_matches_openssl() {
let msg = b"The quick brown fox jumps over the lazy dog";
let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha512", "-binary"], msg) else {
return;
};
assert_eq!(Sha512::digest(msg).as_slice(), expected.as_slice());
}
#[test]
fn sha512_224_matches_openssl() {
let msg = b"The quick brown fox jumps over the lazy dog";
let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha512-224", "-binary"], msg)
else {
return;
};
assert_eq!(Sha512_224::digest(msg).as_slice(), expected.as_slice());
}
#[test]
fn sha512_256_matches_openssl() {
let msg = b"The quick brown fox jumps over the lazy dog";
let Some(expected) = crate::test_utils::run_openssl(&["dgst", "-sha512-256", "-binary"], msg)
else {
return;
};
assert_eq!(Sha512_256::digest(msg).as_slice(), expected.as_slice());
}
}