Files
LumaWeb/docs/decisions/0003-crypto-library.md
T
wt 30f7f222d2 S00-021: Record verified browser OMEMO backend blocker for S00-004
Changes:
- Re-ran both committed probes unchanged (smoke exit 0 SMOKE_PASS; wasm-unsupported exit 2 UNSUPPORTED_BLOCKER) and recorded actual outputs in state/evidence/S00-021-auto-crypto-fcef9b6781bf.md.
- Verified on the reachable npm proxy that no maintained browser/WASM-capable OMEMO2 package exists: @signalapp/libsignal-client 0.105.0 is native-only (zero .wasm); @signalapp/libsignal, omemo-client, omemo-top, omemo-wasm, @converse/omemo are all E404.
- Wrote docs/decisions/0003-crypto-library.md (proposed) documenting the verified audited session/ratchet + persistence capability and the honest blocker for the browser/worker/WASM endpoint and OMEMO2 wire layer, with traceable primary sources.
- Wrote state/handoffs/S00-021.md with the reproducible next step for the S00-004 continuation.

Validation:
- smoke.mjs -> exit 0 (SMOKE_PASS, 631-byte record byte-for-byte reload).
- wasm-unsupported.mjs -> exit 2 (wasmFiles 0, native prebuilds only).
- npm view E404s confirmed against the same proxy that returns @signalapp/libsignal-client 0.105.0, so responses are genuine.
- make check: 72 tooling tests passed (OK).
- No source changes outside scope: experiments/** unchanged; only state/tasks.json (workflow metadata) plus the in-scope ADR. S00-004 stays blocked (honest blocker), not bypassed.

Task: S00-021
Agent: auto-crypto-fcef9b6781bf
Role: crypto
Action: claim
Status: review

Task title: Устранить прерывание: Проверить browser OMEMO backend
2026-10-15 15:38:49 +07:00

8.3 KiB

ADR 0003: OMEMO session/ratchet engine and browser backend feasibility

  • Status: proposed
  • Task: S00-004, remediation S00-021.
  • Date: 2026-10-15.
  • Decision owner: auto-crypto-fcef9b6781bf (crypto).
  • Reviewer: security (separate agent for S00-021 review).
  • Requirements: ENC-003, ENC-009, ENC-011.

Context and required capabilities

Input: immutable ENC-003 (legacy OMEMO and OMEMO 2 wire formats with compatible device lists/bundles and identity/session lifecycle), ENC-009 (encryption runs in the client endpoint with proven implementations and compatible vectors; no homegrown algorithm, no server-side decryption, no treating shared storage as proven interoperability), and ENC-011 (OMEMO 2 wire format by an approved compatible revision with SCE and payload/key/MAC rules; not replaced by media AES-GCM). Also the accepted scope (ADR 0000), stack (ADR 0001) and reviewer decisions S00-001/S00-002, plus the S00-004 blocker report and handoff.

Output is one focused probe record and this ADR (proposed) establishing what is verifiably feasible today for a Web client: an audited session/ratchet engine with secure session-record persistence, and the honest boundary for the browser/worker/WASM endpoint and the OMEMO2 wire layer. Acceptance requires a real library/backend, verified vectors, no homegrown ratchet, and any unsupported format recorded as a blocker (not success).

Candidates and primary sources

Primary public sources and exact reachable-registry records retrieved 2026-10-15 via the configured npm proxy. These sources establish library and distribution boundaries; none of them is treated as a tested product integration.

Candidate Reachable registry License Browser/WASM reality
@signalapp/libsignal-client@0.105.0 exists AGPL-3.0-only Node native addon (dist/Native.js uses node-gyp-build; prebuilds/*/*.node). No .wasm asset ships; cannot execute in a browser worker.
@signalapp/libsignal 404 Not Found — Signal's TypeScript/WASM web distribution is not published to the reachable npm registry; npm view @signalapp/libsignal version returns E404.
omemo-client 404 Not Found — not on reachable registry
omemo-top 404 Not Found — not on reachable registry
omemo-wasm 404 Not Found — not on reachable registry
@converse/omemo 404 Not Found — not on reachable registry

Sources:

  • signalapp/libsignal repository package.json defines the Node distribution of the libsignal client (native bridge).
  • Signal documentation on libsignal WASM/web: the library is compiled to WebAssembly for Signal's browser clients, but that artifact is produced from source into the Signal client builds; it is not shipped as a maintained standalone @signalapp/libsignal npm package on the reachable registry (E404, queried 2026-10-15).
  • The exact registry records were queried with npm view <pkg> version; results (version or E404) are captured in evidence: state/evidence/S00-021-auto-crypto-fcef9b6781bf.md.

Focused experiment and actual result

The previously committed probes inside experiments/0003-crypto-library/session-probe/ were reproduced unchanged from the S00-004 handoff (this run re-ran both, actual exit codes recorded below):

  1. node experiments/0003-crypto-library/session-probe/smoke.mjs — exit 0, SMOKE_PASS. A real A/B pair using @signalapp/libsignal-client sealed-sender APIs established a PreKey session, round-tripped the known plaintext known vector: OMEMO session smoke, stored a 631-byte session record and reloaded it byte-for-byte. This verifies an audited session/ratchet engine and session-record persistence without any homegrown ratchet; it mirrors Signal canonical in-memory store semantics.
  2. node experiments/0003-crypto-library/session-probe/wasm-unsupported.mjs — exit 2. Inspects the installed package: wasmFiles: 0; prebuilds are darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-arm64, win32-x64 native *.node files; dist/Native.js loads via node-gyp-build. This confirms that the shipped artifact cannot run in a browser worker/WASM endpoint, and the distribution ships no .wasm asset.

Result: the audited session/ratchet engine and persistence are verified; the browser/worker/WASM deployment and the OMEMO/OMEMO2 XMPP wire layer are not established by any maintained package on the reachable registry. Per focused check "unsupported format recorded blocker, not success", this is recorded as a blocker, not as an achieved capability.

Decision

Adopt @signalapp/libsignal-client only as the audited session/ratchet engine and session-record persistence primitive for the Node-side spike and downstream adapters that can run a native/external environment, and keep it as the verified evidence that an audited library (not a homegrown ratchet) supplies the whistler/session layer and durable session-records.

Record as a blocker on S00-004 that the browser/worker/WASM endpoint and the OMEMO2 wire-format layer are not available from any maintained package on the reachable registry, and that @signalapp/libsignal (the WASM distribution) is not published there. This remediation does not replace the missing browser backend with a homemade ratchet, does not reuse the shared Node session store as if it proved browser interoperability (ENC-009), and does not pretend the unsupported OMEMO2 wire layer is complete. The correct next step for S00-004's continued execution is: (a) obtain a verified browser/WASM-capable OMEMO2 backend (a distribution with a real .wasm/web build and an OMEMO2/S ce-format mapping) or (b) escalate with traceable upstream primary sources resolving ENC-009/ENC-011 client-endpoint encryption for the browser transport.

License / security / browser constraints

@signalapp/libsignal-client is AGPL-3.0-only. Its AGPL-3.0 obligations apply if the library (or modified copies) is distributed. Its official notices and license are bundled in node_modules/@signalapp/libsignal-client and its acknowledgments; the reader is referred to the package license text and the Signal acknowledgments file before any redistribution. AGPL compatibility with the eventual product distribution decision is a separate review item for the accepted stack/licensing tasks.

Browser constraints (from the accepted stack ADR 0001 and Web profile): the absent WASM distribution is a hard capability boundary here — no .wasm asset to instantiate in a worker. No plaintext fallback, no spy/decrypt bypass, and no server-side decryption path is introduced. Any real OMEMO2 wire mapping must be produced from approved primary sources and preserve ENC-009/ENC-011 client-endpoint encryption; media/transport AES-GCM alone does not satisfy ENC-011.

Consequences and downstream contract

  • S00-004's acceptance requires legacy/OMEMO2 AND worker/wasm AND persistence. Two of the three (browser/WASM and the OMEMO2 wire layer) remain unresolved and are recorded here as a blocker; only persistence + audited ratchet/session are established. A new executor of S00-004 must not declare it done on this basis (it would bypass the requirements).
  • Any crypto boundary contract (planned docs/contracts/crypto.md, S12 tasks) must key off a verified, maintained library and real vectors; it must not assume a browser/WASM OMEMO2 primitive that is still absent.
  • No shared contract, plan definition, requirement snapshot or spec file is changed by this ADR.

Rejected alternatives and migration trigger

  1. Hand-write the Double Ratchet or OMEMO2 wire format. Rejected: forbidden by ENC-009 (no homegrown algorithm/primitive replacement) and the crypto role constraints.
  2. Reuse the Node session store as "interoperability". Rejected: ENC-009 forbids treating shared session storage as proof of interoperability; it is a persistence spike only.
  3. Declare @signalapp/libsignal-client a full browser backend. Rejected: verified native-only, zero .wasm; would be a false success.

Migration/continuation trigger: a verified browser/WASM-capable OMEMO2 package or a resolved, traceable upstream path that satisfies ENC-009/ENC-011 becomes available; then S00-004 (or its assigned continuation) may be re-run and the browser-capable backend validated with known vectors in the web target before acceptance.