Skip to content

feat(fula-crypto/js): A6b Method-2 recipient bindings (unwrap + owner-file decrypt) — 0.6.19#87

Merged
ehsan6sha merged 4 commits into
mainfrom
feat/collab-recipient-bindings
Jun 26, 2026
Merged

feat(fula-crypto/js): A6b Method-2 recipient bindings (unwrap + owner-file decrypt) — 0.6.19#87
ehsan6sha merged 4 commits into
mainfrom
feat/collab-recipient-bindings

Conversation

@ehsan6sha

Copy link
Copy Markdown
Member

What

Method-2 RECIPIENT-side bindings so the hosted Cloudflare Worker (wasm) can consume a collaboration share without re-implementing any fula:v4 crypto in TypeScript. Sibling of #86's wrap_secret_for_recipient producer.

fula-crypto (sharing.rs) — thin compositions of existing primitives (ShareRecipient::accept_share, Aead, ChunkedDecoder), no new crypto:

  • unwrap_secret_for_recipient → recover the exact 32-byte group link secret
  • describe_shared_file → non-secret framing {chunked, num_chunks, encryption_version}
  • decrypt_shared_file_single_block / _chunked → owner (encType:fula) decrypt, byte-mirroring the native MCP read path (AAD fula:v4:content:{key} / per-chunk fula:v4:chunk:{key}:{i}, share nonce, version-gate tristate)

fula-js (lib.rs) — the 4 wasm bindings (unwrapSecretForRecipient, describeSharedFile, decryptSharedFileSingleBlock, decryptSharedFileChunked), all fail-closed.

read.rs — production read path is UNCHANGED; only a #[cfg(test)] no-drift cross-check was added (native cores vs shared cores must stay byte-identical).

Version bumped 0.6.18 → 0.6.19 (workspace-wide).

Why

The local MCP uses native fula-crypto, but the hosted Worker (wasm) had no way to unwrap a v5 ShareToken → it was fail-closed (rejecting the production token shape). These bindings unblock the Worker (#70).

Verification

  • cargo test -p fula-mcp: 84 lib + 9 KAT pass, incl. the no-drift cross-check (now covering all 3 version arms Some(≥4)/Some(<4)/None) and the new KATs.
  • cargo check -p fula-js --target wasm32-unknown-unknown: clean.
  • cargo check -p fula-flutter: clean (Send+Sync gate).

Review gate

Crypto change reviewed on the actual diff by GLM-5.2 + MiMo v2.5 Pro + built-in advisorunanimous SHIP, zero security / fail-open findings (every fail-closed path verified: key length, recipient binding, tamper, expiry, single-vs-chunked routing, nonce, wasm conversion). Kimi/Codex/Cursor were quota-exhausted today (noted; resets not waitable).

Test-coverage findings (GLM F1/F2) were applied post-review (test-only): the 3-arm no-drift cross-check + KATs for version-downgrade rejection (empirically proving encryption_version is bound in the v5 AAD), empty-plaintext, and single-chunk.

Follow-up (tracked, non-blocking)

  • F3: unify read.rs to call the shared sharing::decrypt_accepted_single_block / assemble_accepted_chunked and delete the private copies (the no-drift cross-check now fully covers the arms, so this is safe to defer).
  • Stage-3 note (Worker): bound num_chunks at the Worker fetch layer (a pathological — but authenticated — token could drive a large fetch loop; native has the same property).

🤖 Generated with Claude Code

ehsan6sha and others added 4 commits June 26, 2026 14:45
…rypt cores

Method-2 RECIPIENT counterparts to wrap_secret_for_recipient (#86) so the hosted Worker (wasm) can consume a collaboration share without re-implementing fula:v4 crypto in TS. Thin compositions of ShareRecipient::accept_share + Aead + ChunkedDecoder (no new crypto): unwrap_secret_for_recipient (recover the exact 32-byte link secret), describe_shared_file (non-secret framing), decrypt_shared_file_single_block/_chunked (owner encType:fula decrypt, byte-mirroring the native read path; fail-closed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tSharedFile* wasm bindings

Method-2 recipient wasm bindings (sibling of wrapSecretForRecipient). Each delegates to the shared fula_crypto::sharing core; fail-closed on bad key length, malformed/expired/tampered/non-addressed token, single-vs-chunked mismatch, or a non-Uint8Array chunk element.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…drift gate

Known-answer tests (fixed vectors, fail-closed coverage) + a no-drift cross-check asserting the native read.rs cores and the shared fula_crypto::sharing cores are byte-identical. Per advisor review (GLM F1/F2) the cross-check covers all 3 version arms (Some>=4 / Some<4 / None) and the KAT adds version-downgrade rejection (encryption_version is in the v5 AAD), empty-plaintext, and single-chunk cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Releases the Method-2 recipient bindings (unwrapSecretForRecipient + owner-file decrypt) for the hosted Worker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ehsan6sha ehsan6sha merged commit 1f06606 into main Jun 26, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant