Commit Graph

2 Commits

Author SHA1 Message Date
Claude cd12018e08 test(marmot): add ts-mls interop vector + decryptor
marmot-ts (the TypeScript Marmot client — browsers, Node, Bun, Deno)
wraps a completely different MLS implementation: ts-mls. That backend
shares no code with OpenMLS, which is what MDK/whitenoise use, so
Amethyst passing on both is a strong signal that the on-wire MLS layer
is spec-correct rather than coincidentally self-consistent.

Add a Node-based generator under quartz/tools/tsmls-vector-gen/ that
uses ts-mls 2.0.0-rc.10 directly to emit:
  - Alice's KeyPackage + Bob's joiner KeyPackage
  - Alice's Welcome after add_member + commit
  - Bob's init/encryption/signature private keys (PKCS#8 Ed25519 unwrapped
    to the raw 32-byte seed for parity with the MDK vector shape)
  - Post-join MLS-Exporter("marmot","group-event",32) KAT
  - Three application PrivateMessages from Alice → Bob with the
    expected plaintexts

TsMlsWelcomeInteropTest mirrors MdkWelcomeInteropTest but consumes the
new vector. It proves:
  - KeyPackage self-signature verifies under our Ed25519 + SignContent.
  - Amethyst.processWelcome unwraps the group secrets, derives the
    welcome_key/nonce, AEAD-decrypts GroupInfo, verifies GroupInfoTBS
    with signer_pub, decodes the ratchet tree, and binds the joiner's
    leaf — end-to-end.
  - Post-join exporter secret matches ts-mls byte-for-byte.
  - Amethyst decrypt() parses the RFC 9420 §6.3.1 PrivateMessageContent
    framing (application_data<V> + FramedContentAuthData.signature<V> +
    zero padding) and verifies the sender's FramedContentTBS signature
    against Alice's leaf, for all three ciphertexts.

https://claude.ai/code/session_01HfHdd5S5rvxUW2ihEpLGJr
2026-04-21 13:34:32 +00:00
Claude 91f5d21cc3 test(marmot): MDK-authored Welcome interop vector + decryptor
Add a Rust generator under quartz/tools/mdk-vector-gen that emits a
Welcome, joiner KeyPackage, committer signer_pub, joiner's three
private keys, and a post-join MLS-Exporter KAT, using the same
openmls 0.8 backend MDK / whitenoise use. Commit its output at
quartz/src/commonTest/resources/mls/mdk-welcome.json.

MdkWelcomeInteropTest consumes the vector and proves Amethyst can:
  - parse a KeyPackage OpenMLS authored and verify its self-signature;
  - run the joiner's processWelcome end-to-end (HPKE unwrap of group
    secrets, welcome-key derivation, AEAD GroupInfo decrypt, ratchet
    tree decode, signer leaf lookup, GroupInfoTBS Ed25519 verify);
  - derive MLS-Exporter("marmot", "group-event", 32) byte-for-byte
    identically to openmls — the exact exporter Marmot uses for the
    outer ChaCha20 wrap on kind:445 events.

testBobDecryptsMdkApplicationMessagesFromAlice is @Ignored with a
detailed TODO because Amethyst's MlsGroup.encrypt/decrypt skip the
RFC 9420 §6.3.1 PrivateMessageContent framing (application_data<V> +
FramedContentAuthData + padding). Amethyst ↔ Amethyst works (both
sides omit it) but every cross-implementation PrivateMessage fails.
Tracked as a follow-up.

https://claude.ai/code/session_01HfHdd5S5rvxUW2ihEpLGJr
2026-04-21 05:04:41 +00:00