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
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# mdk-vector-gen
|
||||
|
||||
Rust helper that emits MLS interop test vectors from the same openmls 0.8
|
||||
backend MDK/whitenoise uses. Produces `quartz/src/commonTest/resources/mls/mdk-welcome.json`,
|
||||
which [`MdkWelcomeInteropTest`] consumes to prove Amethyst can parse and
|
||||
decrypt a Welcome + application messages authored by the Rust side.
|
||||
|
||||
## What the vector contains
|
||||
|
||||
- `joiner.init_priv` / `encryption_priv` / `signature_priv` / `signature_pub` —
|
||||
all the private key material the joiner needs to drive
|
||||
`MlsGroup.processWelcome`.
|
||||
- `joiner.key_package` (MlsMessage-wrapped) and `key_package_raw`.
|
||||
- `welcome` (MlsMessage-wrapped) — Alice's Welcome for Bob.
|
||||
- `committer.signer_pub` — Alice's Ed25519 signature public key.
|
||||
- `exporter.{label,context,length,secret}` — `MLS-Exporter("marmot",
|
||||
"group-event", 32)` derived from Bob's post-join state. This is the
|
||||
exporter Marmot uses to derive the outer ChaCha20 key for kind:445
|
||||
events, so a match here means Amethyst's whole post-join key schedule
|
||||
agrees with openmls byte-for-byte.
|
||||
- `app_messages_alice_to_bob[]` — Alice-sent PrivateMessage bytes plus
|
||||
the expected plaintext. (Amethyst decrypt currently skips
|
||||
`PrivateMessageContent` framing; the matching test is `@Ignore`d
|
||||
until that is fixed.)
|
||||
|
||||
## Regenerating
|
||||
|
||||
```
|
||||
cd quartz/tools/mdk-vector-gen
|
||||
cargo run --release > ../../src/commonTest/resources/mls/mdk-welcome.json
|
||||
```
|
||||
|
||||
The generator uses fresh randomness each run, so the committed vector
|
||||
changes on regeneration — that is fine because the Kotlin test only
|
||||
asserts round-trip correctness against whatever is in the JSON. Commit
|
||||
the regenerated file if you change the generator.
|
||||
Reference in New Issue
Block a user