Skip to content

Commit

Permalink
Using u128 for SHA224. (#13)
Browse files Browse the repository at this point in the history
* Buffer256

* experiment

* broken

* next step

* K is correct

* correct

* still works

* still works

* init

* still works

* still

* works again

* remove K

* Works :-)

* minor

* using u128.
  • Loading branch information
sergey-shandar authored Oct 5, 2023
1 parent fe9fa10 commit ae37cb6
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 160 deletions.
5 changes: 5 additions & 0 deletions blockset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ mod bit_vec;
mod digest224;
mod io;
mod sha224;
mod overflow32;
mod sigma32;
mod u32x4;
mod u32x8;
mod u32x16;

#[cfg(test)]
mod static_assert;
Expand Down
19 changes: 19 additions & 0 deletions blockset/src/overflow32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#[inline(always)]
pub const fn add(a: u32, b: u32) -> u32 {
a.overflowing_add(b).0
}

#[inline(always)]
pub const fn add2(a: u32, b: u32, c: u32) -> u32 {
add(add(a, b), c)
}

#[inline(always)]
pub const fn add3(a: u32, b: u32, c: u32, d: u32) -> u32 {
add(add(a, b), add(c, d))
}

#[inline(always)]
pub const fn add4(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 {
add2(add2(a, b, c), d, e)
}
259 changes: 99 additions & 160 deletions blockset/src/sha224.rs
Original file line number Diff line number Diff line change
@@ -1,203 +1,142 @@
use crate::digest224::Digest224;

struct BigSigma(u32, u32, u32);

impl BigSigma {
#[inline(always)]
const fn get(&self, v: u32) -> u32 {
v.rotate_right(self.0) ^ v.rotate_right(self.1) ^ v.rotate_right(self.2)
}
use crate::{
overflow32::{add, add3, add4},
sigma32::{BIG0, BIG1, SMALL0, SMALL1}, u32x4::{to_u32x4, to_u128, get_u32}, u32x8::{u32x8_add, U256}, u32x16::U512,
};

const fn round([s0, s1]: U256, i: usize, w: u128, k: u128) -> U256 {
let (a, e) = {
let t1 = {
let [e, f, g, h] = to_u32x4(s1);
add4(
h,
BIG1.get(e),
(e & f) ^ (!e & g),
get_u32(k, i),
get_u32(w, i),
)
};
let [a, b, c, d] = to_u32x4(s0);
let t2 = add(BIG0.get(a), (a & b) ^ (a & c) ^ (b & c));
(add(t1, t2), add(d, t1))
};
[a as u128 | (s0 << 32), e as u128 | (s1 << 32)]
}

struct SmallSigma(u32, u32, u8);

impl SmallSigma {
#[inline(always)]
const fn get(&self, v: u32) -> u32 {
v.rotate_right(self.0) ^ v.rotate_right(self.1) ^ (v >> self.2)
}
}

#[inline(always)]
const fn add(a: u32, b: u32) -> u32 {
a.overflowing_add(b).0
}

#[inline(always)]
const fn add2(a: u32, b: u32, c: u32) -> u32 {
add(add(a, b), c)
}

#[inline(always)]
const fn add3(a: u32, b: u32, c: u32, d: u32) -> u32 {
add(add(a, b), add(c, d))
}

#[inline(always)]
const fn add4(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 {
add2(add2(a, b, c), d, e)
}

type Digest256 = [u32; 8];

const BIG_S0: BigSigma = BigSigma(2, 13, 22);
const BIG_S1: BigSigma = BigSigma(6, 11, 25);
const SMALL_S0: SmallSigma = SmallSigma(7, 18, 3);
const SMALL_S1: SmallSigma = SmallSigma(17, 19, 10);

type Buffer = [u32; 16];

const fn round([a, b, c, d, e, f, g, h]: Digest256, i: usize, w: &Buffer, k: &Buffer) -> Digest256 {
let t1 = add4(h, BIG_S1.get(e), (e & f) ^ (!e & g), k[i], w[i]);
let t2 = add(BIG_S0.get(a), (a & b) ^ (a & c) ^ (b & c));
[add(t1, t2), a, b, c, add(d, t1), e, f, g]
const fn round4(mut x: U256, i: usize, w: &U512, k: &U512) -> U256 {
let w = w[i];
let k = k[i];
x = round(x, 0, w, k);
x = round(x, 1, w, k);
x = round(x, 2, w, k);
round(x, 3, w, k)
}

const K: [Buffer; 4] = [
pub const K: [U512; 4] = [
[
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, //
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, //
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, //
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, //
0xe9b5dba5_b5c0fbcf_71374491_428a2f98,
0xab1c5ed5_923f82a4_59f111f1_3956c25b,
0x550c7dc3_243185be_12835b01_d807aa98,
0xc19bf174_9bdc06a7_80deb1fe_72be5d74,
],
[
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, //
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, //
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, //
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, //
0x240ca1cc_0fc19dc6_efbe4786_e49b69c1,
0x76f988da_5cb0a9dc_4a7484aa_2de92c6f,
0xbf597fc7_b00327c8_a831c66d_983e5152,
0x14292967_06ca6351_d5a79147_c6e00bf3,
],
[
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, //
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, //
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, //
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, //
0x53380d13_4d2c6dfc_2e1b2138_27b70a85,
0x92722c85_81c2c92e_766a0abb_650a7354,
0xc76c51a3_c24b8b70_a81a664b_a2bfe8a1,
0x106aa070_f40e3585_d6990624_d192e819,
],
[
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, //
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, //
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, //
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, //
0x34b0bcb5_2748774c_1e376c08_19a4c116,
0x682e6ff3_5b9cca4f_4ed8aa4a_391c0cb3,
0x8cc70208_84c87814_78a5636f_748f82ee,
0xc67178f2_bef9a3f7_a4506ceb_90befffa,
],
];

const fn round16(mut x: Digest256, w: &Buffer, j: usize) -> Digest256 {
let k = &K[j];
x = round(x, 0, w, k);
x = round(x, 1, w, k);
x = round(x, 2, w, k);
x = round(x, 3, w, k);
x = round(x, 4, w, k);
x = round(x, 5, w, k);
x = round(x, 6, w, k);
x = round(x, 7, w, k);
x = round(x, 8, w, k);
x = round(x, 9, w, k);
x = round(x, 10, w, k);
x = round(x, 11, w, k);
x = round(x, 12, w, k);
x = round(x, 13, w, k);
x = round(x, 14, w, k);
round(x, 15, w, k)
const fn round16(mut x: U256, w: &U512, i: usize) -> U256 {
let k = &K[i];
x = round4(x, 0, w, k);
x = round4(x, 1, w, k);
x = round4(x, 2, w, k);
round4(x, 3, w, k)
}

#[inline(always)]
const fn w_get(w: &Buffer, i: usize) -> u32 {
w[i & 0xF]
const fn w_round(w0: u32, w1: u32, w9: u32, we: u32) -> u32 {
add3(SMALL1.get(we), w9, SMALL0.get(w1), w0)
}

#[inline(always)]
const fn wi(w: &Buffer, i: usize) -> u32 {
add3(
SMALL_S1.get(w_get(w, i + 0xE)),
w_get(w, i + 9),
SMALL_S0.get(w_get(w, i + 1)),
w[i],
)
const fn wi(w: &U512, i: usize) -> u128 {
w[i & 3]
}

// 0123|4567|89AB|CDEF
// 0123|0123|0123|0123
// 0:WR | | R | R
// 1: WR | | R | R
// 2:R WR| | R|
// 3: R W|R | |R
const fn w_round4(w: &U512, i: usize) -> u128 {
let w10 = wi(w, i + 1) as u32;
let [_, w21, w22, w23] = to_u32x4(wi(w, i + 2));
let [w30, _, w32, w33] = to_u32x4(wi(w, i + 3));
let mut w0 = to_u32x4(w[i]);
w0[0] = w_round(w0[0], w0[1], w21, w32);
w0[1] = w_round(w0[1], w0[2], w22, w33);
w0[2] = w_round(w0[2], w0[3], w23, w0[0]);
w0[3] = w_round(w0[3], w10, w30, w0[1]);
to_u128(w0)
}

const fn next_w(mut w: Buffer) -> Buffer {
w[0x0] = wi(&w, 0x0);
w[0x1] = wi(&w, 0x1);
w[0x2] = wi(&w, 0x2);
w[0x3] = wi(&w, 0x3);
w[0x4] = wi(&w, 0x4);
w[0x5] = wi(&w, 0x5);
w[0x6] = wi(&w, 0x6);
w[0x7] = wi(&w, 0x7);
w[0x8] = wi(&w, 0x8);
w[0x9] = wi(&w, 0x9);
w[0xA] = wi(&w, 0xA);
w[0xB] = wi(&w, 0xB);
w[0xC] = wi(&w, 0xC);
w[0xD] = wi(&w, 0xD);
w[0xE] = wi(&w, 0xE);
w[0xF] = wi(&w, 0xF);
const fn w_round16(mut w: U512) -> U512 {
w[0] = w_round4(&w, 0);
w[1] = w_round4(&w, 1);
w[2] = w_round4(&w, 2);
w[3] = w_round4(&w, 3);
w
}

const SHA224_INIT: Digest256 = [
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
pub const INIT: U256 = [
0xf70e5939_3070dd17_367cd507_c1059ed8,
0xbefa4fa4_64f98fa7_68581511_ffc00b31,
];

pub const fn compress(mut w: Buffer) -> Digest224 {
let mut x: Digest256 = SHA224_INIT;
pub const fn compress(mut w: U512) -> U256 {
let mut x: U256 = INIT;
x = round16(x, &w, 0);
w = next_w(w);
w = w_round16(w);
x = round16(x, &w, 1);
w = next_w(w);
w = w_round16(w);
x = round16(x, &w, 2);
w = next_w(w);
w = w_round16(w);
x = round16(x, &w, 3);
[
add(x[0], SHA224_INIT[0]),
add(x[1], SHA224_INIT[1]),
add(x[2], SHA224_INIT[2]),
add(x[3], SHA224_INIT[3]),
add(x[4], SHA224_INIT[4]),
add(x[5], SHA224_INIT[5]),
add(x[6], SHA224_INIT[6]),
]
x = u32x8_add(&x, &INIT);
x[1] |= 0xFFFF_FFFF << 96;
x
}

#[cfg(test)]
mod tests {
use crate::static_assert::static_assert;
mod test {
use super::{compress, U256};

use super::{compress, Digest224};

pub const fn eq(
[a0, a1, a2, a3, a4, a5, a6]: Digest224,
[b0, b1, b2, b3, b4, b5, b6]: Digest224,
) -> bool {
a0 == b0 && a1 == b1 && a2 == b2 && a3 == b3 && a4 == b4 && a5 == b5 && a6 == b6
}

const A: Digest224 = compress([0x8000_0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

const _: () = static_assert(eq(
compress([0x8000_0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
[
0xd14a028c, 0x2a3a2bc9, 0x476102bb, 0x288234c4, 0x15a2b01f, 0x828ea62a, 0xc5b3e42f,
],
));
const A: U256 = compress([0x8000_0000, 0, 0, 0]);

#[test]
fn test() {
assert!(eq(
A,
[0xd14a028c, 0x2a3a2bc9, 0x476102bb, 0x288234c4, 0x15a2b01f, 0x828ea62a, 0xc5b3e42f]
));
assert_eq!(
A,
[0xd14a028c, 0x2a3a2bc9, 0x476102bb, 0x288234c4, 0x15a2b01f, 0x828ea62a, 0xc5b3e42f]
);
}
println!("{:x?}", A);

#[test]
fn runtime_test() {
assert_eq!(
compress([0x8000_0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
[0xd14a028c, 0x2a3a2bc9, 0x476102bb, 0x288234c4, 0x15a2b01f, 0x828ea62a, 0xc5b3e42f]
A,
[
0x288234c4_476102bb_2a3a2bc9_d14a028c,
0xFFFFFFFF_c5b3e42f_828ea62a_15a2b01f
]
);
}
}
22 changes: 22 additions & 0 deletions blockset/src/sigma32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pub struct Big(u32, u32, u32);

impl Big {
#[inline(always)]
pub const fn get(&self, v: u32) -> u32 {
v.rotate_right(self.0) ^ v.rotate_right(self.1) ^ v.rotate_right(self.2)
}
}

pub struct Small(u32, u32, u8);

impl Small {
#[inline(always)]
pub const fn get(&self, v: u32) -> u32 {
v.rotate_right(self.0) ^ v.rotate_right(self.1) ^ (v >> self.2)
}
}

pub const BIG0: Big = Big(2, 13, 22);
pub const BIG1: Big = Big(6, 11, 25);
pub const SMALL0: Small = Small(7, 18, 3);
pub const SMALL1: Small = Small(17, 19, 10);
37 changes: 37 additions & 0 deletions blockset/src/u32x16.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::u32x4::to_u128;

pub type U512 = [u128; 4];

#[inline(always)]
pub const fn to_u32x16(&[a, b, c, d]: &U512) -> [u32; 16] {
[
a as u32,
(a >> 32) as u32,
(a >> 64) as u32,
(a >> 96) as u32,
b as u32,
(b >> 32) as u32,
(b >> 64) as u32,
(b >> 96) as u32,
c as u32,
(c >> 32) as u32,
(c >> 64) as u32,
(c >> 96) as u32,
d as u32,
(d >> 32) as u32,
(d >> 64) as u32,
(d >> 96) as u32,
]
}

#[inline(always)]
pub const fn to_u512(
&[w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, wa, wb, wc, wd, we, wf]: &[u32; 16],
) -> U512 {
[
to_u128([w0, w1, w2, w3]),
to_u128([w4, w5, w6, w7]),
to_u128([w8, w9, wa, wb]),
to_u128([wc, wd, we, wf]),
]
}
Loading

0 comments on commit ae37cb6

Please sign in to comment.