Created
April 6, 2023 08:15
-
-
Save shadeglare/fcb52d905e6f5da6e9b3f7fbb1465e19 to your computer and use it in GitHub Desktop.
Unrolled sha256 implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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