code wiki / (root) / nx_ct.nx

nx_ct.nx

buildroot/runtime/nx_ct.nx

6648 B167 linesdepth 0pulls 0 transitivereach 48 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

ct.nx -- constant-time arithmetic primitives. Every crypto primitive -- hash, cipher, MAC, KEM, signature -- that touches secret data MUST route through these helpers. The contract: the running time of each function is independent of input values, only of input lengths. No branches on secret bits, no indexed lookups driven by secret bits, no early exits. Why: without constant-time execution, even a cryptographically perfect algorithm leaks secrets through timing (Kocher 1996), power analysis (DPA, Kocher 1999), and cache side-channels (Spectre 2018, Flush+Reload 2014). These leaks defeat RSA, AES, ECDSA, and every post-quantum scheme that NIST standardised. Adversary model we harden against: - Timing from shared clocks (local or remote) - Hyperthread / SMT cache interference - Power/EM on modest hardware Out of scope (addressed at silicon phase, not in this file): - Speculative execution (Spectre family) - Rowhammer DRAM fault injection - Physical glitching / laser fault injection Research: - "Cryptographic Engineering" (KoƧ 2008), ch. 11 - "The Boringssl/Fiat-Crypto constant-time subset" (Erbsen 2019) - NIST SP 800-140A side-channel resistance requirements Invariants enforced, not assumed: C1 No branch depends on a byte or word value that could be secret. Branches on *lengths* are allowed -- length is assumed to be known to the adversary anyway. C2 No indexed memory load uses a secret value as the index (prevents cache-line-sampling attacks). C3 No early return short-circuits a comparison; every byte of the fixed-length input participates in the result. C4 Arithmetic uses unsigned semantics where possible so the optimiser never rewrites branchless code into branched code (signed overflow is UB in C and a rewrite trigger; NishiLang has no UB but we still prefer the unsigned

dependencies 0 imports · 7 importers

nx_ct.nx nx_aead.nx nx_basic_auth.nx nx_csrf_token.nx nx_ed25519.nx nx_jwt.nx nx_signed_cookie.nx nx_totp_verify.nx

imports: none

imported by: nx_aead.nxnx_basic_auth.nxnx_csrf_token.nxnx_ed25519.nxnx_jwt.nxnx_signed_cookie.nxnx_totp_verify.nx

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main ct_eq ct_lt ct_select

structs

none

consts

none

functions

49func ct_eq(a: i64, b: i64) -> i64 {
67func ct_lt(a: i64, b: i64) -> i64 {
called by 1: main
86func ct_select(cond: i64, a: i64, b: i64) -> i64 {
called by 1: main
98func ct_memcmp(a: *u8, b: *u8, n: i64) -> i64 {
114func ct_copy_cond(cond: i64, dst: *u8, src: *u8, n: i64) -> i64 {
130func ct_is_zero(buf: *u8, n: i64) -> i64 {
calls 1: ct_eq
146func main() -> i64 {