use digest::Digest;
use cryptoutil::{write_u32_be, read_u32v_be,
write_u64_be, read_u64v_be,
add_bytes_to_bits, add_bytes_to_bits_tuple,
FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
use simd::{u32x4, u64x2};
const STATE_LEN: usize = 8;
const BLOCK_LEN: usize = 16;
#[inline]
fn sha256load(v2: u32x4, v3: u32x4) -> u32x4 {
u32x4(v3.3, v2.0, v2.1, v2.2)
}
#[inline]
fn sha256swap(v0: u32x4) -> u32x4 {
u32x4(v0.2, v0.3, v0.0, v0.1)
}
fn sha256msg1(v0: u32x4, v1: u32x4) -> u32x4 {
#[inline]
fn sigma0x4(x: u32x4) -> u32x4 {
((x >> u32x4( 7, 7, 7, 7)) | (x << u32x4(25, 25, 25, 25))) ^
((x >> u32x4(18, 18, 18, 18)) | (x << u32x4(14, 14, 14, 14))) ^
(x >> u32x4( 3, 3, 3, 3))
}
v0 + sigma0x4(sha256load(v0, v1))
}
fn sha256msg2(v4: u32x4, v3: u32x4) -> u32x4 {
macro_rules! sigma1 {
($a:expr) => (($a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10)))
}
let u32x4(x3, x2, x1, x0) = v4;
let u32x4(w15, w14, _, _) = v3;
let w16 = x0.wrapping_add(sigma1!(w14));
let w17 = x1.wrapping_add(sigma1!(w15));
let w18 = x2.wrapping_add(sigma1!(w16));
let w19 = x3.wrapping_add(sigma1!(w17));
u32x4(w19, w18, w17, w16)
}
pub fn sha256_schedule_x4(v0: u32x4, v1: u32x4, v2: u32x4, v3: u32x4) -> u32x4 {
sha256msg2(sha256msg1(v0, v1) + sha256load(v2, v3), v3)
}
pub fn sha256_digest_round_x2(cdgh: u32x4, abef: u32x4, wk: u32x4) -> u32x4 {
macro_rules! big_sigma0 {
($a:expr) => (($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22)))
}
macro_rules! big_sigma1 {
($a:expr) => (($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25)))
}
macro_rules! bool3ary_202 {
($a:expr, $b:expr, $c:expr) => (($c ^ ($a & ($b ^ $c))))
} macro_rules! bool3ary_232 {
($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
} let u32x4(_, _, wk1, wk0) = wk;
let u32x4(a0, b0, e0, f0) = abef;
let u32x4(c0, d0, g0, h0) = cdgh;
let x0 = big_sigma1!(e0).wrapping_add(bool3ary_202!(e0, f0, g0)).wrapping_add(wk0).wrapping_add(h0);
let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
let (a1, b1, c1, d1, e1, f1, g1, h1) = (
x0.wrapping_add(y0), a0, b0, c0,
x0.wrapping_add(d0), e0, f0, g0);
let x1 = big_sigma1!(e1).wrapping_add(bool3ary_202!(e1, f1, g1)).wrapping_add(wk1).wrapping_add(h1);
let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1));
let (a2, b2, _, _, e2, f2, _, _) = (
x1.wrapping_add(y1), a1, b1, c1,
x1.wrapping_add(d1), e1, f1, g1);
u32x4(a2, b2, e2, f2)
}
pub fn sha256_digest_block_u32(state: &mut [u32; 8], block: &[u32; 16]) {
let k = &K32X4;
macro_rules! schedule {
($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
sha256msg2(sha256msg1($v0, $v1) + sha256load($v2, $v3), $v3)
)
}
macro_rules! rounds4 {
($abef:ident, $cdgh:ident, $rest:expr) => {
{
$cdgh = sha256_digest_round_x2($cdgh, $abef, $rest);
$abef = sha256_digest_round_x2($abef, $cdgh, sha256swap($rest));
}
}
}
let mut abef = u32x4(state[0],
state[1],
state[4],
state[5]);
let mut cdgh = u32x4(state[2],
state[3],
state[6],
state[7]);
let mut w0 = u32x4(block[3],
block[2],
block[1],
block[0]);
rounds4!(abef, cdgh, k[0] + w0);
let mut w1 = u32x4(block[7],
block[6],
block[5],
block[4]);
rounds4!(abef, cdgh, k[1] + w1);
let mut w2 = u32x4(block[11],
block[10],
block[9],
block[8]);
rounds4!(abef, cdgh, k[2] + w2);
let mut w3 = u32x4(block[15],
block[14],
block[13],
block[12]);
rounds4!(abef, cdgh, k[3] + w3);
let mut w4 = schedule!(w0, w1, w2, w3);
rounds4!(abef, cdgh, k[4] + w4);
w0 = schedule!(w1, w2, w3, w4);
rounds4!(abef, cdgh, k[5] + w0);
w1 = schedule!(w2, w3, w4, w0);
rounds4!(abef, cdgh, k[6] + w1);
w2 = schedule!(w3, w4, w0, w1);
rounds4!(abef, cdgh, k[7] + w2);
w3 = schedule!(w4, w0, w1, w2);
rounds4!(abef, cdgh, k[8] + w3);
w4 = schedule!(w0, w1, w2, w3);
rounds4!(abef, cdgh, k[9] + w4);
w0 = schedule!(w1, w2, w3, w4);
rounds4!(abef, cdgh, k[10] + w0);
w1 = schedule!(w2, w3, w4, w0);
rounds4!(abef, cdgh, k[11] + w1);
w2 = schedule!(w3, w4, w0, w1);
rounds4!(abef, cdgh, k[12] + w2);
w3 = schedule!(w4, w0, w1, w2);
rounds4!(abef, cdgh, k[13] + w3);
w4 = schedule!(w0, w1, w2, w3);
rounds4!(abef, cdgh, k[14] + w4);
w0 = schedule!(w1, w2, w3, w4);
rounds4!(abef, cdgh, k[15] + w0);
let u32x4(a, b, e, f) = abef;
let u32x4(c, d, g, h) = cdgh;
state[0] = state[0].wrapping_add(a);
state[1] = state[1].wrapping_add(b);
state[2] = state[2].wrapping_add(c);
state[3] = state[3].wrapping_add(d);
state[4] = state[4].wrapping_add(e);
state[5] = state[5].wrapping_add(f);
state[6] = state[6].wrapping_add(g);
state[7] = state[7].wrapping_add(h);
}
pub fn sha256_digest_block(state: &mut [u32; 8], block: &[u8]) {
assert_eq!(block.len(), BLOCK_LEN*4);
let mut block2 = [0u32; BLOCK_LEN];
read_u32v_be(&mut block2[..], block);
sha256_digest_block_u32(state, &block2);
}
#[inline]
fn sha512load(v0: u64x2, v1: u64x2) -> u64x2 {
u64x2(v1.1, v0.0)
}
pub fn sha512_schedule_x2(v0: u64x2, v1: u64x2, v4to5: u64x2, v7: u64x2) -> u64x2 {
fn sigma0(x: u64) -> u64 {
((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7)
}
fn sigma1(x: u64) -> u64 {
((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6)
}
let u64x2(w1, w0) = v0;
let u64x2(_, w2) = v1;
let u64x2(w10, w9) = v4to5;
let u64x2(w15, w14) = v7;
let w16 = sigma1(w14).wrapping_add(w9).wrapping_add(sigma0(w1)).wrapping_add(w0);
let w17 = sigma1(w15).wrapping_add(w10).wrapping_add(sigma0(w2)).wrapping_add(w1);
u64x2(w17, w16)
}
pub fn sha512_digest_round(ae: u64x2, bf: u64x2, cg: u64x2, dh: u64x2, wk0: u64) -> u64x2 {
macro_rules! big_sigma0 {
($a:expr) => (($a.rotate_right(28) ^ $a.rotate_right(34) ^ $a.rotate_right(39)))
}
macro_rules! big_sigma1 {
($a:expr) => (($a.rotate_right(14) ^ $a.rotate_right(18) ^ $a.rotate_right(41)))
}
macro_rules! bool3ary_202 {
($a:expr, $b:expr, $c:expr) => (($c ^ ($a & ($b ^ $c))))
} macro_rules! bool3ary_232 {
($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
} let u64x2(a0, e0) = ae;
let u64x2(b0, f0) = bf;
let u64x2(c0, g0) = cg;
let u64x2(d0, h0) = dh;
let x0 = big_sigma1!(e0).wrapping_add(bool3ary_202!(e0, f0, g0)).wrapping_add(wk0).wrapping_add(h0);
let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0));
let (a1, _, _, _, e1, _, _, _) = (
x0.wrapping_add(y0), a0, b0, c0,
x0.wrapping_add(d0), e0, f0, g0);
u64x2(a1, e1)
}
pub fn sha512_digest_block_u64(state: &mut [u64; 8], block: &[u64; 16]) {
let k = &K64X2;
macro_rules! schedule {
($v0:expr, $v1:expr, $v4:expr, $v5:expr, $v7:expr) => (
sha512_schedule_x2($v0, $v1, sha512load($v4, $v5), $v7)
)
}
macro_rules! rounds4 {
($ae:ident, $bf:ident, $cg:ident, $dh:ident, $wk0:expr, $wk1:expr) => {
{
let u64x2(u, t) = $wk0;
let u64x2(w, v) = $wk1;
$dh = sha512_digest_round($ae, $bf, $cg, $dh, t);
$cg = sha512_digest_round($dh, $ae, $bf, $cg, u);
$bf = sha512_digest_round($cg, $dh, $ae, $bf, v);
$ae = sha512_digest_round($bf, $cg, $dh, $ae, w);
}
}
}
let mut ae = u64x2(state[0],
state[4]);
let mut bf = u64x2(state[1],
state[5]);
let mut cg = u64x2(state[2],
state[6]);
let mut dh = u64x2(state[3],
state[7]);
let (mut w1, mut w0) = (u64x2(block[3],
block[2]),
u64x2(block[1],
block[0]));
rounds4!(ae, bf, cg, dh, k[0] + w0, k[1] + w1);
let (mut w3, mut w2) = (u64x2(block[7],
block[6]),
u64x2(block[5],
block[4]));
rounds4!(ae, bf, cg, dh, k[2] + w2, k[3] + w3);
let (mut w5, mut w4) = (u64x2(block[11],
block[10]),
u64x2(block[9],
block[8]));
rounds4!(ae, bf, cg, dh, k[4] + w4, k[5] + w5);
let (mut w7, mut w6) = (u64x2(block[15],
block[14]),
u64x2(block[13],
block[12]));
rounds4!(ae, bf, cg, dh, k[6] + w6, k[7] + w7);
let mut w8 = schedule!(w0, w1, w4, w5, w7);
let mut w9 = schedule!(w1, w2, w5, w6, w8);
rounds4!(ae, bf, cg, dh, k[8] + w8, k[9] + w9);
w0 = schedule!(w2, w3, w6, w7, w9);
w1 = schedule!(w3, w4, w7, w8, w0);
rounds4!(ae, bf, cg, dh, k[10] + w0, k[11] + w1);
w2 = schedule!(w4, w5, w8, w9, w1);
w3 = schedule!(w5, w6, w9, w0, w2);
rounds4!(ae, bf, cg, dh, k[12] + w2, k[13] + w3);
w4 = schedule!(w6, w7, w0, w1, w3);
w5 = schedule!(w7, w8, w1, w2, w4);
rounds4!(ae, bf, cg, dh, k[14] + w4, k[15] + w5);
w6 = schedule!(w8, w9, w2, w3, w5);
w7 = schedule!(w9, w0, w3, w4, w6);
rounds4!(ae, bf, cg, dh, k[16] + w6, k[17] + w7);
w8 = schedule!(w0, w1, w4, w5, w7);
w9 = schedule!(w1, w2, w5, w6, w8);
rounds4!(ae, bf, cg, dh, k[18] + w8, k[19] + w9);
w0 = schedule!(w2, w3, w6, w7, w9);
w1 = schedule!(w3, w4, w7, w8, w0);
rounds4!(ae, bf, cg, dh, k[20] + w0, k[21] + w1);
w2 = schedule!(w4, w5, w8, w9, w1);
w3 = schedule!(w5, w6, w9, w0, w2);
rounds4!(ae, bf, cg, dh, k[22] + w2, k[23] + w3);
w4 = schedule!(w6, w7, w0, w1, w3);
w5 = schedule!(w7, w8, w1, w2, w4);
rounds4!(ae, bf, cg, dh, k[24] + w4, k[25] + w5);
w6 = schedule!(w8, w9, w2, w3, w5);
w7 = schedule!(w9, w0, w3, w4, w6);
rounds4!(ae, bf, cg, dh, k[26] + w6, k[27] + w7);
w8 = schedule!(w0, w1, w4, w5, w7);
w9 = schedule!(w1, w2, w5, w6, w8);
rounds4!(ae, bf, cg, dh, k[28] + w8, k[29] + w9);
w0 = schedule!(w2, w3, w6, w7, w9);
w1 = schedule!(w3, w4, w7, w8, w0);
rounds4!(ae, bf, cg, dh, k[30] + w0, k[31] + w1);
w2 = schedule!(w4, w5, w8, w9, w1);
w3 = schedule!(w5, w6, w9, w0, w2);
rounds4!(ae, bf, cg, dh, k[32] + w2, k[33] + w3);
w4 = schedule!(w6, w7, w0, w1, w3);
w5 = schedule!(w7, w8, w1, w2, w4);
rounds4!(ae, bf, cg, dh, k[34] + w4, k[35] + w5);
w6 = schedule!(w8, w9, w2, w3, w5);
w7 = schedule!(w9, w0, w3, w4, w6);
rounds4!(ae, bf, cg, dh, k[36] + w6, k[37] + w7);
w8 = schedule!(w0, w1, w4, w5, w7);
w9 = schedule!(w1, w2, w5, w6, w8);
rounds4!(ae, bf, cg, dh, k[38] + w8, k[39] + w9);
let u64x2(a, e) = ae;
let u64x2(b, f) = bf;
let u64x2(c, g) = cg;
let u64x2(d, h) = dh;
state[0] = state[0].wrapping_add(a);
state[1] = state[1].wrapping_add(b);
state[2] = state[2].wrapping_add(c);
state[3] = state[3].wrapping_add(d);
state[4] = state[4].wrapping_add(e);
state[5] = state[5].wrapping_add(f);
state[6] = state[6].wrapping_add(g);
state[7] = state[7].wrapping_add(h);
}
pub fn sha512_digest_block(state: &mut [u64; 8], block: &[u8]) {
assert_eq!(block.len(), BLOCK_LEN*8);
let mut block2 = [0u64; BLOCK_LEN];
read_u64v_be(&mut block2[..], block);
sha512_digest_block_u64(state, &block2);
}
#[derive(Copy, Clone)]
struct Engine512State {
h: [u64; 8]
}
impl Engine512State {
fn new(h: &[u64; 8]) -> Engine512State {
Engine512State {
h: *h
}
}
fn reset(&mut self, h: &[u64; STATE_LEN]) {
self.h = *h;
}
pub fn process_block(&mut self, data: &[u8]) {
sha512_digest_block(&mut self.h, data);
}
}
pub const K64: [u64; 80] = [
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
];
pub const K64X2: [u64x2; 40] = [
u64x2(K64[1], K64[0]), u64x2(K64[3], K64[2]), u64x2(K64[5], K64[4]), u64x2(K64[7], K64[6]),
u64x2(K64[9], K64[8]), u64x2(K64[11], K64[10]), u64x2(K64[13], K64[12]), u64x2(K64[15], K64[14]),
u64x2(K64[17], K64[16]), u64x2(K64[19], K64[18]), u64x2(K64[21], K64[20]), u64x2(K64[23], K64[22]),
u64x2(K64[25], K64[24]), u64x2(K64[27], K64[26]), u64x2(K64[29], K64[28]), u64x2(K64[31], K64[30]),
u64x2(K64[33], K64[32]), u64x2(K64[35], K64[34]), u64x2(K64[37], K64[36]), u64x2(K64[39], K64[38]),
u64x2(K64[41], K64[40]), u64x2(K64[43], K64[42]), u64x2(K64[45], K64[44]), u64x2(K64[47], K64[46]),
u64x2(K64[49], K64[48]), u64x2(K64[51], K64[50]), u64x2(K64[53], K64[52]), u64x2(K64[55], K64[54]),
u64x2(K64[57], K64[56]), u64x2(K64[59], K64[58]), u64x2(K64[61], K64[60]), u64x2(K64[63], K64[62]),
u64x2(K64[65], K64[64]), u64x2(K64[67], K64[66]), u64x2(K64[69], K64[68]), u64x2(K64[71], K64[70]),
u64x2(K64[73], K64[72]), u64x2(K64[75], K64[74]), u64x2(K64[77], K64[76]), u64x2(K64[79], K64[78])
];
#[derive(Copy, Clone)]
struct Engine512 {
length_bits: (u64, u64),
buffer: FixedBuffer128,
state: Engine512State,
finished: bool,
}
impl Engine512 {
fn new(h: &[u64; STATE_LEN]) -> Engine512 {
Engine512 {
length_bits: (0, 0),
buffer: FixedBuffer128::new(),
state: Engine512State::new(h),
finished: false
}
}
fn reset(&mut self, h: &[u64; STATE_LEN]) {
self.length_bits = (0, 0);
self.buffer.reset();
self.state.reset(h);
self.finished = false;
}
fn input(&mut self, input: &[u8]) {
assert!(!self.finished);
self.length_bits = add_bytes_to_bits_tuple(self.length_bits, input.len() as u64);
let self_state = &mut self.state;
self.buffer.input(input, |input: &[u8]| { self_state.process_block(input) });
}
fn finish(&mut self) {
if self.finished {
return;
}
let self_state = &mut self.state;
self.buffer.standard_padding(16, |input: &[u8]| { self_state.process_block(input) });
match self.length_bits {
(hi, low) => {
write_u64_be(self.buffer.next(8), hi);
write_u64_be(self.buffer.next(8), low);
}
}
self_state.process_block(self.buffer.full_buffer());
self.finished = true;
}
}
#[derive(Copy, Clone)]
pub struct Sha512 {
engine: Engine512
}
impl Sha512 {
pub fn new() -> Sha512 {
Sha512 {
engine: Engine512::new(&H512)
}
}
}
impl Digest for Sha512 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(&mut out[0..8], self.engine.state.h[0]);
write_u64_be(&mut out[8..16], self.engine.state.h[1]);
write_u64_be(&mut out[16..24], self.engine.state.h[2]);
write_u64_be(&mut out[24..32], self.engine.state.h[3]);
write_u64_be(&mut out[32..40], self.engine.state.h[4]);
write_u64_be(&mut out[40..48], self.engine.state.h[5]);
write_u64_be(&mut out[48..56], self.engine.state.h[6]);
write_u64_be(&mut out[56..64], self.engine.state.h[7]);
}
fn reset(&mut self) {
self.engine.reset(&H512);
}
fn output_bits(&self) -> usize { 512 }
fn block_size(&self) -> usize { 128 }
}
static H512: [u64; STATE_LEN] = [
0x6a09e667f3bcc908,
0xbb67ae8584caa73b,
0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1,
0x510e527fade682d1,
0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b,
0x5be0cd19137e2179
];
#[derive(Copy, Clone)]
pub struct Sha384 {
engine: Engine512
}
impl Sha384 {
pub fn new() -> Sha384 {
Sha384 {
engine: Engine512::new(&H384)
}
}
}
impl Digest for Sha384 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(&mut out[0..8], self.engine.state.h[0]);
write_u64_be(&mut out[8..16], self.engine.state.h[1]);
write_u64_be(&mut out[16..24], self.engine.state.h[2]);
write_u64_be(&mut out[24..32], self.engine.state.h[3]);
write_u64_be(&mut out[32..40], self.engine.state.h[4]);
write_u64_be(&mut out[40..48], self.engine.state.h[5]);
}
fn reset(&mut self) {
self.engine.reset(&H384);
}
fn output_bits(&self) -> usize { 384 }
fn block_size(&self) -> usize { 128 }
}
static H384: [u64; STATE_LEN] = [
0xcbbb9d5dc1059ed8,
0x629a292a367cd507,
0x9159015a3070dd17,
0x152fecd8f70e5939,
0x67332667ffc00b31,
0x8eb44a8768581511,
0xdb0c2e0d64f98fa7,
0x47b5481dbefa4fa4
];
#[derive(Clone, Copy)]
pub struct Sha512Trunc256 {
engine: Engine512
}
impl Sha512Trunc256 {
pub fn new() -> Sha512Trunc256 {
Sha512Trunc256 {
engine: Engine512::new(&H512_TRUNC_256)
}
}
}
impl Digest for Sha512Trunc256 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(&mut out[0..8], self.engine.state.h[0]);
write_u64_be(&mut out[8..16], self.engine.state.h[1]);
write_u64_be(&mut out[16..24], self.engine.state.h[2]);
write_u64_be(&mut out[24..32], self.engine.state.h[3]);
}
fn reset(&mut self) {
self.engine.reset(&H512_TRUNC_256);
}
fn output_bits(&self) -> usize { 256 }
fn block_size(&self) -> usize { 128 }
}
static H512_TRUNC_256: [u64; STATE_LEN] = [
0x22312194fc2bf72c,
0x9f555fa3c84c64c2,
0x2393b86b6f53b151,
0x963877195940eabd,
0x96283ee2a88effe3,
0xbe5e1e2553863992,
0x2b0199fc2c85b8aa,
0x0eb72ddc81c52ca2
];
#[derive(Clone, Copy)]
pub struct Sha512Trunc224 {
engine: Engine512
}
impl Sha512Trunc224 {
pub fn new() -> Sha512Trunc224 {
Sha512Trunc224 {
engine: Engine512::new(&H512_TRUNC_224)
}
}
}
impl Digest for Sha512Trunc224 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u64_be(&mut out[0..8], self.engine.state.h[0]);
write_u64_be(&mut out[8..16], self.engine.state.h[1]);
write_u64_be(&mut out[16..24], self.engine.state.h[2]);
write_u32_be(&mut out[24..28], (self.engine.state.h[3] >> 32) as u32);
}
fn reset(&mut self) {
self.engine.reset(&H512_TRUNC_224);
}
fn output_bits(&self) -> usize { 224 }
fn block_size(&self) -> usize { 128 }
}
static H512_TRUNC_224: [u64; STATE_LEN] = [
0x8c3d37c819544da2,
0x73e1996689dcd4d6,
0x1dfab7ae32ff9c82,
0x679dd514582f9fcf,
0x0f6d2b697bd44da8,
0x77e36f7304c48942,
0x3f9d85a86a1d36c8,
0x1112e6ad91d692a1,
];
#[derive(Clone, Copy)]
struct Engine256State {
h: [u32; 8],
}
impl Engine256State {
fn new(h: &[u32; STATE_LEN]) -> Engine256State {
Engine256State {
h: *h
}
}
fn reset(&mut self, h: &[u32; STATE_LEN]) {
self.h = *h;
}
pub fn process_block(&mut self, data: &[u8]) {
sha256_digest_block(&mut self.h, data);
}
}
pub const K32: [u32; 64] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
pub const K32X4: [u32x4; 16] = [
u32x4(K32[3], K32[2], K32[1], K32[0]),
u32x4(K32[7], K32[6], K32[5], K32[4]),
u32x4(K32[11], K32[10], K32[9], K32[8]),
u32x4(K32[15], K32[14], K32[13], K32[12]),
u32x4(K32[19], K32[18], K32[17], K32[16]),
u32x4(K32[23], K32[22], K32[21], K32[20]),
u32x4(K32[27], K32[26], K32[25], K32[24]),
u32x4(K32[31], K32[30], K32[29], K32[28]),
u32x4(K32[35], K32[34], K32[33], K32[32]),
u32x4(K32[39], K32[38], K32[37], K32[36]),
u32x4(K32[43], K32[42], K32[41], K32[40]),
u32x4(K32[47], K32[46], K32[45], K32[44]),
u32x4(K32[51], K32[50], K32[49], K32[48]),
u32x4(K32[55], K32[54], K32[53], K32[52]),
u32x4(K32[59], K32[58], K32[57], K32[56]),
u32x4(K32[63], K32[62], K32[61], K32[60]),
];
#[derive(Clone, Copy)]
struct Engine256 {
length_bits: u64,
buffer: FixedBuffer64,
state: Engine256State,
finished: bool,
}
impl Engine256 {
fn new(h: &[u32; STATE_LEN]) -> Engine256 {
Engine256 {
length_bits: 0,
buffer: FixedBuffer64::new(),
state: Engine256State::new(h),
finished: false
}
}
fn reset(&mut self, h: &[u32; STATE_LEN]) {
self.length_bits = 0;
self.buffer.reset();
self.state.reset(h);
self.finished = false;
}
fn input(&mut self, input: &[u8]) {
assert!(!self.finished);
self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64);
let self_state = &mut self.state;
self.buffer.input(input, |input: &[u8]| { self_state.process_block(input) });
}
fn finish(&mut self) {
if self.finished {
return;
}
let self_state = &mut self.state;
self.buffer.standard_padding(8, |input: &[u8]| { self_state.process_block(input) });
write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 );
write_u32_be(self.buffer.next(4), self.length_bits as u32);
self_state.process_block(self.buffer.full_buffer());
self.finished = true;
}
}
#[derive(Clone, Copy)]
pub struct Sha256 {
engine: Engine256
}
impl Sha256 {
pub fn new() -> Sha256 {
Sha256 {
engine: Engine256::new(&H256)
}
}
}
impl Digest for Sha256 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u32_be(&mut out[0..4], self.engine.state.h[0]);
write_u32_be(&mut out[4..8], self.engine.state.h[1]);
write_u32_be(&mut out[8..12], self.engine.state.h[2]);
write_u32_be(&mut out[12..16], self.engine.state.h[3]);
write_u32_be(&mut out[16..20], self.engine.state.h[4]);
write_u32_be(&mut out[20..24], self.engine.state.h[5]);
write_u32_be(&mut out[24..28], self.engine.state.h[6]);
write_u32_be(&mut out[28..32], self.engine.state.h[7]);
}
fn reset(&mut self) {
self.engine.reset(&H256);
}
fn output_bits(&self) -> usize { 256 }
fn block_size(&self) -> usize { 64 }
}
static H256: [u32; STATE_LEN] = [
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19
];
#[derive(Clone, Copy)]
pub struct Sha224 {
engine: Engine256
}
impl Sha224 {
pub fn new() -> Sha224 {
Sha224 {
engine: Engine256::new(&H224)
}
}
}
impl Digest for Sha224 {
fn input(&mut self, d: &[u8]) {
self.engine.input(d);
}
fn result(&mut self, out: &mut [u8]) {
self.engine.finish();
write_u32_be(&mut out[0..4], self.engine.state.h[0]);
write_u32_be(&mut out[4..8], self.engine.state.h[1]);
write_u32_be(&mut out[8..12], self.engine.state.h[2]);
write_u32_be(&mut out[12..16], self.engine.state.h[3]);
write_u32_be(&mut out[16..20], self.engine.state.h[4]);
write_u32_be(&mut out[20..24], self.engine.state.h[5]);
write_u32_be(&mut out[24..28], self.engine.state.h[6]);
}
fn reset(&mut self) {
self.engine.reset(&H224);
}
fn output_bits(&self) -> usize { 224 }
fn block_size(&self) -> usize { 64 }
}
static H224: [u32; STATE_LEN] = [
0xc1059ed8,
0x367cd507,
0x3070dd17,
0xf70e5939,
0xffc00b31,
0x68581511,
0x64f98fa7,
0xbefa4fa4
];
#[cfg(test)]
mod tests {
use cryptoutil::test::test_digest_1million_random;
use digest::Digest;
use sha2::{Sha512, Sha384, Sha512Trunc256, Sha512Trunc224, Sha256, Sha224};
struct Test {
input: &'static str,
output_str: &'static str,
}
fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
for t in tests.iter() {
sh.input_str(t.input);
let out_str = sh.result_str();
assert!(&out_str[..] == t.output_str);
sh.reset();
}
for t in tests.iter() {
let len = t.input.len();
let mut left = len;
while left > 0 {
let take = (left + 1) / 2;
sh.input_str(&t.input[len - left..take + len - left]);
left = left - take;
}
let out_str = sh.result_str();
assert!(&out_str[..] == t.output_str);
sh.reset();
}
}
#[test]
fn test_sha512() {
let wikipedia_tests = vec![
Test {
input: "",
output_str: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
},
Test {
input: "The quick brown fox jumps over the lazy dog",
output_str: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6"
},
Test {
input: "The quick brown fox jumps over the lazy dog.",
output_str: "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed"
},
];
let tests = wikipedia_tests;
let mut sh = Box::new(Sha512::new());
test_hash(&mut *sh, &tests[..]);
}
#[test]
fn test_sha384() {
let wikipedia_tests = vec![
Test {
input: "",
output_str: "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
},
Test {
input: "The quick brown fox jumps over the lazy dog",
output_str: "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1"
},
Test {
input: "The quick brown fox jumps over the lazy dog.",
output_str: "ed892481d8272ca6df370bf706e4d7bc1b5739fa2177aae6c50e946678718fc67a7af2819a021c2fc34e91bdb63409d7"
},
];
let tests = wikipedia_tests;
let mut sh = Box::new(Sha384::new());
test_hash(&mut *sh, &tests[..]);
}
#[test]
fn test_sha512_256() {
let wikipedia_tests = vec![
Test {
input: "",
output_str: "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"
},
Test {
input: "The quick brown fox jumps over the lazy dog",
output_str: "dd9d67b371519c339ed8dbd25af90e976a1eeefd4ad3d889005e532fc5bef04d"
},
Test {
input: "The quick brown fox jumps over the lazy dog.",
output_str: "1546741840f8a492b959d9b8b2344b9b0eb51b004bba35c0aebaac86d45264c3"
},
];
let tests = wikipedia_tests;
let mut sh = Box::new(Sha512Trunc256::new());
test_hash(&mut *sh, &tests[..]);
}
#[test]
fn test_sha512_224() {
let wikipedia_tests = vec![
Test {
input: "",
output_str: "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4"
},
Test {
input: "The quick brown fox jumps over the lazy dog",
output_str: "944cd2847fb54558d4775db0485a50003111c8e5daa63fe722c6aa37"
},
Test {
input: "The quick brown fox jumps over the lazy dog.",
output_str: "6d6a9279495ec4061769752e7ff9c68b6b0b3c5a281b7917ce0572de"
},
];
let tests = wikipedia_tests;
let mut sh = Box::new(Sha512Trunc224::new());
test_hash(&mut *sh, &tests[..]);
}
#[test]
fn test_sha256() {
let wikipedia_tests = vec![
Test {
input: "",
output_str: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
Test {
input: "The quick brown fox jumps over the lazy dog",
output_str: "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"
},
Test {
input: "The quick brown fox jumps over the lazy dog.",
output_str: "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"
},
];
let tests = wikipedia_tests;
let mut sh = Box::new(Sha256::new());
test_hash(&mut *sh, &tests[..]);
}
#[test]
fn test_sha224() {
let wikipedia_tests = vec![
Test {
input: "",
output_str: "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"
},
Test {
input: "The quick brown fox jumps over the lazy dog",
output_str: "730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525"
},
Test {
input: "The quick brown fox jumps over the lazy dog.",
output_str: "619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4c"
},
];
let tests = wikipedia_tests;
let mut sh = Box::new(Sha224::new());
test_hash(&mut *sh, &tests[..]);
}
#[test]
fn test_1million_random_sha512() {
let mut sh = Sha512::new();
test_digest_1million_random(
&mut sh,
128,
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
}
#[test]
fn test_1million_random_sha256() {
let mut sh = Sha256::new();
test_digest_1million_random(
&mut sh,
64,
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
}
}
#[cfg(all(test, feature = "with-bench"))]
mod bench {
use test::Bencher;
use digest::Digest;
use sha2::{STATE_LEN, BLOCK_LEN};
use sha2::{Sha256, Sha512, sha256_digest_block_u32, sha512_digest_block_u64};
#[bench]
pub fn sha256_block(bh: & mut Bencher) {
let mut state = [0u32; STATE_LEN];
let words = [1u32; BLOCK_LEN];
bh.iter( || {
sha256_digest_block_u32(&mut state, &words);
});
bh.bytes = 64u64;
}
#[bench]
pub fn sha512_block(bh: & mut Bencher) {
let mut state = [0u64; STATE_LEN];
let words = [1u64; BLOCK_LEN];
bh.iter( || {
sha512_digest_block_u64(&mut state, &words);
});
bh.bytes = 128u64;
}
#[bench]
pub fn sha256_10(bh: & mut Bencher) {
let mut sh = Sha256::new();
let bytes = [1u8; 10];
bh.iter( || {
sh.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
#[bench]
pub fn sha256_1k(bh: & mut Bencher) {
let mut sh = Sha256::new();
let bytes = [1u8; 1024];
bh.iter( || {
sh.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
#[bench]
pub fn sha256_64k(bh: & mut Bencher) {
let mut sh = Sha256::new();
let bytes = [1u8; 65536];
bh.iter( || {
sh.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
#[bench]
pub fn sha512_10(bh: & mut Bencher) {
let mut sh = Sha512::new();
let bytes = [1u8; 10];
bh.iter( || {
sh.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
#[bench]
pub fn sha512_1k(bh: & mut Bencher) {
let mut sh = Sha512::new();
let bytes = [1u8; 1024];
bh.iter( || {
sh.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
#[bench]
pub fn sha512_64k(bh: & mut Bencher) {
let mut sh = Sha512::new();
let bytes = [1u8; 65536];
bh.iter( || {
sh.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
}