Skip to content

Instantly share code, notes, and snippets.

@shadeglare
Created April 6, 2023 08:15
Show Gist options
  • Save shadeglare/fcb52d905e6f5da6e9b3f7fbb1465e19 to your computer and use it in GitHub Desktop.
Save shadeglare/fcb52d905e6f5da6e9b3f7fbb1465e19 to your computer and use it in GitHub Desktop.
Unrolled sha256 implementation
pub fn sha256(data: &[u8]) -> [u8; 32] {
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
macro_rules! ch {
($x:expr, $y:expr, $z:expr) => {
($x & $y) ^ ((!$x) & $z)
};
}
macro_rules! maj {
($x:expr, $y:expr, $z:expr) => {
($x & $y) ^ ($x & $z) ^ ($y & $z)
};
}
macro_rules! Sigma0 {
($x:expr) => {
$x.rotate_right(2u32) ^ $x.rotate_right(13u32) ^ $x.rotate_right(22u32)
};
}
macro_rules! Sigma1 {
($x:expr) => {
$x.rotate_right(6u32) ^ $x.rotate_right(11u32) ^ $x.rotate_right(25u32)
};
}
macro_rules! sigma0 {
($x:expr) => {
$x.rotate_right(7u32) ^ $x.rotate_right(18u32) ^ ($x >> 3u32)
};
}
macro_rules! sigma1 {
($x:expr) => {
$x.rotate_right(17u32) ^ $x.rotate_right(19u32) ^ ($x >> 10u32)
};
}
macro_rules! process_block {
($W:ident, $H:ident) => {
if cfg!(target_endian = "little") {
$W[0] = u32::from_be($W[0]);
$W[1] = u32::from_be($W[1]);
$W[2] = u32::from_be($W[2]);
$W[3] = u32::from_be($W[3]);
$W[4] = u32::from_be($W[4]);
$W[5] = u32::from_be($W[5]);
$W[6] = u32::from_be($W[6]);
$W[7] = u32::from_be($W[7]);
$W[8] = u32::from_be($W[8]);
$W[9] = u32::from_be($W[9]);
$W[10] = u32::from_be($W[10]);
$W[11] = u32::from_be($W[11]);
$W[12] = u32::from_be($W[12]);
$W[13] = u32::from_be($W[13]);
$W[14] = u32::from_be($W[14]);
$W[15] = u32::from_be($W[15]);
}
macro_rules! schedule_w {
($t:expr) => {
$W[$t] = sigma1!($W[$t - 2])
.wrapping_add($W[$t - 7])
.wrapping_add(sigma0!($W[$t - 15]))
.wrapping_add($W[$t - 16]);
};
}
schedule_w!(16);
schedule_w!(17);
schedule_w!(18);
schedule_w!(19);
schedule_w!(20);
schedule_w!(21);
schedule_w!(22);
schedule_w!(23);
schedule_w!(24);
schedule_w!(25);
schedule_w!(26);
schedule_w!(27);
schedule_w!(28);
schedule_w!(29);
schedule_w!(30);
schedule_w!(31);
schedule_w!(32);
schedule_w!(33);
schedule_w!(34);
schedule_w!(35);
schedule_w!(36);
schedule_w!(37);
schedule_w!(38);
schedule_w!(39);
schedule_w!(40);
schedule_w!(41);
schedule_w!(42);
schedule_w!(43);
schedule_w!(44);
schedule_w!(45);
schedule_w!(46);
schedule_w!(47);
schedule_w!(48);
schedule_w!(49);
schedule_w!(50);
schedule_w!(51);
schedule_w!(52);
schedule_w!(53);
schedule_w!(54);
schedule_w!(55);
schedule_w!(56);
schedule_w!(57);
schedule_w!(58);
schedule_w!(59);
schedule_w!(60);
schedule_w!(61);
schedule_w!(62);
schedule_w!(63);
let mut a = $H[0];
let mut b = $H[1];
let mut c = $H[2];
let mut d = $H[3];
let mut e = $H[4];
let mut f = $H[5];
let mut g = $H[6];
let mut h = $H[7];
macro_rules! step {
($t:expr) => {
let T1 = h
.wrapping_add(Sigma1!(e))
.wrapping_add(ch!(e, f, g))
.wrapping_add(K[$t])
.wrapping_add($W[$t]);
let T2 = Sigma0!(a).wrapping_add(maj!(a, b, c));
h = g;
g = f;
f = e;
e = d.wrapping_add(T1);
d = c;
c = b;
b = a;
a = T1.wrapping_add(T2);
};
}
step!(0);
step!(1);
step!(2);
step!(3);
step!(4);
step!(5);
step!(6);
step!(7);
step!(8);
step!(9);
step!(10);
step!(11);
step!(12);
step!(13);
step!(14);
step!(15);
step!(16);
step!(17);
step!(18);
step!(19);
step!(20);
step!(21);
step!(22);
step!(23);
step!(24);
step!(25);
step!(26);
step!(27);
step!(28);
step!(29);
step!(30);
step!(31);
step!(32);
step!(33);
step!(34);
step!(35);
step!(36);
step!(37);
step!(38);
step!(39);
step!(40);
step!(41);
step!(42);
step!(43);
step!(44);
step!(45);
step!(46);
step!(47);
step!(48);
step!(49);
step!(50);
step!(51);
step!(52);
step!(53);
step!(54);
step!(55);
step!(56);
step!(57);
step!(58);
step!(59);
step!(60);
step!(61);
step!(62);
step!(63);
$H[0] = a.wrapping_add($H[0]);
$H[1] = b.wrapping_add($H[1]);
$H[2] = c.wrapping_add($H[2]);
$H[3] = d.wrapping_add($H[3]);
$H[4] = e.wrapping_add($H[4]);
$H[5] = f.wrapping_add($H[5]);
$H[6] = g.wrapping_add($H[6]);
$H[7] = h.wrapping_add($H[7]);
};
}
unsafe {
const ONE_SIZE: usize = 1;
const LEN_SIZE: usize = 8;
const BLOCK_SIZE: usize = 64;
const LEN_OFFSET: isize = (BLOCK_SIZE - LEN_SIZE) as isize;
#[rustfmt::skip]
const K: [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
];
#[rustfmt::skip]
let mut H: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];
#[allow(invalid_value)]
let mut W = std::mem::MaybeUninit::<[u32; 64]>::uninit().assume_init();
let PW = W.as_mut_ptr() as *mut u8;
let mut PD = data.as_ptr();
let mut bytes_left = data.len();
let mut one_written = false;
loop {
let bytes_to_read = usize::min(BLOCK_SIZE, bytes_left);
let can_write_one = !one_written && (bytes_to_read + ONE_SIZE <= BLOCK_SIZE);
let zero_offset = if one_written {
bytes_to_read
} else {
bytes_to_read + ONE_SIZE
} as isize;
let can_write_len = zero_offset <= LEN_OFFSET;
let zero_count = if can_write_len {
LEN_OFFSET - zero_offset
} else {
BLOCK_SIZE as isize - zero_offset
};
std::ptr::copy(PD, PW, bytes_to_read);
PD = PD.offset(bytes_to_read as isize);
if can_write_one {
std::ptr::write_bytes(PW.offset(bytes_to_read as isize), 0x80, ONE_SIZE);
one_written = true;
}
if zero_count > 0 {
std::ptr::write_bytes(PW.offset(zero_offset as isize), 0x00, zero_count as usize);
}
if can_write_len {
let bytes = (data.len() * 8).to_be_bytes().as_ptr();
std::ptr::copy(bytes, PW.offset(zero_offset + zero_count), LEN_SIZE);
process_block!(W, H);
break;
} else {
process_block!(W, H);
bytes_left -= bytes_to_read;
}
}
if cfg!(target_endian = "little") {
H[0] = u32::from_be(H[0]);
H[1] = u32::from_be(H[1]);
H[2] = u32::from_be(H[2]);
H[3] = u32::from_be(H[3]);
H[4] = u32::from_be(H[4]);
H[5] = u32::from_be(H[5]);
H[6] = u32::from_be(H[6]);
H[7] = u32::from_be(H[7]);
}
std::mem::transmute(H)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment