F1.1: std.hash — streaming SHA-256 in library/modules/std/hash.sx
Add a pure-sx streaming SHA-256 (FIPS 180-4) stdlib module, importable as `#import "modules/std/hash.sx";`. All 32-bit word arithmetic is done in s64 and masked back with `& MASK32`, so digests are deterministic and platform-independent — no shelling out, no native crypto. API: - init() -> Sha256 (by-value *self pattern) - update(*Sha256, string) (multi-block + partial-block buffering) - final(*Sha256) -> string (32-byte digest as lowercase hex) - sha256_hex(string) -> string (one-shot) - sha256_file([:0]u8) -> ?string (digest of a file via fs.read_file) Verified against FIPS/NIST known-answer vectors and `shasum -a 256`: "" , "abc", the 56- and 112-byte multi-block vectors, 1000×'a', and the 64/65-byte block boundaries; chunked update() matches the one-shot call. examples/0710-modules-sha256.sx pins the KAT vectors + the streaming invariant; gate green (zig build, zig build test, run_examples 370/0/0/0).
This commit is contained in:
37
examples/0710-modules-sha256.sx
Normal file
37
examples/0710-modules-sha256.sx
Normal file
@@ -0,0 +1,37 @@
|
||||
// Streaming SHA-256 (FIPS 180-4) from `modules/std/hash.sx`.
|
||||
//
|
||||
// Known-answer vectors (empty, "abc", the 112-byte NIST multi-block
|
||||
// vector) plus the streaming invariant: feeding the same bytes in
|
||||
// several `update` chunks yields the same digest as the one-shot call.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/std/hash.sx";
|
||||
|
||||
check :: (label: string, got: string, want: string) {
|
||||
if got == want {
|
||||
print("{}: ok\n", label);
|
||||
} else {
|
||||
print("{}: FAIL got {} want {}\n", label, got, want);
|
||||
}
|
||||
}
|
||||
|
||||
main :: () {
|
||||
check("empty", sha256_hex(""),
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
|
||||
check("abc", sha256_hex("abc"),
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
|
||||
|
||||
// 112-byte input — spans more than one 64-byte block.
|
||||
multi := "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
|
||||
check("multi", sha256_hex(multi),
|
||||
"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1");
|
||||
|
||||
// Streaming must equal one-shot regardless of chunk boundaries.
|
||||
h := init();
|
||||
h.update("abcdefghbcdefghicdefghijdefghijke"); // 33 bytes
|
||||
h.update("fghijklfghijklmghijklmnhijklmno"); // crosses block edge
|
||||
h.update("ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
|
||||
streamed := h.final();
|
||||
check("stream-eq-oneshot",
|
||||
if streamed == sha256_hex(multi) then "yes" else "no", "yes");
|
||||
}
|
||||
1
examples/expected/0710-modules-sha256.exit
Normal file
1
examples/expected/0710-modules-sha256.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/expected/0710-modules-sha256.stderr
Normal file
1
examples/expected/0710-modules-sha256.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
4
examples/expected/0710-modules-sha256.stdout
Normal file
4
examples/expected/0710-modules-sha256.stdout
Normal file
@@ -0,0 +1,4 @@
|
||||
empty: ok
|
||||
abc: ok
|
||||
multi: ok
|
||||
stream-eq-oneshot: ok
|
||||
Reference in New Issue
Block a user