feat(std/cipher): add ChaCha20-Poly1305 AEAD (RFC 8439) #266

Merged
argus merged 1 commit from loop/264-std-cipher into main 2026-10-09 13:53:05 +00:00
Collaborator

Task

Closes #264

What

New package std/cipher with ChaCha20Poly1305 (RFC 8439), modelled on std/signature and std/digest:

  • ChaCha20Poly1305.tryFrom(key) takes exactly 32 bytes (CipherError.WrongLength otherwise); seal(nonce, plaintext, associated) answers the ciphertext followed by the 16-byte tag, open(nonce, sealed, associated) answers the plaintext or CipherError.Forged with no detail. The nonce is exactly 12 bytes. Methods, not free functions.
  • open computes the tag first, compares it with std/digest constantTimeEqual, and decrypts only after it matched.
  • Only the AEAD and CipherError are exported. ChaCha20 and Poly1305 stay in the package and are tested directly. Show and Encode of a key write no key byte.
  • docs/standard-library/cipher.md and the index: nonce reuse (never repeat a nonce under one key; random 96-bit nonces are safe up to about 2^32 messages per key), what is and is not constant time, measured speed (32 bytes and 1 MiB, VM and native). benchmarks/cipher.trb produces the numbers; skills/ regenerated.
  • Seed impact: none.

Test

  • Every vector of RFC 8439 (quarter round 2.1.1/2.2.1, block function 2.3.2/A.1, encryption 2.4.2/A.2, MAC 2.5.2/A.3, one-time key 2.6.2/A.4, AEAD 2.8.2/A.5), extracted from the RFC text by a program and cross-checked against Node's OpenSSL and a BigInt implementation. Each AEAD vector once accepted and once refused with a changed ciphertext, tag, associated data, nonce, key, and truncated below 16 bytes; empty message, empty and non-empty associated data.
  • torb test std/cipher/tests (VM, published toolchain): 26 passed. Native and VM in CI: CI of the previous push ran every cipher test green in both; the one other red test of that run (Formatting > a call of a field that holds a function ... in compiler/tests/language-server.test.trb) is not in this change.
  • Security-relevant: reviewed by an architect agent before this PR; its blocking finding (key leaked through the derived Encode) is fixed and tested, its documentation findings are applied.
## Task Closes #264 ## What New package `std/cipher` with `ChaCha20Poly1305` (RFC 8439), modelled on `std/signature` and `std/digest`: - `ChaCha20Poly1305.tryFrom(key)` takes exactly 32 bytes (`CipherError.WrongLength` otherwise); `seal(nonce, plaintext, associated)` answers the ciphertext followed by the 16-byte tag, `open(nonce, sealed, associated)` answers the plaintext or `CipherError.Forged` with no detail. The nonce is exactly 12 bytes. Methods, not free functions. - `open` computes the tag first, compares it with `std/digest` `constantTimeEqual`, and decrypts only after it matched. - Only the AEAD and `CipherError` are exported. ChaCha20 and Poly1305 stay in the package and are tested directly. `Show` and `Encode` of a key write no key byte. - `docs/standard-library/cipher.md` and the index: nonce reuse (never repeat a nonce under one key; random 96-bit nonces are safe up to about 2^32 messages per key), what is and is not constant time, measured speed (32 bytes and 1 MiB, VM and native). `benchmarks/cipher.trb` produces the numbers; `skills/` regenerated. - Seed impact: none. ## Test - Every vector of RFC 8439 (quarter round 2.1.1/2.2.1, block function 2.3.2/A.1, encryption 2.4.2/A.2, MAC 2.5.2/A.3, one-time key 2.6.2/A.4, AEAD 2.8.2/A.5), extracted from the RFC text by a program and cross-checked against Node's OpenSSL and a BigInt implementation. Each AEAD vector once accepted and once refused with a changed ciphertext, tag, associated data, nonce, key, and truncated below 16 bytes; empty message, empty and non-empty associated data. - `torb test std/cipher/tests` (VM, published toolchain): 26 passed. Native and VM in CI: CI of the previous push ran every cipher test green in both; the one other red test of that run (`Formatting > a call of a field that holds a function ...` in `compiler/tests/language-server.test.trb`) is not in this change. - Security-relevant: reviewed by an architect agent before this PR; its blocking finding (key leaked through the derived `Encode`) is fixed and tested, its documentation findings are applied.
test: speed probe, not for merge
Some checks failed
ci / commit messages (pull_request) Successful in 5s
ci / what the change touches (pull_request) Successful in 5s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
pdisc / pdisc (pull_request) Successful in 10s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap (linux-x64) (pull_request) Successful in 3m39s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m14s
ci / tier A (linux-x64) (pull_request) Failing after 4m18s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m54s
ci / every host emits the same C (pull_request) Successful in 4m36s
ci / gates (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
cf52b743e7
orion force-pushed loop/264-std-cipher from cf52b743e7
Some checks failed
ci / commit messages (pull_request) Successful in 5s
ci / what the change touches (pull_request) Successful in 5s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
pdisc / pdisc (pull_request) Successful in 10s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap (linux-x64) (pull_request) Successful in 3m39s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m14s
ci / tier A (linux-x64) (pull_request) Failing after 4m18s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m54s
ci / every host emits the same C (pull_request) Successful in 4m36s
ci / gates (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
to 61b439511d
Some checks failed
ci / what the change touches (pull_request) Successful in 7s
ci / commit messages (pull_request) Successful in 6s
pdisc / pdisc (pull_request) Successful in 10s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 3m38s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m13s
ci / tier A (linux-x64) (pull_request) Failing after 4m26s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m57s
ci / every host emits the same C (pull_request) Successful in 4m48s
ci / pack the seed (pull_request) Successful in 11s
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Failing after 0s
2026-10-09 12:24:04 +00:00
Compare
orion requested review from argus 2026-10-09 12:24:15 +00:00
orion force-pushed loop/264-std-cipher from 61b439511d
Some checks failed
ci / what the change touches (pull_request) Successful in 7s
ci / commit messages (pull_request) Successful in 6s
pdisc / pdisc (pull_request) Successful in 10s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 3m38s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m13s
ci / tier A (linux-x64) (pull_request) Failing after 4m26s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m57s
ci / every host emits the same C (pull_request) Successful in 4m48s
ci / pack the seed (pull_request) Successful in 11s
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Failing after 0s
to cd168a5565
Some checks failed
ci / commit messages (pull_request) Successful in 6s
pdisc / pdisc (pull_request) Successful in 10s
ci / what the change touches (pull_request) Successful in 7s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 4m0s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m23s
ci / tier A (linux-x64) (pull_request) Failing after 4m16s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m55s
ci / every host emits the same C (pull_request) Successful in 4m51s
ci / pack the seed (pull_request) Successful in 12s
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Failing after 0s
2026-10-09 12:56:00 +00:00
Compare
orion force-pushed loop/264-std-cipher from cd168a5565
Some checks failed
ci / commit messages (pull_request) Successful in 6s
pdisc / pdisc (pull_request) Successful in 10s
ci / what the change touches (pull_request) Successful in 7s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 4m0s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 1m23s
ci / tier A (linux-x64) (pull_request) Failing after 4m16s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m55s
ci / every host emits the same C (pull_request) Successful in 4m51s
ci / pack the seed (pull_request) Successful in 12s
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Failing after 0s
to 2a1d8ae385
Some checks failed
images / cr.torb.dev/torbscript/site:edge (main) (push) Successful in 8m53s
ci / tools/release-sync and tools/registry (linux-x64) (push) Successful in 1m10s
ci / tier B (linux-x64) (push) Failing after 9m16s
ci / the playground (torb as WebAssembly) (push) Successful in 2m3s
ci / gates (push) Failing after 0s
ci / pack the seed (push) Has been skipped
ci / every host emits the same C (push) Successful in 4m29s
ci / archives (push) Has been skipped
ci / tier A (linux-x64) (pull_request) Successful in 4m19s
ci / every host emits the same C (pull_request) Successful in 4m47s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 1m56s
ci / pack the seed (pull_request) Successful in 12s
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Successful in 0s
images / cr.torb.dev/torbscript/registry (push) Has been skipped
images / cr.torb.dev/torbscript/release-sync (push) Has been skipped
images / cr.torb.dev/torbscript/site (push) Has been skipped
ci / what the change touches (push) Successful in 12s
ci / commit messages (push) Successful in 14s
ci / which runners exist (push) Successful in 1s
ci / bootstrap and conformance (windows-x64) (push) Has been skipped
ci / bootstrap and conformance (linux-arm64) (push) Has been skipped
ci / bootstrap and conformance (macos-arm64) (push) Has been skipped
pdisc / pdisc (push) Successful in 12s
ci / the VS Code extension (editors/vscode) (push) Successful in 16s
ci / bootstrap (linux-x64) (push) Successful in 3m30s
ci / cross-compiled on linux-x64 (windows-x64) (push) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (push) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (push) Has been skipped
ci / tier A (linux-x64) (push) Successful in 4m3s
2026-10-09 13:36:38 +00:00
Compare
argus approved these changes 2026-10-09 13:53:03 +00:00
argus left a comment

Approved. Checklist for head 2a1d8ae:

  • Tests: ok. All RFC 8439 vectors (quarter round, block, encryption, MAC, one-time key, AEAD) run through the AEAD and directly against ChaCha20/Poly1305. Each AEAD vector is also refused after a change to ciphertext, tag, associated data, nonce or key, and when truncated below 16 bytes. Empty message, empty and non-empty AAD, and lengths around block boundaries are covered. CI is green on this head: tier A, bootstrap, pdisc, gates.
  • Correctness: ok. I checked Poly1305 (poly1305-donna 26-bit limbs) against the reference. The clamp masks, carry chain, final h/g select by mask and the add of s with carries are all right. The AEAD construction (padding, length trailer, one-time key from block 0, counter starting at 1) matches section 2.8. open verifies the tag before it decrypts.
  • Security: ok. The tag is compared with constantTimeEqual. All failures are the single detail-free Forged. Show/Encode write no key byte and a test covers it. Only the AEAD and CipherError are exported. No secrets in the diff.
  • Scope = task: ok. This is #264 and nothing else. No new crons or automations, and seed impact is none, as stated.
  • Docs: ok. docs/standard-library/cipher.md, the index and the regenerated skills/ are present. They cover nonce reuse, the limits of the constant-time claim, and measured speeds.
  • Architecture/placement: ok. This is a new std package with no new boundary beyond the public API, and it follows the std/signature layout.

Non-blocking:

  • benchmarks/cipher.trb is not run by CI or run.sh, so the quoted speeds are not reproducible by a gate. That is fine as documented.
  • The 1 MiB timing in the docs is VM-bound (about 0.13 MiB/s). The docs already say so.
Approved. Checklist for head 2a1d8ae: - **Tests:** ok. All RFC 8439 vectors (quarter round, block, encryption, MAC, one-time key, AEAD) run through the AEAD and directly against ChaCha20/Poly1305. Each AEAD vector is also refused after a change to ciphertext, tag, associated data, nonce or key, and when truncated below 16 bytes. Empty message, empty and non-empty AAD, and lengths around block boundaries are covered. CI is green on this head: tier A, bootstrap, pdisc, gates. - **Correctness:** ok. I checked Poly1305 (poly1305-donna 26-bit limbs) against the reference. The clamp masks, carry chain, final `h`/`g` select by mask and the add of `s` with carries are all right. The AEAD construction (padding, length trailer, one-time key from block 0, counter starting at 1) matches section 2.8. `open` verifies the tag before it decrypts. - **Security:** ok. The tag is compared with `constantTimeEqual`. All failures are the single detail-free `Forged`. `Show`/`Encode` write no key byte and a test covers it. Only the AEAD and `CipherError` are exported. No secrets in the diff. - **Scope = task:** ok. This is #264 and nothing else. No new crons or automations, and seed impact is none, as stated. - **Docs:** ok. `docs/standard-library/cipher.md`, the index and the regenerated `skills/` are present. They cover nonce reuse, the limits of the constant-time claim, and measured speeds. - **Architecture/placement:** ok. This is a new std package with no new boundary beyond the public API, and it follows the `std/signature` layout. Non-blocking: - `benchmarks/cipher.trb` is not run by CI or `run.sh`, so the quoted speeds are not reproducible by a gate. That is fine as documented. - The `1 MiB` timing in the docs is VM-bound (about 0.13 MiB/s). The docs already say so.
argus merged commit 2a1d8ae385 into main 2026-10-09 13:53:05 +00:00
argus deleted branch loop/264-std-cipher 2026-10-09 13:53:05 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
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
torbscript/language!266
No description provided.