feat(alg): impl sha2
This commit is contained in:
parent
11677d8fe0
commit
bb81a7dd49
6 changed files with 371 additions and 38 deletions
30
Cargo.lock
generated
30
Cargo.lock
generated
|
@ -15,8 +15,10 @@ dependencies = [
|
||||||
name = "algorithms"
|
name = "algorithms"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"assert_hex",
|
||||||
"criterion",
|
"criterion",
|
||||||
"iai",
|
"iai",
|
||||||
|
"pretty_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -28,6 +30,12 @@ dependencies = [
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assert_hex"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7010f1430f0fc8ca80bdb5e5d074db68776a2e268ec6cf80b53712d3ea4bca7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -282,6 +290,12 @@ dependencies = [
|
||||||
"defmt 1.0.1",
|
"defmt 1.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
|
@ -517,6 +531,16 @@ dependencies = [
|
||||||
"plotters-backend",
|
"plotters-backend",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error-attr2"
|
name = "proc-macro-error-attr2"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -1002,3 +1026,9 @@ name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
|
|
|
@ -6,8 +6,10 @@ edition = "2024"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
assert_hex = "0.4.1"
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
iai = "0.1.1"
|
iai = "0.1.1"
|
||||||
|
pretty_assertions = "1.4.1"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "crc32bench"
|
name = "crc32bench"
|
||||||
|
@ -16,3 +18,8 @@ harness = false
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "crc32bench_iai"
|
name = "crc32bench_iai"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
std = []
|
||||||
|
show_internals = ["std"]
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
#include <threads.h>
|
#include <threads.h>
|
||||||
|
|
||||||
#ifdef TEST
|
#ifdef TEST
|
||||||
// #define SHOW_INTERNALS
|
#define SHOW_INTERNALS
|
||||||
|
|
||||||
#endif // TEST
|
#endif // TEST
|
||||||
|
|
||||||
#ifdef SHOW_INTERNALS
|
#ifdef SHOW_INTERNALS
|
||||||
|
@ -48,7 +47,8 @@ static uint32_t addTemp = 0;
|
||||||
#define SHA256_ROTL(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
|
#define SHA256_ROTL(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
|
||||||
#define SHA256_ROTR(bits, word) (((word) >> (bits)) | ((word) << (32 - (bits))))
|
#define SHA256_ROTR(bits, word) (((word) >> (bits)) | ((word) << (32 - (bits))))
|
||||||
|
|
||||||
/* Define the SHA SIGMA and sigma macros */
|
/* Define the SHA SIGMA and sigma macros, yes these have the same name and are
|
||||||
|
* different */
|
||||||
#define SHA256_SIGMA0(word) \
|
#define SHA256_SIGMA0(word) \
|
||||||
(SHA256_ROTR(2, word) ^ SHA256_ROTR(13, word) ^ SHA256_ROTR(22, word))
|
(SHA256_ROTR(2, word) ^ SHA256_ROTR(13, word) ^ SHA256_ROTR(22, word))
|
||||||
#define SHA256_SIGMA1(word) \
|
#define SHA256_SIGMA1(word) \
|
||||||
|
@ -168,9 +168,7 @@ static void sha2_256_process_message_block(SHA2Context *context) {
|
||||||
#ifdef SHOW_INTERNALS
|
#ifdef SHOW_INTERNALS
|
||||||
TRACE("DONE:\t")
|
TRACE("DONE:\t")
|
||||||
dump_alphabet;
|
dump_alphabet;
|
||||||
#endif // SHOW_INTERNALS
|
|
||||||
|
|
||||||
#ifdef SHOW_INTERNALS
|
|
||||||
TRACE("Intermediate hash before we add the working variables:\n");
|
TRACE("Intermediate hash before we add the working variables:\n");
|
||||||
for (int o = 0; o < SHA2_256_HashParts; o++) {
|
for (int o = 0; o < SHA2_256_HashParts; o++) {
|
||||||
TRACE("\t%d:\t%032b\n", o, context->intermediate_hash[o]);
|
TRACE("\t%d:\t%032b\n", o, context->intermediate_hash[o]);
|
||||||
|
@ -254,14 +252,7 @@ static void sha2_256_pad_message(SHA2Context *context, uint8_t pad_byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha2_256_finalize(SHA2Context *context, uint8_t pad_byte) {
|
static void sha2_256_finalize(SHA2Context *context, uint8_t pad_byte) {
|
||||||
size_t i;
|
|
||||||
sha2_256_pad_message(context, pad_byte);
|
sha2_256_pad_message(context, pad_byte);
|
||||||
/* message may be sensitive, so clear it out */
|
|
||||||
for (i = 0; i < SHA2_256_BlockSize; ++i)
|
|
||||||
context->message_block[i] = 0;
|
|
||||||
context->length_high = 0; /* and clear length */
|
|
||||||
context->length_low = 0;
|
|
||||||
context->computed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -7,7 +7,7 @@ use super::super::sha2::{DIGEST256_EMPTY, Digest256, SHA2_256_BLOCK_SIZE};
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
pub enum SHA2Result {
|
pub enum SHA2Outcome {
|
||||||
shaSuccess = 0,
|
shaSuccess = 0,
|
||||||
shaNull, /* Null pointer parameter */
|
shaNull, /* Null pointer parameter */
|
||||||
shaInputTooLong, /* input data too long */
|
shaInputTooLong, /* input data too long */
|
||||||
|
@ -50,45 +50,48 @@ impl Default for Sha2_256Context {
|
||||||
mod ffi {
|
mod ffi {
|
||||||
use super::*;
|
use super::*;
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
pub fn sha2_256_oneshot(data: *const u8, len: usize, digest: *mut Digest256) -> SHA2Result;
|
pub fn sha2_256_oneshot(data: *const u8, len: usize, digest: *mut Digest256)
|
||||||
pub fn sha2_256_reset(context: *mut Sha2_256Context) -> SHA2Result;
|
-> SHA2Outcome;
|
||||||
|
pub fn sha2_256_reset(context: *mut Sha2_256Context) -> SHA2Outcome;
|
||||||
pub fn sha2_256_input(
|
pub fn sha2_256_input(
|
||||||
context: *mut Sha2_256Context,
|
context: *mut Sha2_256Context,
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> SHA2Result;
|
) -> SHA2Outcome;
|
||||||
pub fn sha2_256_result(context: *mut Sha2_256Context, digest: *mut Digest256)
|
pub fn sha2_256_result(
|
||||||
-> SHA2Result;
|
context: *mut Sha2_256Context,
|
||||||
|
digest: *mut Digest256,
|
||||||
|
) -> SHA2Outcome;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Result> {
|
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Outcome> {
|
||||||
let mut digest: Digest256 = DIGEST256_EMPTY;
|
let mut digest: Digest256 = DIGEST256_EMPTY;
|
||||||
let res =
|
let res =
|
||||||
unsafe { ffi::sha2_256_oneshot(ref_to_ptr(data), data.len(), ref_to_ptr_mut(&mut digest)) };
|
unsafe { ffi::sha2_256_oneshot(ref_to_ptr(data), data.len(), ref_to_ptr_mut(&mut digest)) };
|
||||||
to_res(digest, res)
|
to_res(digest, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sha2_256_reset(context: &mut Sha2_256Context) -> Result<(), SHA2Result> {
|
pub fn sha2_256_reset(context: &mut Sha2_256Context) -> Result<(), SHA2Outcome> {
|
||||||
let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) };
|
let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) };
|
||||||
to_res((), res)
|
to_res((), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sha2_256_input(context: &mut Sha2_256Context, data: &[u8]) -> Result<(), SHA2Result> {
|
pub fn sha2_256_input(context: &mut Sha2_256Context, data: &[u8]) -> Result<(), SHA2Outcome> {
|
||||||
let res = unsafe { ffi::sha2_256_input(ref_to_ptr_mut(context), ref_to_ptr(data), data.len()) };
|
let res = unsafe { ffi::sha2_256_input(ref_to_ptr_mut(context), ref_to_ptr(data), data.len()) };
|
||||||
to_res((), res)
|
to_res((), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sha2_256_result(context: &mut Sha2_256Context) -> Result<Digest256, SHA2Result> {
|
pub fn sha2_256_result(context: &mut Sha2_256Context) -> Result<Digest256, SHA2Outcome> {
|
||||||
let mut digest: Digest256 = DIGEST256_EMPTY;
|
let mut digest: Digest256 = DIGEST256_EMPTY;
|
||||||
let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) };
|
let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) };
|
||||||
to_res(digest, res)
|
to_res(digest, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn to_res<T>(if_ok: T, res: SHA2Result) -> Result<T, SHA2Result> {
|
pub(crate) fn to_res<T>(if_ok: T, res: SHA2Outcome) -> Result<T, SHA2Outcome> {
|
||||||
if res == SHA2Result::shaSuccess {
|
if res == SHA2Outcome::shaSuccess {
|
||||||
Ok(if_ok)
|
Ok(if_ok)
|
||||||
} else {
|
} else {
|
||||||
Err(res)
|
Err(res)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::hash::ffi::SHA2Result;
|
use crate::hash::ffi::SHA2Outcome;
|
||||||
|
|
||||||
pub const SHA2_256_HASH_BITS: usize = 256;
|
pub const SHA2_256_HASH_BITS: usize = 256;
|
||||||
pub const SHA2_256_HASH_BYTES: usize = SHA2_256_HASH_BITS / 8;
|
pub const SHA2_256_HASH_BYTES: usize = SHA2_256_HASH_BITS / 8;
|
||||||
|
@ -8,19 +8,48 @@ pub const SHA2_256_BLOCK_SIZE: usize = 2 * SHA2_256_HASH_BYTES;
|
||||||
pub type Digest256 = [u32; SHA2_256_HASH_PARTS];
|
pub type Digest256 = [u32; SHA2_256_HASH_PARTS];
|
||||||
pub(crate) const DIGEST256_EMPTY: Digest256 = [0; SHA2_256_HASH_PARTS];
|
pub(crate) const DIGEST256_EMPTY: Digest256 = [0; SHA2_256_HASH_PARTS];
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
macro_rules! show_internals {
|
||||||
pub struct SHA2_256Context {
|
($block:block) => {
|
||||||
|
#[cfg(feature = "show_internals")]
|
||||||
|
$block
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub struct Sha2_256Context {
|
||||||
intermediate_hash: Digest256,
|
intermediate_hash: Digest256,
|
||||||
block: [u8; SHA2_256_BLOCK_SIZE],
|
block: [u8; SHA2_256_BLOCK_SIZE],
|
||||||
block_idx: usize,
|
block_idx: usize,
|
||||||
|
length_low: usize,
|
||||||
|
length_high: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SHA2_256Context {
|
impl Sha2_256Context {
|
||||||
|
const K: [u32; SHA2_256_BLOCK_SIZE] = [
|
||||||
|
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,
|
||||||
|
];
|
||||||
|
const H: [u32; SHA2_256_HASH_PARTS] = [
|
||||||
|
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
|
||||||
|
0x5be0cd19,
|
||||||
|
];
|
||||||
|
const PAD_BYTE: u8 = 0x80;
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
intermediate_hash: Default::default(),
|
intermediate_hash: Self::H,
|
||||||
block: [0; SHA2_256_BLOCK_SIZE],
|
block: [0; SHA2_256_BLOCK_SIZE],
|
||||||
block_idx: Default::default(),
|
block_idx: Default::default(),
|
||||||
|
length_low: Default::default(),
|
||||||
|
length_high: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,28 +57,293 @@ impl SHA2_256Context {
|
||||||
*self = Self::new();
|
*self = Self::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&mut self, data: &[u8]) -> Result<(), SHA2Result> {
|
pub fn input(&mut self, data: &[u8]) -> Result<(), SHA2Outcome> {
|
||||||
todo!()
|
if data.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
for byte in data {
|
||||||
|
self.block[self.block_idx] = *byte;
|
||||||
|
self.block_idx += 1;
|
||||||
|
if self.add_length(8).is_ok() && self.block_idx == SHA2_256_BLOCK_SIZE {
|
||||||
|
self.process_block();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(self) -> Result<Digest256, SHA2Result> {
|
pub fn finish(mut self) -> Result<Digest256, SHA2Outcome> {
|
||||||
todo!()
|
self.finalize();
|
||||||
|
Ok(self.intermediate_hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BUG: false values at end?
|
||||||
|
fn process_block(&mut self) {
|
||||||
|
show_internals!({
|
||||||
|
self.show_internal_state("start processing");
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut w = [0; SHA2_256_BLOCK_SIZE];
|
||||||
|
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
|
for t in 0..16 {
|
||||||
|
let t4 = t * 4;
|
||||||
|
w[t] = ((self.block[t4] as u32) << 24)
|
||||||
|
| ((self.block[t4 + 1] as u32) << 16)
|
||||||
|
| ((self.block[t4 + 2] as u32) << 8)
|
||||||
|
| (self.block[t4 + 3] as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
for t in 16..SHA2_256_BLOCK_SIZE {
|
||||||
|
w[t] = Self::sha256_sigma1_1(w[t - 2])
|
||||||
|
.wrapping_add(w[t - 7])
|
||||||
|
.wrapping_add(Self::sha256_sigma0_1(w[t - 15]))
|
||||||
|
.wrapping_add(w[t - 16]);
|
||||||
|
}
|
||||||
|
|
||||||
|
show_internals!({
|
||||||
|
for (i, w) in w.iter().enumerate() {
|
||||||
|
println!("w[{i}]:\t{w:032b}")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut a = self.intermediate_hash[0];
|
||||||
|
let mut b = self.intermediate_hash[1];
|
||||||
|
let mut c = self.intermediate_hash[2];
|
||||||
|
let mut d = self.intermediate_hash[3];
|
||||||
|
let mut e = self.intermediate_hash[4];
|
||||||
|
let mut f = self.intermediate_hash[5];
|
||||||
|
let mut g = self.intermediate_hash[6];
|
||||||
|
let mut h = self.intermediate_hash[7];
|
||||||
|
|
||||||
|
show_internals!({
|
||||||
|
println!("A:\t{a:032b}");
|
||||||
|
println!("B:\t{b:032b}");
|
||||||
|
println!("C:\t{c:032b}");
|
||||||
|
println!("D:\t{d:032b}");
|
||||||
|
println!("E:\t{e:032b}");
|
||||||
|
println!("F:\t{f:032b}");
|
||||||
|
println!("G:\t{g:032b}");
|
||||||
|
println!("H:\t{h:032b}");
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut temp1;
|
||||||
|
let mut temp2;
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
|
for t in 0..SHA2_256_BLOCK_SIZE {
|
||||||
|
show_internals!({
|
||||||
|
println!("Iter {t}");
|
||||||
|
});
|
||||||
|
|
||||||
|
// BUG: the alphabet values are not being changed correctly?
|
||||||
|
temp1 = h
|
||||||
|
.wrapping_add(Self::sha256_sigma1_0(e))
|
||||||
|
.wrapping_add(Self::sha_ch(e, f, g))
|
||||||
|
.wrapping_add(Self::K[t])
|
||||||
|
.wrapping_add(w[t]);
|
||||||
|
temp2 = Self::sha256_sigma0_0(a).wrapping_add(Self::sha_maj(a, b, c));
|
||||||
|
h = g;
|
||||||
|
g = f;
|
||||||
|
f = e;
|
||||||
|
e = d.wrapping_add(temp1);
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = a;
|
||||||
|
a = temp1.wrapping_add(temp2);
|
||||||
|
|
||||||
|
show_internals!({
|
||||||
|
println!("A:\t{a:032b} {a:08x}");
|
||||||
|
println!("B:\t{b:032b} {b:08x}");
|
||||||
|
println!("C:\t{c:032b} {c:08x}");
|
||||||
|
println!("D:\t{d:032b} {d:08x}");
|
||||||
|
println!("E:\t{e:032b} {e:08x}");
|
||||||
|
println!("F:\t{f:032b} {f:08x}");
|
||||||
|
println!("G:\t{g:032b} {g:08x}");
|
||||||
|
println!("H:\t{h:032b} {h:08x}");
|
||||||
|
for (i, h) in self.intermediate_hash.iter().enumerate() {
|
||||||
|
println!("h[{i}]:\t{h:032b} {h:08x}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
show_internals!({
|
||||||
|
self.show_internal_state("assigning intermediate_hash");
|
||||||
|
});
|
||||||
|
|
||||||
|
self.intermediate_hash[0] = self.intermediate_hash[0].wrapping_add(a);
|
||||||
|
self.intermediate_hash[1] = self.intermediate_hash[1].wrapping_add(b);
|
||||||
|
self.intermediate_hash[2] = self.intermediate_hash[2].wrapping_add(c);
|
||||||
|
self.intermediate_hash[3] = self.intermediate_hash[3].wrapping_add(d);
|
||||||
|
self.intermediate_hash[4] = self.intermediate_hash[4].wrapping_add(e);
|
||||||
|
self.intermediate_hash[5] = self.intermediate_hash[5].wrapping_add(f);
|
||||||
|
self.intermediate_hash[6] = self.intermediate_hash[6].wrapping_add(g);
|
||||||
|
self.intermediate_hash[7] = self.intermediate_hash[7].wrapping_add(h);
|
||||||
|
|
||||||
|
self.block_idx = 0;
|
||||||
|
|
||||||
|
// BUG: something is weird with these hash values, they are almost right?
|
||||||
|
show_internals!({
|
||||||
|
self.show_internal_state("processing end");
|
||||||
|
for (i, h) in self.intermediate_hash.iter().enumerate() {
|
||||||
|
println!("h[{i}]:\t{h:032b}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_length(&mut self, len: usize) -> Result<(), SHA2Outcome> {
|
||||||
|
let add_temp = self.length_low;
|
||||||
|
|
||||||
|
// Update length_low and check for overflow
|
||||||
|
self.length_low = self.length_low.wrapping_add(len);
|
||||||
|
if self.length_low < add_temp {
|
||||||
|
// Overflow occurred, increment length_high
|
||||||
|
self.length_high = self.length_high.wrapping_add(1);
|
||||||
|
if self.length_high == 0 {
|
||||||
|
return Err(SHA2Outcome::shaInputTooLong);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SHA2_256Context {
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) {
|
||||||
|
self.pad_block();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pad_block(&mut self) {
|
||||||
|
if self.block_idx >= (SHA2_256_BLOCK_SIZE - 8) {
|
||||||
|
self.block[self.block_idx] = Self::PAD_BYTE;
|
||||||
|
self.block_idx += 1;
|
||||||
|
while self.block_idx < SHA2_256_BLOCK_SIZE {
|
||||||
|
self.block[self.block_idx] = 0;
|
||||||
|
self.block_idx += 1;
|
||||||
|
}
|
||||||
|
self.process_block();
|
||||||
|
} else {
|
||||||
|
self.block[self.block_idx] = Self::PAD_BYTE;
|
||||||
|
self.block_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while self.block_idx < (SHA2_256_BLOCK_SIZE - 8) {
|
||||||
|
self.block[self.block_idx] = 0;
|
||||||
|
self.block_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.block[56] = (self.length_high >> 24) as u8;
|
||||||
|
self.block[57] = (self.length_high >> 16) as u8;
|
||||||
|
self.block[58] = (self.length_high >> 8) as u8;
|
||||||
|
self.block[59] = (self.length_high) as u8;
|
||||||
|
self.block[60] = (self.length_low >> 24) as u8;
|
||||||
|
self.block[61] = (self.length_low >> 16) as u8;
|
||||||
|
self.block[62] = (self.length_low >> 8) as u8;
|
||||||
|
self.block[63] = (self.length_low) as u8;
|
||||||
|
|
||||||
|
self.process_block();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "show_internals")]
|
||||||
|
fn show_internal_state(&self, msg: impl core::fmt::Display) {
|
||||||
|
println!("{msg}\n{self:#x?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// internal functions for SHA2 process_block
|
||||||
|
impl Sha2_256Context {
|
||||||
|
#[inline]
|
||||||
|
fn sha256_shr(bits: u32, word: u32) -> u32 {
|
||||||
|
word >> bits
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sha256_rotr(bits: u32, word: u32) -> u32 {
|
||||||
|
u32::rotate_right(word, bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256_sigma0_0(word: u32) -> u32 {
|
||||||
|
Self::sha256_rotr(2, word) ^ Self::sha256_rotr(13, word) ^ Self::sha256_shr(22, word)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256_sigma1_0(word: u32) -> u32 {
|
||||||
|
Self::sha256_rotr(6, word) ^ Self::sha256_rotr(11, word) ^ Self::sha256_shr(25, word)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256_sigma0_1(word: u32) -> u32 {
|
||||||
|
Self::sha256_rotr(7, word) ^ Self::sha256_rotr(18, word) ^ Self::sha256_shr(3, word)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256_sigma1_1(word: u32) -> u32 {
|
||||||
|
Self::sha256_rotr(17, word) ^ Self::sha256_rotr(19, word) ^ Self::sha256_shr(10, word)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sha_ch(x: u32, y: u32, z: u32) -> u32 {
|
||||||
|
(x & (y ^ z)) ^ z
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sha_maj(x: u32, y: u32, z: u32) -> u32 {
|
||||||
|
(x & (y | z)) | (y & z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Sha2_256Context {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Result> {
|
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Outcome> {
|
||||||
todo!()
|
let mut ctx = Sha2_256Context::default();
|
||||||
|
ctx.input(data)?;
|
||||||
|
ctx.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "show_internals")]
|
||||||
|
#[allow(unused)]
|
||||||
|
mod debug {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
struct InlineArrHex2<'a, T: core::fmt::Debug + core::fmt::LowerHex>(&'a [T]);
|
||||||
|
|
||||||
|
impl<'a, T> core::fmt::Debug for InlineArrHex2<'a, T>
|
||||||
|
where
|
||||||
|
T: core::fmt::Debug + core::fmt::LowerHex,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(f, "[\n")?;
|
||||||
|
for (i, t) in self.0.iter().enumerate() {
|
||||||
|
write!(f, "0x{t:02x}")?;
|
||||||
|
if i < self.0.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
if i % 8 == 7 && i < self.0.len() - 1 {
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "\n]")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Debug for Sha2_256Context {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("Sha2_256Context")
|
||||||
|
.field("intermediate_hash", &InlineArrHex2(&self.intermediate_hash))
|
||||||
|
.field("block", &InlineArrHex2(&self.block))
|
||||||
|
.field("block_idx", &self.block_idx)
|
||||||
|
.field("length_low", &self.length_low)
|
||||||
|
.field("length_high", &self.length_high)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "show_internals")]
|
||||||
|
use debug::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use assert_hex::*;
|
||||||
|
use pretty_assertions::{assert_eq, assert_ne};
|
||||||
|
|
||||||
const TEST_VALUES: &[(&str, Digest256)] = &[
|
const TEST_VALUES: &[(&str, Digest256)] = &[
|
||||||
(
|
(
|
||||||
|
@ -70,8 +364,16 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check() {
|
fn test_check() {
|
||||||
|
let mut dig;
|
||||||
for (input, expected_output) in TEST_VALUES.iter().copied() {
|
for (input, expected_output) in TEST_VALUES.iter().copied() {
|
||||||
assert_eq!(sha2_256_oneshot(input.as_bytes()), Ok(expected_output))
|
dig = sha2_256_oneshot(input.as_bytes()).unwrap();
|
||||||
|
println!(
|
||||||
|
"Binary of first seg matches: {}\n{:032b}\n{:032b}",
|
||||||
|
dig[0] == expected_output[0],
|
||||||
|
dig[0],
|
||||||
|
expected_output[0]
|
||||||
|
);
|
||||||
|
assert_eq_hex!(dig, expected_output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//! Many thanks to the [crc-catalogue](https://reveng.sourceforge.io/crc-catalogue/) for providing
|
//! Many thanks to the [crc-catalogue](https://reveng.sourceforge.io/crc-catalogue/) for providing
|
||||||
//! an overview over the various algorithms with test vectors and examples.
|
//! an overview over the various algorithms with test vectors and examples.
|
||||||
|
|
||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(any(test, feature = "std")), no_std)]
|
||||||
|
|
||||||
pub mod crc;
|
pub mod crc;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
|
|
Loading…
Add table
Reference in a new issue