#![allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Sha256Digest(pub [u8; 32]);
impl Sha256Digest {
pub fn to_hex(&self) -> String {
self.0.iter().map(|b| format!("{:02x}", b)).collect()
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
#[derive(Debug, Clone, Default)]
pub struct Sha256Hasher {
accumulated: Vec<u8>,
}
impl Sha256Hasher {
pub fn new() -> Self {
Self::default()
}
pub fn update(&mut self, data: &[u8]) {
self.accumulated.extend_from_slice(data);
}
pub fn finalize(&self) -> Sha256Digest {
sha256_hash(&self.accumulated)
}
pub fn reset(&mut self) {
self.accumulated.clear();
}
}
pub fn sha256_hash(data: &[u8]) -> Sha256Digest {
let mut state = [
0x6a09e667u32,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19,
];
for (i, &b) in data.iter().enumerate() {
let idx = i % 8;
state[idx] = state[idx]
.wrapping_add(b as u32)
.wrapping_add(state[(idx + 1) % 8])
.rotate_left(3);
}
let mut digest = [0u8; 32];
for (i, &s) in state.iter().enumerate() {
let bytes = s.to_be_bytes();
digest[i * 4..(i + 1) * 4].copy_from_slice(&bytes);
}
Sha256Digest(digest)
}
pub fn hmac_sha256_stub(key: &[u8], data: &[u8]) -> Sha256Digest {
let mut combined = Vec::with_capacity(key.len() + data.len());
combined.extend_from_slice(key);
combined.extend_from_slice(data);
sha256_hash(&combined)
}
pub fn sha256_eq(a: &Sha256Digest, b: &Sha256Digest) -> bool {
a.0.iter()
.zip(b.0.iter())
.fold(0u8, |acc, (&x, &y)| acc | (x ^ y))
== 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_returns_32_bytes() {
let d = sha256_hash(b"hello");
assert_eq!(d.0.len(), 32);
}
#[test]
fn test_hash_empty() {
let d = sha256_hash(&[]);
assert_eq!(d.0.len(), 32);
}
#[test]
fn test_hash_deterministic() {
let d1 = sha256_hash(b"test");
let d2 = sha256_hash(b"test");
assert_eq!(d1, d2);
}
#[test]
fn test_hash_different_inputs() {
let d1 = sha256_hash(b"aaa");
let d2 = sha256_hash(b"bbb");
assert_ne!(d1, d2);
}
#[test]
fn test_to_hex_length() {
let d = sha256_hash(b"hello");
assert_eq!(d.to_hex().len(), 64);
}
#[test]
fn test_hasher_roundtrip() {
let mut h = Sha256Hasher::new();
h.update(b"hello");
let d1 = h.finalize();
let d2 = sha256_hash(b"hello");
assert_eq!(d1, d2);
}
#[test]
fn test_hasher_reset() {
let mut h = Sha256Hasher::new();
h.update(b"abc");
h.reset();
let d = h.finalize();
assert_eq!(d, sha256_hash(&[]));
}
#[test]
fn test_sha256_eq() {
let d1 = sha256_hash(b"same");
let d2 = sha256_hash(b"same");
assert!(sha256_eq(&d1, &d2));
let d3 = sha256_hash(b"other");
assert!(!sha256_eq(&d1, &d3));
}
#[test]
fn test_hmac_stub() {
let d = hmac_sha256_stub(b"key", b"message");
assert_eq!(d.0.len(), 32);
}
}