Proposal: cryptography library (Crypto.*) — SHA-256, HMAC, secure random (save/leaderboard integrity) #19

Closed
opened 2026-08-29 20:22:00 +02:00 by orkun · 1 comment
Owner

Summary

A cryptography library for the handful of security-sensitive things games do:
secure hashing (SHA-256), HMAC/signatures, and secure random bytes. Kept separate
from the fast non-crypto Hash.* library so nobody reaches for the wrong tool.

Why it matters for game devs (occasionally)

  • Anti-cheat-ish save integrity: sign a save/leaderboard payload so casual
    tampering is detectable.
  • Networking: verify a message/token hasn't been forged; challenge-response.
  • Secure IDs / secrets: cryptographically-random tokens.

This is low priority because most games don't need it, and when they do it's
usually a narrow slice. Correctness matters a lot, so it deserves a careful,
unhurried implementation.

Proposed API (illustrative)

# doc-check: skip — illustrative API sketch
let digest = Crypto.sha256(bytes)
let mac    = Crypto.hmac_sha256(key, payload)     # sign a save
let ok     = Crypto.verify_hmac(key, payload, mac)
let token  = Crypto.random_bytes(32)              # CSPRNG
Text.from(Crypto.hex(digest))
  • sha256 (+ maybe sha512, blake3), hmac_sha256, verify_hmac,
    random_bytes (OS CSPRNG), hex/base64 helpers.
  • Constant-time compare for MACs (verify_hmac, not ==).

Considerations

  • Do not roll novel crypto: implement well-specified, test-vector-backed
    standard algorithms only; lean on known-answer tests.
  • Native/C-free is a real constraint here — either implement the primitives in
    Ludic carefully or FFI to the OS crypto where acceptable (decide in the RFC).
  • Be explicit about what this is not: not DRM, not unbeatable anti-cheat
    (a client-side game can't keep secrets from its owner). Document honestly so
    non-experts don't over-trust it.
  • CSPRNG must be OS-backed and kept out of deterministic gameplay RNG.

Scope / acceptance

  • SHA-256 + HMAC-SHA256 + secure random_bytes, all with test vectors.
  • Constant-time verify; hex/base64 helpers.
  • Docs page with honest "what this protects / doesn't" guidance.
  • Tests (known-answer vectors).

Related: Hashing (non-crypto), UUID, networking, Filesystem (signed saves).

## Summary A **cryptography** library for the handful of security-sensitive things games do: secure hashing (SHA-256), HMAC/signatures, and secure random bytes. Kept separate from the fast non-crypto `Hash.*` library so nobody reaches for the wrong tool. ## Why it matters for game devs (occasionally) - **Anti-cheat-ish save integrity**: sign a save/leaderboard payload so casual tampering is detectable. - **Networking**: verify a message/token hasn't been forged; challenge-response. - **Secure IDs / secrets**: cryptographically-random tokens. This is **low priority** because most games don't need it, and when they do it's usually a narrow slice. Correctness matters a lot, so it deserves a careful, unhurried implementation. ## Proposed API (illustrative) ```ludic # doc-check: skip — illustrative API sketch let digest = Crypto.sha256(bytes) let mac = Crypto.hmac_sha256(key, payload) # sign a save let ok = Crypto.verify_hmac(key, payload, mac) let token = Crypto.random_bytes(32) # CSPRNG Text.from(Crypto.hex(digest)) ``` - `sha256` (+ maybe `sha512`, `blake3`), `hmac_sha256`, `verify_hmac`, `random_bytes` (OS CSPRNG), hex/base64 helpers. - **Constant-time compare** for MACs (`verify_hmac`, not `==`). ## Considerations - **Do not roll novel crypto**: implement well-specified, test-vector-backed standard algorithms only; lean on known-answer tests. - Native/C-free is a real constraint here — either implement the primitives in Ludic carefully or FFI to the OS crypto where acceptable (decide in the RFC). - Be explicit about what this is **not**: not DRM, not unbeatable anti-cheat (a client-side game can't keep secrets from its owner). Document honestly so non-experts don't over-trust it. - CSPRNG must be OS-backed and kept out of deterministic gameplay RNG. ## Scope / acceptance - [ ] SHA-256 + HMAC-SHA256 + secure `random_bytes`, all with test vectors. - [ ] Constant-time verify; hex/base64 helpers. - [ ] Docs page with honest "what this protects / doesn't" guidance. - [ ] Tests (known-answer vectors). Related: Hashing (non-crypto), UUID, networking, Filesystem (signed saves).
orkun added the
proposal
priority:low
area:stdlib
labels 2026-08-29 20:22:00 +02:00
Author
Owner

Done in a4f1494 (commit 2ddf830).

The cryptography library is complete:

  • SHA-256 (Crypto.sha256), HMAC-SHA256 (Crypto.hmac_sha256), and constant-time verify_hmac were already in place; this adds the OS CSPRNG surface — Crypto.random_bytes(n) / random_hex(n) (reading /dev/urandom, returned as hex since a str can't hold NUL) and Crypto.random_u32() — plus a standard base64 encoder (Crypto.base64, RFC 4648).
  • All pure integer IR, C-free, bit-identical across platforms.
  • The CSPRNG helpers are explicitly non-deterministic and documented as such (must never seed the lockstep Random.* sim RNG).

Acceptance:

  • SHA-256 + HMAC-SHA256 + secure random_bytes, all with test vectors
  • Constant-time verify; hex/base64 helpers
  • Docs page with honest "what this protects / doesn't" guidance
  • Tests (known-answer vectors)

Tests: examples/library/crypto.ludic checks SHA-256 (FIPS 180-4), HMAC-SHA256 (RFC 4231 case 2), and base64 (RFC 4648) against published vectors, plus the CSPRNG shape — wired into x test. Docs: per-symbol pages under docs/language/crypto/.

Not in scope for v1 (can be follow-ups if a concrete need appears): sha512/blake3, and an OS-native CSPRNG binding on wasm (the read degrades to zeroes there, documented).

Done in a4f1494 (commit `2ddf830`). The cryptography library is complete: - **SHA-256** (`Crypto.sha256`), **HMAC-SHA256** (`Crypto.hmac_sha256`), and **constant-time `verify_hmac`** were already in place; this adds the **OS CSPRNG surface** — `Crypto.random_bytes(n)` / `random_hex(n)` (reading `/dev/urandom`, returned as hex since a `str` can't hold NUL) and `Crypto.random_u32()` — plus a standard **base64** encoder (`Crypto.base64`, RFC 4648). - All pure integer IR, C-free, bit-identical across platforms. - The CSPRNG helpers are explicitly **non-deterministic** and documented as such (must never seed the lockstep `Random.*` sim RNG). **Acceptance:** - [x] SHA-256 + HMAC-SHA256 + secure `random_bytes`, all with test vectors - [x] Constant-time verify; hex/base64 helpers - [x] Docs page with honest "what this protects / doesn't" guidance - [x] Tests (known-answer vectors) Tests: `examples/library/crypto.ludic` checks SHA-256 (FIPS 180-4), HMAC-SHA256 (RFC 4231 case 2), and base64 (RFC 4648) against published vectors, plus the CSPRNG shape — wired into `x test`. Docs: per-symbol pages under `docs/language/crypto/`. Not in scope for v1 (can be follow-ups if a concrete need appears): sha512/blake3, and an OS-native CSPRNG binding on wasm (the read degrades to zeroes there, documented).
orkun closed this issue 2026-08-30 20:58:26 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: workshopsoft/ludic#19
No description provided.