code wiki / (root) / nx_rate_limit.nx

nx_rate_limit.nx

buildroot/runtime/nx_rate_limit.nx

8614 B221 linesdepth 3pulls 3 transitivereach 0 importersview sourcekind tooltopic rate
docsdependenciesstructsconstsfunctions

about

nx_rate_limit.nx -- token-bucket rate limiter for brute-force resistance. Per docs/SECURITY_POSTURE.md principle P3: every API that verifies a signature, unseals a capability, or processes auth must rate-limit retries from the same source. Without this, an attacker with unlimited tries can exhaust the search space of any K-bit secret in 2^K / rate seconds, and current commodity hardware lets that be very fast. Token bucket semantics: - Each (operation, identity) pair has a bucket of `capacity` tokens, refilled at `refill_per_sec` tokens/second. - Each `consume(op, id)` call removes 1 token; if bucket is empty, the call fails (returns -EAGAIN). - State is persistent across restarts (caller stores the serialized bucket; we provide load/save). Lockout escalation: - After `lockout_threshold` consecutive failures from same identity: lockout_duration grows exponentially (1s, 1min, 1hr, 1day, permanent). - Permanent lockout requires explicit `nx_rl_admin_unlock` by an authority key (multi-person if K-of-N policy is enabled; single-key fallback for early dev). Logging: every failure emits a signed log entry through nx_attest (when shipped) so external witnesses can observe abuse patterns. Pairs with: nx_atom (per-bucket CAS), nx_attest (failure logs), nx_pcc (proof of "bucket invariant: tokens in [0, capacity]").

dependencies 1 imports · 0 importers

syscalls.nx nx_rate_limit.nx

imports: syscalls.nx

imported by: nobody (leaf or entry point)

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

main nx_rl_new nx_rl_now_ms nx_rl_try_consume nx_rl_now_ms ↻ nx_rl_refill nx_rl_now_ms ↻ nx_rl_record nx_rl_backoff_ms nx_rl_now_ms ↻ nx_rl_admin_unlock nx_rl_now_ms ↻ nx_rl_backoff_ms ↻

structs

48struct NxRlBucket

consts

40const NX_MAGIC_1000000: i64 = 1000000
41const NX_MAGIC_3600: i64 = 3600
42const NX_MAGIC_86400: i64 = 86400
43const NX_MAGIC_60000: i64 = 60000
44const NX_MAGIC_86400000: i64 = 86400000
58const NX_RL_BUCKET_BYTES: i64 = 56
61const NX_RL_OK: i64 = 0
62const NX_RL_THROTTLED: i64 = 0xFFFFFFFFFFFFFFF5 // -11 / -EAGAIN
63const NX_RL_LOCKED_OUT: i64 = 0xFFFFFFFFFFFFFFE9 // -23 / temporary lockout
64const NX_RL_PERMANENT_LOCK: i64 = 0xFFFFFFFFFFFFFFE8 // -24 / permanent
69const NX_RL_DEFAULT_CAPACITY: i64 = 5
70const NX_RL_DEFAULT_REFILL_PER_MIN: i64 = 5
71const NX_RL_DEFAULT_LOCKOUT_THRESHOLD: i64 = 5
72const NX_RL_PERMANENT_AT: i64 = 100

functions

75func nx_rl_now_ms() -> i64
83func nx_rl_new(capacity: i64, refill_per_sec: i64) -> *NxRlBucket
called by 1: main calls 1: nx_rl_now_ms
97func nx_rl_refill(b: *NxRlBucket) -> i64
called by 1: nx_rl_try_consume calls 1: nx_rl_now_ms
112func nx_rl_try_consume(b: *NxRlBucket) -> i64
called by 1: main calls 2: nx_rl_now_msnx_rl_refill
130func nx_rl_backoff_ms(count: i64) -> i64
called by 2: nx_rl_recordmain
141func nx_rl_record(b: *NxRlBucket, success: i64) -> i64
called by 1: main calls 2: nx_rl_backoff_msnx_rl_now_ms
166func nx_rl_admin_unlock(b: *NxRlBucket) -> i64
called by 1: main calls 1: nx_rl_now_ms
177func main() -> i64