fix(alg): sha2-256 sigma functions were wrong

This commit is contained in:
cscherr 2025-07-22 11:04:46 +02:00
parent bb81a7dd49
commit e78dc4a628
Signed by: cscherrNT
GPG key ID: 8E2B45BC51A27EA7
2 changed files with 73 additions and 20 deletions

View file

@ -18,3 +18,8 @@ apt install binutils-arm-none-eabi gcc-arm-none-eabi # compiler for the target a
apt install ruby # ceedling is the used build system for algorithms-c, and needs to be installed with gem, the ruby package manager apt install ruby # ceedling is the used build system for algorithms-c, and needs to be installed with gem, the ruby package manager
gem install ceedling gem install ceedling
``` ```
## Acknowledgements
For implementing the SHA-2-256 Algorithm, [this](https://sha256algorithm.com/)
website was very helpful.

View file

@ -76,7 +76,6 @@ impl Sha2_256Context {
Ok(self.intermediate_hash) Ok(self.intermediate_hash)
} }
// BUG: false values at end?
fn process_block(&mut self) { fn process_block(&mut self) {
show_internals!({ show_internals!({
self.show_internal_state("start processing"); self.show_internal_state("start processing");
@ -93,10 +92,12 @@ impl Sha2_256Context {
| (self.block[t4 + 3] as u32); | (self.block[t4 + 3] as u32);
} }
// NOTE: The sigma functions used for initializing W and for calculating the alphabet
// variables differ.
for t in 16..SHA2_256_BLOCK_SIZE { for t in 16..SHA2_256_BLOCK_SIZE {
w[t] = Self::sha256_sigma1_1(w[t - 2]) w[t] = Self::sha256_sigma1_w(w[t - 2])
.wrapping_add(w[t - 7]) .wrapping_add(w[t - 7])
.wrapping_add(Self::sha256_sigma0_1(w[t - 15])) .wrapping_add(Self::sha256_sigma0_w(w[t - 15]))
.wrapping_add(w[t - 16]); .wrapping_add(w[t - 16]);
} }
@ -134,13 +135,12 @@ impl Sha2_256Context {
println!("Iter {t}"); println!("Iter {t}");
}); });
// BUG: the alphabet values are not being changed correctly?
temp1 = h temp1 = h
.wrapping_add(Self::sha256_sigma1_0(e)) .wrapping_add(Self::sha256_sigma1(e))
.wrapping_add(Self::sha_ch(e, f, g)) .wrapping_add(Self::sha_ch(e, f, g))
.wrapping_add(Self::K[t]) .wrapping_add(Self::K[t])
.wrapping_add(w[t]); .wrapping_add(w[t]);
temp2 = Self::sha256_sigma0_0(a).wrapping_add(Self::sha_maj(a, b, c)); temp2 = Self::sha256_sigma0(a).wrapping_add(Self::sha_maj(a, b, c));
h = g; h = g;
g = f; g = f;
f = e; f = e;
@ -151,6 +151,8 @@ impl Sha2_256Context {
a = temp1.wrapping_add(temp2); a = temp1.wrapping_add(temp2);
show_internals!({ show_internals!({
println!("temp1:\t{temp1:032b} {temp1:08x}");
println!("temp2:\t{temp2:032b} {temp2:08x}");
println!("A:\t{a:032b} {a:08x}"); println!("A:\t{a:032b} {a:08x}");
println!("B:\t{b:032b} {b:08x}"); println!("B:\t{b:032b} {b:08x}");
println!("C:\t{c:032b} {c:08x}"); println!("C:\t{c:032b} {c:08x}");
@ -180,7 +182,6 @@ impl Sha2_256Context {
self.block_idx = 0; self.block_idx = 0;
// BUG: something is weird with these hash values, they are almost right?
show_internals!({ show_internals!({
self.show_internal_state("processing end"); self.show_internal_state("processing end");
for (i, h) in self.intermediate_hash.iter().enumerate() { for (i, h) in self.intermediate_hash.iter().enumerate() {
@ -255,25 +256,28 @@ impl Sha2_256Context {
#[inline] #[inline]
fn sha256_rotr(bits: u32, word: u32) -> u32 { fn sha256_rotr(bits: u32, word: u32) -> u32 {
u32::rotate_right(word, bits) word.rotate_right(bits)
} }
fn sha256_sigma0_0(word: u32) -> u32 { /// This is a different function for W
Self::sha256_rotr(2, word) ^ Self::sha256_rotr(13, word) ^ Self::sha256_shr(22, word) fn sha256_sigma0_w(word: u32) -> u32 {
}
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) Self::sha256_rotr(7, word) ^ Self::sha256_rotr(18, word) ^ Self::sha256_shr(3, word)
} }
fn sha256_sigma1_1(word: u32) -> u32 { /// This is a different function for W
fn sha256_sigma1_w(word: u32) -> u32 {
Self::sha256_rotr(17, word) ^ Self::sha256_rotr(19, word) ^ Self::sha256_shr(10, word) Self::sha256_rotr(17, word) ^ Self::sha256_rotr(19, word) ^ Self::sha256_shr(10, word)
} }
// NOTE: these do not use shift right for the last internal variable!
fn sha256_sigma0(word: u32) -> u32 {
Self::sha256_rotr(2, word) ^ Self::sha256_rotr(13, word) ^ Self::sha256_rotr(22, word)
}
fn sha256_sigma1(word: u32) -> u32 {
Self::sha256_rotr(6, word) ^ Self::sha256_rotr(11, word) ^ Self::sha256_rotr(25, word)
}
#[inline] #[inline]
fn sha_ch(x: u32, y: u32, z: u32) -> u32 { fn sha_ch(x: u32, y: u32, z: u32) -> u32 {
(x & (y ^ z)) ^ z (x & (y ^ z)) ^ z
@ -309,7 +313,7 @@ mod debug {
T: core::fmt::Debug + core::fmt::LowerHex, T: core::fmt::Debug + core::fmt::LowerHex,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "[\n")?; writeln!(f, "[")?;
for (i, t) in self.0.iter().enumerate() { for (i, t) in self.0.iter().enumerate() {
write!(f, "0x{t:02x}")?; write!(f, "0x{t:02x}")?;
if i < self.0.len() - 1 { if i < self.0.len() - 1 {
@ -337,6 +341,7 @@ mod debug {
} }
} }
#[cfg(feature = "show_internals")] #[cfg(feature = "show_internals")]
#[allow(unused)]
use debug::*; use debug::*;
#[cfg(test)] #[cfg(test)]
@ -345,6 +350,31 @@ mod test {
use assert_hex::*; use assert_hex::*;
use pretty_assertions::{assert_eq, assert_ne}; use pretty_assertions::{assert_eq, assert_ne};
macro_rules! assert_eq_bin {
($left:expr, $right:expr $(,)?) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!(r#"assertion `left == right` failed
left: {:b}
right: {:b}"#, &*left_val, &*right_val)
}
}
}
});
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!(r#"assertion `left == right` failed: {}
left: {:b}
right: {:b}"#, format_args!($($arg)+), &*left_val, &*right_val)
}
}
}
});
}
const TEST_VALUES: &[(&str, Digest256)] = &[ const TEST_VALUES: &[(&str, Digest256)] = &[
( (
"AAAA", "AAAA",
@ -363,7 +393,7 @@ mod test {
]; ];
#[test] #[test]
fn test_check() { fn test_sha256_check() {
let mut dig; let mut dig;
for (input, expected_output) in TEST_VALUES.iter().copied() { for (input, expected_output) in TEST_VALUES.iter().copied() {
dig = sha2_256_oneshot(input.as_bytes()).unwrap(); dig = sha2_256_oneshot(input.as_bytes()).unwrap();
@ -376,4 +406,22 @@ mod test {
assert_eq_hex!(dig, expected_output) assert_eq_hex!(dig, expected_output)
} }
} }
#[test]
fn test_sha256_sigma0() {
let a = 0b01101010000010011110011001100111;
assert_eq_bin!(
Sha2_256Context::sha256_sigma0(a),
0b11001110001000001011010001111110
);
}
#[test]
fn test_sha256_sigma1() {
let a = 0b01010001000011100101001001111111;
assert_eq_bin!(
Sha2_256Context::sha256_sigma1(a),
0b00110101100001110010011100101011
);
}
} }