WO-02 — SHAKE256 / KMAC256 wrapper¶
7 October 2026 · Built by Claude on branch wo-02-shake (from wo-01-librl). Local checks passed. Not committed or merged without the owner’s approval; awaiting the owner’s review.
Delivered¶
File |
What |
|---|---|
|
|
|
static target |
|
command-line driver for differential tests and surprise exams |
|
unit checks: known answers, XOF prefix property, KMAC length binding, tag rule, incremental splits, every error path |
|
independent pure-Python reference (Keccak-f[1600] from FIPS 202; cSHAKE256/KMAC256 from SP 800-185; no OpenSSL) and its frozen vectors |
|
C++ vs golden, every vector, every mode |
No SHA-2, no floating point, no cryptographic code of our own beyond the independent test reference. Nothing was downloaded or installed: OpenSSL 3.6.5 was already present via Homebrew.
How the reference was trusted before freezing¶
Check |
Result |
|---|---|
Pure-Python SHAKE256 vs Python |
identical on every vector (asserted during generation) |
Pure-Python KMAC256 vs the OpenSSL command-line tool ( |
40/40 random cases identical |
NIST SP 800-185 KMAC256 sample #4 (key 0x40…0x5F, data 00010203, “My Tagged Application”, 512 bits) |
|
Golden regenerates byte for byte ( |
yes |
Results¶
Gate (WORK-ORDERS.md) |
Result |
|---|---|
NIST known answers |
SHAKE256(“”) and SHAKE256(“abc”) (FIPS 202), KMAC256 sample #4 (SP 800-185): pass |
Matches Python |
yes: golden + surprise exam |
Golden differential (442 SHAKE256 × 4 modes, 60 tagged, 98 KMAC256) |
1,926 comparisons, 0 mismatches |
Surprise exam (fresh inputs up to 20,000 bytes, seed never recorded): SHAKE vs hashlib, tagged vs hashlib, KMAC vs pure Python |
17,800 comparisons, 0 mismatches |
Release CTest (WO-01 + WO-02) |
5/5 passed |
ASan + UBSan CTest |
5/5 passed |
|
no warnings |
clang-format 22.1.8 (repo UNC style) |
clean |
Source fingerprints (SHAKE256, first 16 bytes): shake.hpp f4060cdc…, shake.cpp d6ef4269…, shake_cli.cpp dc888abd…, shake_tests.cpp d1ca55f9…, verify_wo02.py 8f20ab5e…, generate_wo02.py 12657d9d…, wo02-golden.json 777daba1…, CMakeLists.txt 515ab685….
Decisions to review¶
Tag rule: tags must be non-empty printable ASCII with no spaces or NUL; the separator is one 0x00 byte, exactly as the spec writes
"E46-txid\0" ‖ data.Limits: SHAKE output ≤ 1 MiB per call (wrapper policy; E46 uses 16/32/64 bytes). KMAC256 key 4–512 bytes, customization ≤ 512 bytes, output 1–2,097,151 bytes, checked before calling OpenSSL (these mirror OpenSSL’s own bounds), so errors are deterministic.
KMAC mode: non-XOF (output length bound into the MAC), as SP 800-185 KMAC256 defines; a test proves the 32-byte and 64-byte results differ.
Not done: no fuzz harness (the wrapper has no parser of its own; input parsing lives in the CLI’s shared hex helper from WO-01, which WO-01 already fuzzed); no benchmark (speed is OpenSSL’s, and no WO-02 gate requires it).
Dependency: E46 now requires OpenSSL ≥ 3.0 at build time. On Linux the system OpenSSL 3 works; the macOS path hint is only used if
OPENSSL_ROOT_DIRisn’t set.
Reproduce¶
cmake --preset release && cmake --build --preset release && ctest --preset release
cmake --preset sanitize && cmake --build --preset sanitize && ctest --preset sanitize
python3 -B e46/golden/generate_wo02.py --check