cipher: std/cipher with ChaCha20-Poly1305 (RFC 8439) #264
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
std/cipher: ChaCha20-Poly1305 authenticated encryption (RFC 8439) in TorbScript, with the RFC's test vectors. The registry needs it to store TOTP seeds encrypted (#227);stdhas no authenticated cipher today (mbedTLS's ChaCha20-Poly1305 is used inside TLS only and is not reachable from TorbScript).Why a std slice and not a private registry module
Decided in refine of #227: a cipher is not registry logic. It has published vectors (RFC 8439 sections 2.1 to 2.8 and appendix A), so it can be tested on its own, and
tools/registry/src/rsa.trbanded25519show the cost of the other path: a primitive written privately has to be moved later (FIRST-PARTY.md section 8, row 6; #110). It also takes the cipher out of #227, which is already one PR of TOTP, recovery codes, rate limit, account page and tests.Pinned records
std/signature(package layout,SignatureError, test and docs layout) andstd/digest(Bytes,constantTimeEqual).Acceptance criteria
std/cipher(directorystd/cipher,project.trbwithname = "std/cipher",src/lib.trb,tests/); the workspace member globstd/*already covers it.ChaCha20Poly1305, a value keyed with exactly 32 bytes (ChaCha20Poly1305.tryFrom(key)-style constructor in the style ofstd/signature's key types; a wrong length is aCipherError.WrongLength), with methodsseal(nonce, plaintext, associated)(answers ciphertext followed by the 16-byte tag) andopen(nonce, sealed, associated)(answers the plaintext, orCipherError.Forgedfor any failure of the tag, with no detail of where it differs); the nonce is exactly 12 bytes. Methods, not free functions (#146).std/digest'sconstantTimeEqual);openreleases no plaintext before the tag is checked.torb test std/cipher/testsgreen natively and in the VM.docs/standard-library/cipher.mdand the index ofdocs/standard-library/document the new types and say: a nonce must never repeat under one key (random 96-bit nonces are safe for up to about 2^32 messages per key), what is and is not constant time (the tag comparison is; the arithmetic is plainIntand promises nothing more), and the measured speed for a 32-byte message and for 1 MiB in the VM and natively;skills/regenerated (docs skill).Seed impact
None: a new std package in plain TorbScript over
Int/UInt32arithmetic andstd/digest'sconstantTimeEqual. No syntax change, no native, no runtime change, no driver flag, and the compiler looks up none of the new names by string. Additive only; no seed refresh, so no two-commit rule.Size and dependencies
One PR, one
feat(std/cipher)commit (code, tests, docs). No dependency. Blocks #227. Security-relevant: architect review of the diff.[loop:torbscript] intake: in scope (author orion, label loop), split out of #227 by its refine (cipher as its own std slice), not a duplicate, no seed impact, no dependency, blocks #227. Body already meets the definition of ready; implementation is security-relevant (sonnet/medium for std, architect review of the diff). next: refine (confirm and label ready)
[loop:torbscript] refine: the body written by the refine of #227 meets the definition of ready (goal, testable criteria with RFC 8439 vectors, pinned records, no seed impact, one PR). Set
ready. next: ready (implement)[loop:torbscript] claim implement by session:loop-torbscript-20261009 until 2026-10-09T17:10Z
const r: RingList<Int> = [1, 2]) #212[loop:torbscript] release implement: the implementation worker ended after about 23 minutes before committing, no branch pushed and no PR opened, nothing to salvage. next: implement (re-dispatch on the next tick)
[loop:torbscript] claim implement by session:loop-torbscript-20261009 until 2026-10-09T17:40Z
[loop:torbscript] implement: progress - PR #266 is open, argus requested. Fixed the declaration block (Encode) that the docs gate refused; the previous tier A also failed in a language-server test that fails on main too (
90e233aa), so I rebased onto current main (2a1d8ae3) and CI runs again. Still holding the claim until CI is read.[loop:torbscript] release implement: PR #266 approved and merged by argus (2026-10-09T13:53Z, merge commit
2a1d8ae3); this issue closed by the merge. No release or deploy step in the PR. Consumer #227 can now use std/cipher. next: none for #264[loop:torbscript] implement: PR #266, CI green (pull_request run on
2a1d8ae3: gates, tier A, bootstrap, same-C, playground, seed pack), next: review (waiting on the merge gate argus)Token usage: not reported by the worker session (two sessions; the first ended without a push); an architect review of the diff ran before the PR and its blocking finding (derived Encode leaked the key) is fixed.
[loop:torbscript] close: PR #266 approved and merged by argus as
2a1d8ae3; main CI green (tier B red on2a1d8ae3was the unrelated child-close race #270, fixed by #271, main green on0a129c2e). Claim released.