Cryptography
A pure-NURL crypto and TLS stack, built on libc only.
NURL ships its own cryptography and TLS implementation. The
implementation uses only NURL on top of libc. No OpenSSL, no
libcrypto, no libssl. A binary
that only uses this stack links libc (and libm) alone. All of it is
under stdlib/std/.
What's implemented
| Area | Modules | Notes |
|---|---|---|
| Post-Quantum | mlkem (FIPS 203 ML-KEM-512/768/1024), mldsa (FIPS 204 ML-DSA-44/65/87), slhdsa (FIPS 205 SLH-DSA-SHAKE) | pure-NURL lattice and stateless hash-based KEM and signatures |
| Hashes & XOF | hash_sha256, hash_sha512, hash_sha3 (FIPS 202 SHA3-224/256/384/512, SHAKE128/256), hash_blake2b, hash_blake3, hash_sha1, hash_md5 | SHA-1 and MD5 are for legacy interop only, never for signatures |
| HMAC / KDF | hkdf, pbkdf2, scrypt | |
| AEAD | aes_gcm (AES-128/256-GCM), chacha20poly1305 | the TLS 1.3 and QUIC record ciphers |
| Classical ECDH / signatures | x25519, ed25519, ecdsa_p256 (P-256 + P-384), minisign | p256_field is a dedicated constant-time field implementation for the P-256 secret path |
| RSA | rsa (PKCS#1 v1.5 verify, PSS verify + sign) | built on the bigint module |
| X.509, PKCS & SSH | x509, x509_gen, csr (PKCS#10), pkey (encrypted PKCS#8 v2), tls_verify, ssh, ssh_ed25519 | DER/PEM parsing, cert/CSR generation, chain/hostname/policy verification, and SSH keys/wire protocol |
| TLS & QUIC | tls (client 1.3 with hybrid X25519MLKEM768 by default, 1.2 fallback), tls_server (1.3), quic_crypto, quic_tls | supports both classical and ML-DSA certificates |
| Randomness | random (CSPRNG), rng (xoshiro256**) | rng is explicitly not cryptographic — simulations only |
| Constant-time compare | subtle | length-independent secret comparison |
Randomness
Every cryptographic draw — keys, nonces, salts, blinding factors — goes
through one runtime bridge that selects the OS CSPRNG per platform
(getrandom(2) on Linux, arc4random_buf on macOS, BCryptGenRandom on
Windows). If a draw fails, the system panics. It does not silently fall back to
predictable bytes. The xoshiro256** generator in std/rng.nu is a separate,
non-cryptographic PRNG. The crypto and TLS code never uses it.
Correctness
Every primitive has a known-answer test that runs on every build, backed by 770+ Project Wycheproof vectors and NIST ACVP test suites (including FIPS 203 ML-KEM, FIPS 204 ML-DSA, FIPS 205 SLH-DSA, and FIPS 202 SHA-3).
Interoperability tests check the stack against OpenSSL, curl,
browsers, and the badssl.com negative test suite. ECDSA signing uses a
deterministic nonce (RFC 6979), so a signature is reproducible and never
reuses a nonce. This is independent of the random per-signature blinding
factor for side-channel hardening.
Side-channel posture
Timing vs. power/EM side-channels
By construction, the elliptic-curve and symmetric primitives run in constant time. This includes operand timing. RSA's big-integer arithmetic has one residual: operand-dependent timing. Blinding covers this. Power/electromagnetic (DPA/template) side-channels are out of scope for the whole stack. You need hardware, not software, to defend against those.
TLS
tls_connect verifies the full certificate chain and hostname. You skip
verification with a separate, explicitly named function
(tls_connect_insecure). It is not a flag on tls_connect. The
socket-layer tcp_connect_tls (and its _alpn and _full variants)
takes the choice as an argument instead: a non-zero verify verifies, 0
encrypts without verifying. See
Networking for the connection-level API.
Next
- Networking — TLS, MQTT, and the socket layer this stack sits under.
- The full trust model, KAT list, and what is explicitly out of scope is in
docs/CRYPTO.md.
Last updated on