chacha20.nx
buildroot/runtime/chacha20.nx
about
chacha20.nx -- RFC 8439 ChaCha20 stream cipher.
256-bit key, 96-bit nonce, 32-bit counter -> 64-byte keystream
blocks that XOR with plaintext. Specified in RFC 8439 (May 2018),
identical to IETF ChaCha20 (Bernstein 2008, IETF variant by Nir +
Langley 2014).
Why ChaCha20:
- Naturally constant-time: only ADD, ROTATE, XOR operations on
32-bit words. No S-box tables, no branches on secret data.
Immune to cache side-channels that plague table-based AES.
- Quantum stance: under Grover's algorithm the effective security
of a 256-bit-keyed stream cipher is 128 bits -- secure for the
forseeable future. Pairs with ML-KEM-768 for TLS 1.3 PQ hybrid.
- Simpler than AES (no key schedule distinct from encryption;
no bitsliced constant-time variant required).
Invariants:
CC1 No branches on key, nonce, counter, or state values. Every
word of the 16-word state is processed identically.
CC2 Rotate-left operations use constant shift amounts (7, 8, 9,
12, 13, 16, 18, 25) -- never driven by secret data.
CC3 Memory access pattern depends only on block length, not on
key/nonce/counter values.
CC4 The 32-bit counter is caller-owned; wrap-around behaviour
at 2^32 blocks (= 256 GiB with a given key+nonce) is
undefined by the spec. Callers must rekey before wrap.
API:
chacha20_block(key, counter, nonce, out) -- one 64-byte block
chacha20_encrypt(key, counter, nonce, in, n, out)
-- full message
References:
RFC 8439, section 2.3 "The ChaCha20 Block Function"
RFC 8439, section 2.4 "The ChaCha20 Encryption Algorithm"
Test vectors: RFC 8439 Appendix A.1 / A.2
dependencies 2 imports · 1 importers
imports: syscalls.nxnx_bits.nx
imported by: aead.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| none |
functions
| 44 | func u32_mask(x: i64) -> i64 { |
| 49 | func rotl32(x: i64, r: i64) -> i64 { |
| 56 | func qr(state: *i64, a: i64, b: i64, c: i64, d: i64) -> i64 { |
| 76 | func load_u32_le(buf: *u8, off: i64) -> i64 {
called by 1: chacha20_block |
| 85 | func store_u32_le(buf: *u8, off: i64, v: i64) -> i64 {
called by 1: chacha20_block |
| 104 | func chacha20_block(key: *u8, counter: i64, nonce: *u8, out: *u8) -> i64 { |
| 176 | func chacha20_encrypt(key: *u8, counter: i64, nonce: *u8, |
| 203 | func main() -> i64 {
calls 1: chacha20_block |