Hashing: SHA-256 & HMAC
akurai-hash gives every AkurAI application FIPS 180-4 SHA-256 and RFC 2104 HMAC-SHA256 without linking sha2 or hmac. Pure std, #![forbid(unsafe_code)], and proven by known-answer vectors (NIST empty/abc/two-block/one-million-a, RFC 4231 cases 1, 2, 6, 7) in crates/hash/tests/vectors.rs.
One-shot
use akurai_hash::{hex_lower, sha256};
let digest: [u8; 32] = sha256(b"abc");
assert_eq!(
hex_lower(&digest),
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
);
Streaming
Hash data that does not fit in memory, or arrives in chunks:
use akurai_hash::Sha256;
let mut h = Sha256::new();
for chunk in reader_chunks() {
h.update(&chunk);
}
let digest = h.finalize();
Chunk boundaries never affect the result — feeding one byte at a time yields the same digest as one call.
HMAC
use akurai_hash::{hex_lower, hmac_sha256};
let mac = hmac_sha256(b"Jefe", b"what do ya want for nothing?");
assert_eq!(
hex_lower(&mac),
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
);
Keys longer than the 64-byte block are hashed first, per RFC 2104. This is the building block for AWS SigV4 request signing and any keyed integrity check.
Content-addressed blobs
The blob store keeps its fast FNV-1a ids by default. When ids must resist an adversary crafting collisions, opt in per call:
use akurai_blobs::{content_id_sha256, BlobStore};
let mut store = BlobStore::open("data/blobs.db")?;
let id = store.put_sha256(bytes)?; // 64 lowercase hex chars
assert_eq!(id, content_id_sha256(bytes));
FNV ids are 32 chars and SHA-256 ids are 64, so the two schemes never collide inside one store.
Performance
A straightforward scalar implementation: tens of MB/s, adequate for signing, ETags, and upload integrity. It is not SIMD-accelerated; hashing multi-gigabyte streams on the request path should be avoided regardless of implementation.