sha3.nx
buildroot/runtime/sha3.nx
about
sha3.nx -- FIPS 202 SHA3-256 (Keccak-f[1600], rate=1088 bits).
Quantum-safe companion to sha256.nx. Under Grover's algorithm both
SHA-256 and SHA3-256 have ~128-bit collision resistance on a quantum
adversary, which remains secure -- but SHA-3 is the primitive used
internally by NIST post-quantum schemes (ML-KEM FIPS 203, ML-DSA
FIPS 204, SLH-DSA FIPS 205), so shipping it here is the prerequisite
for every quantum-safe KEM/signature we'll add later.
Design:
- State: 25 * u64 = 1600 bits, laid out as a 5x5 lane grid A[x,y]
- Permutation: 24 rounds of theta, rho, pi, chi, iota
- Padding: SHA-3 domain separation byte 0x06, trailing 0x80
- Rate for SHA3-256: r = 1088 bits = 136 bytes; capacity c = 512
- Output: 32 bytes (first 256 bits of the state after finalisation)
Reference: FIPS PUB 202, sections 3.2-3.3. Known answer:
sha3_256("abc") =
3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532
This implementation:
- Pure NishiLang; no C interop; no libc.
- Uses only arithmetic + bit ops (XOR, AND, NOT, rotate-left)
defined on i64; 1600-bit state lives in a 25-entry i64 array.
- Sequential round loop; no table lookups on secret data.
Timing-side-channel stance: Keccak-f is naturally constant-time
when compiled straight from the spec. The only operations are
XOR, AND, NOT, and rotate-left -- all secret-independent in time.
No S-box table, no conditional on state bits. Safe to handle
secret data directly.
dependencies 2 imports · 0 importers
imports: syscalls.nxnx_bits.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 42 | const RC0: i64 = 0x0000000000000001 |
| 43 | const RC1: i64 = 0x0000000000008082 |
| 44 | const RC2: i64 = 0x800000000000808A |
| 45 | const RC3: i64 = 0x8000000080008000 |
| 46 | const RC4: i64 = 0x000000000000808B |
| 47 | const RC5: i64 = 0x0000000080000001 |
| 48 | const RC6: i64 = 0x8000000080008081 |
| 49 | const RC7: i64 = 0x8000000000008009 |
| 50 | const RC8: i64 = 0x000000000000008A |
| 51 | const RC9: i64 = 0x0000000000000088 |
| 52 | const RC10: i64 = 0x0000000080008009 |
| 53 | const RC11: i64 = 0x000000008000000A |
| 54 | const RC12: i64 = 0x000000008000808B |
| 55 | const RC13: i64 = 0x800000000000008B |
| 56 | const RC14: i64 = 0x8000000000008089 |
| 57 | const RC15: i64 = 0x8000000000008003 |
| 58 | const RC16: i64 = 0x8000000000008002 |
| 59 | const RC17: i64 = 0x8000000000000080 |
| 60 | const RC18: i64 = 0x000000000000800A |
| 61 | const RC19: i64 = 0x800000008000000A |
| 62 | const RC20: i64 = 0x8000000080008081 |
| 63 | const RC21: i64 = 0x8000000000008080 |
| 64 | const RC22: i64 = 0x0000000080000001 |
| 65 | const RC23: i64 = 0x8000000080008008 |
functions
| 68 | func sha3_rc(r: i64) -> i64 {
called by 1: keccak_round |
| 97 | func sha3_rho(i: i64) -> i64 {
called by 1: keccak_round |
| 126 | func rotl64(x: i64, r: i64) -> i64 { |
| 131 | func lane_at(state: *i64, x: i64, y: i64) -> i64 {
called by 1: keccak_round |
| 135 | func lane_set(state: *i64, x: i64, y: i64, v: i64) -> i64 {
called by 1: keccak_round |
| 142 | func keccak_round(state: *i64, scratch: *i64, round_idx: i64) -> i64 { |
| 213 | func keccak_permute(state: *i64, scratch: *i64) -> i64 { |
| 227 | func sha3_256(in_bytes: *u8, n: i64, out: *u8) -> i64 { |
| 293 | func main() -> i64 {
calls 1: sha3_256 |