use futures::io::{AsyncRead, AsyncReadExt};
const K: [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,
];
const H: [u64; 8] = [
0x6a09e667f3bcc908,
0xbb67ae8584caa73b,
0x3c6ef372fe94f82b,
0xa54ff53a5f1d36f1,
0x510e527fade682d1,
0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b,
0x5be0cd19137e2179,
];
const ZERO_BUFFER: [u8; 128] = [0; 128];
pub fn encode_core(bytes: &[u8], mut h: [u64; 8]) -> [u64; 8] {
let bytes = get_normalized_message_bytes(bytes);
for chunk_num in 0..(bytes.len() >> 7) {
let chunk_start_index = chunk_num << 7;
let chunk: &[u8] = &bytes[chunk_start_index..chunk_start_index + 128];
let result = process_chunk(chunk, &h);
for i in 0..8 {
h[i] = h[i].wrapping_add(result[i]);
}
}
h
}
fn get_normalized_message_bytes(bytes: &[u8]) -> Vec<u8> {
let message_length: usize = bytes.len();
let message_bit_length: usize = message_length << 3;
let zeros = vec![0; (128 - (message_length + 17) % 128) % 128];
let mut result: Vec<u8> = Vec::with_capacity(bytes.len() + zeros.len() + 17);
result.extend_from_slice(bytes);
result.push(0x80);
result.extend_from_slice(&zeros);
result.extend_from_slice(&(message_bit_length as u128).to_be_bytes());
result
}
pub fn process_chunk(chunk: &[u8], vars: &[u64]) -> [u64; 8] {
let mut chunk_u64 = [0u64; 16];
for (i, chunk_bytes) in chunk.chunks_exact(8).enumerate() {
let chunk: [u8; 8] = chunk_bytes.try_into().unwrap();
chunk_u64[i] = u64::from_be_bytes(chunk);
}
let mut a: u64 = vars[0];
let mut b: u64 = vars[1];
let mut c: u64 = vars[2];
let mut d: u64 = vars[3];
let mut e: u64 = vars[4];
let mut f: u64 = vars[5];
let mut g: u64 = vars[6];
let mut h: u64 = vars[7];
let mut w: [u64; 80] = [0; 80];
w[0..16].copy_from_slice(&chunk_u64);
for num in 16..80 {
let s0 = w[num - 15];
let s1 = w[num - 2];
let sigma0 = s0.rotate_right(1) ^ s0.rotate_right(8) ^ (s0 >> 7);
let sigma1 = s1.rotate_right(19) ^ s1.rotate_right(61) ^ (s1 >> 6);
w[num] = w[num - 16]
.wrapping_add(sigma0)
.wrapping_add(w[num - 7])
.wrapping_add(sigma1);
}
for num in 0..80 {
let ch = g ^ (e & (f ^ g));
let sigma1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
let temp1 = h.wrapping_add(sigma1).wrapping_add(ch).wrapping_add(K[num]).wrapping_add(w[num]);
let maj = (a & b) ^ (c & (a ^ b));
let sigma0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
let temp2 = sigma0.wrapping_add(maj);
h = g;
g = f;
f = e;
e = d.wrapping_add(temp1);
d = c;
c = b;
b = a;
a = temp1.wrapping_add(temp2);
}
[a, b, c, d, e, f, g, h]
}
pub fn encode(bytes: &[u8]) -> [u8; 64] {
let h = encode_core(bytes, H);
let mut hh = [0u8; 64];
for i in 0..8 {
let start_index = i << 3;
hh[start_index..start_index + 8].copy_from_slice(&h[i].to_be_bytes());
}
hh
}
pub async fn encode_async<R>(mut reader: R) -> Result<[u8; 64], std::io::Error>
where
R: AsyncRead + Unpin,
{
let mut h = H;
let mut buffer = [0u8; 128];
let mut buffer_len = 0;
let mut total_length = 0;
loop {
let bytes_read = reader.read(&mut buffer[buffer_len..]).await?;
if bytes_read == 0 {
break;
}
buffer_len += bytes_read;
total_length += bytes_read;
if buffer_len == 128 {
let result = process_chunk(&buffer[..buffer_len], &h);
for i in 0..8 {
h[i] = h[i].wrapping_add(result[i]);
}
buffer_len = 0;
}
}
let final_chunk2 =
get_final_chunks_sha2(&mut buffer, total_length, buffer_len);
let result = process_chunk(&buffer, &h);
for i in 0..8 {
h[i] = h[i].wrapping_add(result[i]);
}
if let Some(chunk2) = final_chunk2 {
let result = process_chunk(&chunk2, &h);
for i in 0..8 {
h[i] = h[i].wrapping_add(result[i]);
}
}
let mut hh = [0u8; 64];
for i in 0..8 {
let start_index = i << 3;
hh[start_index..start_index + 8].copy_from_slice(&h[i].to_be_bytes());
}
Ok(hh)
}
pub(crate) fn get_final_chunks_sha2(chunk1: &mut [u8; 128], total_len: usize, partial_data_len: usize) -> Option<[u8; 128]> {
let total_len= total_len << 3;
let mut full_padded_length = total_len + 1 + 128;
full_padded_length += 1024 - (full_padded_length % 1024);
chunk1[partial_data_len] = 0x80;
chunk1[partial_data_len + 1..].copy_from_slice(&ZERO_BUFFER[..128 - partial_data_len - 1]);
let two_chunks = full_padded_length - total_len > 1024;
if two_chunks {
let mut chunk2 = [0u8; 128];
chunk2[112..].copy_from_slice(&(total_len as u128).to_be_bytes());
Some(chunk2)
} else {
chunk1[112..].copy_from_slice(&(total_len as u128).to_be_bytes());
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use futures::io::Cursor;
#[tokio::test]
async fn test_encode_empty_string() {
let result = encode_async(Cursor::new("".as_bytes())).await.unwrap();
assert_eq!(
result,
[
0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d,
0x80, 0x07, 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21,
0xd3, 0x6c, 0xe9, 0xce, 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83,
0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e
]
);
}
#[tokio::test]
async fn test_encode_abc() {
let result = encode_async(Cursor::new("abc".as_bytes())).await.unwrap();
assert_eq!(
result,
[
0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20,
0x41, 0x31, 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, 0x0A, 0x9E, 0xEE, 0xE6,
0x4B, 0x55, 0xD3, 0x9A, 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, 0x36, 0xBA,
0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F
]
);
}
#[tokio::test]
async fn test_encode_message_digest() {
let result = encode_async(Cursor::new("message digest".as_bytes())).await.unwrap();
assert_eq!(
result,
[
0x10, 0x7d, 0xbf, 0x38, 0x9d, 0x9e, 0x9f, 0x71, 0xa3, 0xa9, 0x5f, 0x6c, 0x05, 0x5b,
0x92, 0x51, 0xbc, 0x52, 0x68, 0xc2, 0xbe, 0x16, 0xd6, 0xc1, 0x34, 0x92, 0xea, 0x45,
0xb0, 0x19, 0x9f, 0x33, 0x09, 0xe1, 0x64, 0x55, 0xab, 0x1e, 0x96, 0x11, 0x8e, 0x8a,
0x90, 0x5d, 0x55, 0x97, 0xb7, 0x20, 0x38, 0xdd, 0xb3, 0x72, 0xa8, 0x98, 0x26, 0x04,
0x6d, 0xe6, 0x66, 0x87, 0xbb, 0x42, 0x0e, 0x7c
]
);
}
#[tokio::test]
async fn test_encode_abcdefghijklmnopqrstuvwxyz() {
let result = encode_async(Cursor::new("abcdefghijklmnopqrstuvwxyz".as_bytes())).await.unwrap();
assert_eq!(
result,
[
0x4d, 0xbf, 0xf8, 0x6c, 0xc2, 0xca, 0x1b, 0xae, 0x1e, 0x16, 0x46, 0x8a, 0x05, 0xcb,
0x98, 0x81, 0xc9, 0x7f, 0x17, 0x53, 0xbc, 0xe3, 0x61, 0x90, 0x34, 0x89, 0x8f, 0xaa,
0x1a, 0xab, 0xe4, 0x29, 0x95, 0x5a, 0x1b, 0xf8, 0xec, 0x48, 0x3d, 0x74, 0x21, 0xfe,
0x3c, 0x16, 0x46, 0x61, 0x3a, 0x59, 0xed, 0x54, 0x41, 0xfb, 0x0f, 0x32, 0x13, 0x89,
0xf7, 0x7f, 0x48, 0xa8, 0x79, 0xc7, 0xb1, 0xf1
]
);
}
#[tokio::test]
async fn test_encode_alphanumeric_string() {
let result = encode_async(Cursor::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".as_bytes())).await.unwrap();
assert_eq!(
result,
[
0x1e, 0x07, 0xbe, 0x23, 0xc2, 0x6a, 0x86, 0xea, 0x37, 0xea, 0x81, 0x0c, 0x8e, 0xc7,
0x80, 0x93, 0x52, 0x51, 0x5a, 0x97, 0x0e, 0x92, 0x53, 0xc2, 0x6f, 0x53, 0x6c, 0xfc,
0x7a, 0x99, 0x96, 0xc4, 0x5c, 0x83, 0x70, 0x58, 0x3e, 0x0a, 0x78, 0xfa, 0x4a, 0x90,
0x04, 0x1d, 0x71, 0xa4, 0xce, 0xab, 0x74, 0x23, 0xf1, 0x9c, 0x71, 0xb9, 0xd5, 0xa3,
0xe0, 0x12, 0x49, 0xf0, 0xbe, 0xbd, 0x58, 0x94
]
);
}
#[tokio::test]
async fn test_encode_long_string() {
let result = encode_async(Cursor::new("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".as_bytes())).await.unwrap();
assert_eq!(
result,
[
0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC,
0x14, 0x3F, 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, 0x72, 0x99, 0xAE, 0xAD,
0xB6, 0x88, 0x90, 0x18, 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, 0x33, 0x1B,
0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09
]
);
}
#[tokio::test]
async fn test_encode_million_a() {
let result = encode_async(Cursor::new(&vec!["a".as_bytes()[0]; 1000000])).await.unwrap();
assert_eq!(
result,
[
0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15,
0xB4, 0x63, 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, 0x56, 0x32, 0xA8, 0x03,
0xAF, 0xA9, 0x73, 0xEB, 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, 0x4C, 0xB0,
0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E,
0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B
]
);
}
#[tokio::test]
async fn test_encode_repeated_pattern() {
let result = encode_async(Cursor::new(
vec!["01234567012345670123456701234567"; 20]
.join("")
.as_bytes(),
)).await.unwrap();
assert_eq!(
result,
[
0x89, 0xD0, 0x5B, 0xA6, 0x32, 0xC6, 0x99, 0xC3, 0x12, 0x31, 0xDE, 0xD4, 0xFF, 0xC1,
0x27, 0xD5, 0xA8, 0x94, 0xDA, 0xD4, 0x12, 0xC0, 0xE0, 0x24, 0xDB, 0x87, 0x2D, 0x1A,
0xBD, 0x2B, 0xA8, 0x14, 0x1A, 0x0F, 0x85, 0x07, 0x2A, 0x9B, 0xE1, 0xE2, 0xAA, 0x04,
0xCF, 0x33, 0xC7, 0x65, 0xCB, 0x51, 0x08, 0x13, 0xA3, 0x9C, 0xD5, 0xA8, 0x4C, 0x4A,
0xCA, 0xA6, 0x4D, 0x3F, 0x3F, 0xB7, 0xBA, 0xE9
]
);
}
#[tokio::test]
async fn test_encode_single_byte_d0() {
let result = encode_async(Cursor::new(&[0xd0])).await.unwrap();
assert_eq!(
result,
[
0x99, 0x92, 0x20, 0x29, 0x38, 0xE8, 0x82, 0xE7, 0x3E, 0x20, 0xF6, 0xB6, 0x9E, 0x68,
0xA0, 0xA7, 0x14, 0x90, 0x90, 0x42, 0x3D, 0x93, 0xC8, 0x1B, 0xAB, 0x3F, 0x21, 0x67,
0x8D, 0x4A, 0xCE, 0xEE, 0xE5, 0x0E, 0x4E, 0x8C, 0xAF, 0xAD, 0xA4, 0xC8, 0x5A, 0x54,
0xEA, 0x83, 0x06, 0x82, 0x6C, 0x4A, 0xD6, 0xE7, 0x4C, 0xEC, 0xE9, 0x63, 0x1B, 0xFA,
0x8A, 0x54, 0x9B, 0x4A, 0xB3, 0xFB, 0xBA, 0x15
]
);
}
#[tokio::test]
async fn test_encode_16_byte_array() {
let result = encode_async(Cursor::new(&[
0x8d, 0x4e, 0x3c, 0x0e, 0x38, 0x89, 0x19, 0x14, 0x91, 0x81, 0x6e, 0x9d, 0x98, 0xbf,
0xf0, 0xa0,
])).await.unwrap();
assert_eq!(
result,
[
0xCB, 0x0B, 0x67, 0xA4, 0xB8, 0x71, 0x2C, 0xD7, 0x3C, 0x9A, 0xAB, 0xC0, 0xB1, 0x99,
0xE9, 0x26, 0x9B, 0x20, 0x84, 0x4A, 0xFB, 0x75, 0xAC, 0xBD, 0xD1, 0xC1, 0x53, 0xC9,
0x82, 0x89, 0x24, 0xC3, 0xDD, 0xED, 0xAA, 0xFE, 0x66, 0x9C, 0x5F, 0xDD, 0x0B, 0xC6,
0x6F, 0x63, 0x0F, 0x67, 0x73, 0x98, 0x82, 0x13, 0xEB, 0x1B, 0x16, 0xF5, 0x17, 0xAD,
0x0D, 0xE4, 0xB2, 0xF0, 0xC9, 0x5C, 0x90, 0xF8
]
);
}
#[tokio::test]
async fn test_encode_large_byte_array() {
let result = encode_async(Cursor::new(&[
0xa5, 0x5f, 0x20, 0xc4, 0x11, 0xaa, 0xd1, 0x32, 0x80, 0x7a, 0x50, 0x2d, 0x65, 0x82,
0x4e, 0x31, 0xa2, 0x30, 0x54, 0x32, 0xaa, 0x3d, 0x06, 0xd3, 0xe2, 0x82, 0xa8, 0xd8,
0x4e, 0x0d, 0xe1, 0xde, 0x69, 0x74, 0xbf, 0x49, 0x54, 0x69, 0xfc, 0x7f, 0x33, 0x8f,
0x80, 0x54, 0xd5, 0x8c, 0x26, 0xc4, 0x93, 0x60, 0xc3, 0xe8, 0x7a, 0xf5, 0x65, 0x23,
0xac, 0xf6, 0xd8, 0x9d, 0x03, 0xe5, 0x6f, 0xf2, 0xf8, 0x68, 0x00, 0x2b, 0xc3, 0xe4,
0x31, 0xed, 0xc4, 0x4d, 0xf2, 0xf0, 0x22, 0x3d, 0x4b, 0xb3, 0xb2, 0x43, 0x58, 0x6e,
0x1a, 0x7d, 0x92, 0x49, 0x36, 0x69, 0x4f, 0xcb, 0xba, 0xf8, 0x8d, 0x95, 0x19, 0xe4,
0xeb, 0x50, 0xa6, 0x44, 0xf8, 0xe4, 0xf9, 0x5e, 0xb0, 0xea, 0x95, 0xbc, 0x44, 0x65,
0xc8, 0x82, 0x1a, 0xac, 0xd2, 0xfe, 0x15, 0xab, 0x49, 0x81, 0x16, 0x4b, 0xbb, 0x6d,
0xc3, 0x2f, 0x96, 0x90, 0x87, 0xa1, 0x45, 0xb0, 0xd9, 0xcc, 0x9c, 0x67, 0xc2, 0x2b,
0x76, 0x32, 0x99, 0x41, 0x9c, 0xc4, 0x12, 0x8b, 0xe9, 0xa0, 0x77, 0xb3, 0xac, 0xe6,
0x34, 0x06, 0x4e, 0x6d, 0x99, 0x28, 0x35, 0x13, 0xdc, 0x06, 0xe7, 0x51, 0x5d, 0x0d,
0x73, 0x13, 0x2e, 0x9a, 0x0d, 0xc6, 0xd3, 0xb1, 0xf8, 0xb2, 0x46, 0xf1, 0xa9, 0x8a,
0x3f, 0xc7, 0x29, 0x41, 0xb1, 0xe3, 0xbb, 0x20, 0x98, 0xe8, 0xbf, 0x16, 0xf2, 0x68,
0xd6, 0x4f, 0x0b, 0x0f, 0x47, 0x07, 0xfe, 0x1e, 0xa1, 0xa1, 0x79, 0x1b, 0xa2, 0xf3,
0xc0, 0xc7, 0x58, 0xe5, 0xf5, 0x51, 0x86, 0x3a, 0x96, 0xc9, 0x49, 0xad, 0x47, 0xd7,
0xfb, 0x40, 0xd2,
])).await.unwrap();
assert_eq!(
result,
[
0xC6, 0x65, 0xBE, 0xFB, 0x36, 0xDA, 0x18, 0x9D, 0x78, 0x82, 0x2D, 0x10, 0x52, 0x8C,
0xBF, 0x3B, 0x12, 0xB3, 0xEE, 0xF7, 0x26, 0x03, 0x99, 0x09, 0xC1, 0xA1, 0x6A, 0x27,
0x0D, 0x48, 0x71, 0x93, 0x77, 0x96, 0x6B, 0x95, 0x7A, 0x87, 0x8E, 0x72, 0x05, 0x84,
0x77, 0x9A, 0x62, 0x82, 0x5C, 0x18, 0xDA, 0x26, 0x41, 0x5E, 0x49, 0xA7, 0x17, 0x6A,
0x89, 0x4E, 0x75, 0x10, 0xFD, 0x14, 0x51, 0xF5
]
);
}
}