🏗️ Starting the Meeting
Creating an MLS Group
In 15 minutes: Learn to create your first MLS group
Prerequisite: Welcome messages
🎯 The Simple Story
Alice wants to create a secure group chat with MLS.
She's like creating a "Secret Meeting Room" where:
- She's the first one inside
- She decides who can join
- She has the master key
Let's see how this works
🧠 Mental Model
Hold this picture in your head:
Creating an MLS Group:
Step 1: Alice prepares (key package)
└─ Generate key package (ID card)
Step 2: Alice creates room
└─ Initialize MLS manager (create group)
Step 3: Room is ready
└─ Has ratchet tree, group secret, epoch 0
└─ Alice inside (index 0)
Step 4: Alice waits for others
└─ Can send messages to empty room?
└─ Or wait for members to join
Result: Secret meeting room created
📊 See It Happen
🎭 Code: Creating a Group
Step 1: Initialize MLS Manager
import { MLSManager } from 'ts-mls';
// Alice's code
const alice = new MLSManager('alice@example.com');
// Step 1: Initialize with ciphersuite
await alice.initialize();
What this does:
- Creates MLS manager for Alice
- Chooses ciphersuite (crypto algorithm)
- Sets up crypto provider
Step 2: Generate Key Package
// Step 2: Generate key package (Alice's ID card)
const aliceKeyPackage = await alice.generateKeyPackage();
// Alice shares her key package public part
const aliceKeyPackagePublic = aliceKeyPackage.publicPackage;
What this does:
- Generates key package for Alice
- Public part: Can share with anyone
- Private part: Alice keeps secret
- Used by others to encrypt for Alice
Step 3: Create the Group
// Step 3: Create the group
const groupInfo = await alice.createGroup('team-chat');
console.log('Group created');
console.log('Group ID:', groupInfo.groupId);
console.log('Epoch:', groupInfo.epoch);
console.log('Members:', groupInfo.members);
What this does:
- Creates empty group
- Alice is the first member (index 0)
- Generates group secret K₀
- Sets up ratchet tree
- Epoch 0 starts
Step 4: What Happens Behind the Scenes?
createGroup(team-chat) does:
1. Create group ID
team-chat → group_id (bytes)
2. Initialize ratchet tree
Tree: [Alice (leaf 0)]
└─ GroupSecret (root)
3. Generate group secret
K₀ = random 32 bytes
4. Create group context
├─ group_id
├─ epoch = 0
├─ tree_hash
└─ ciphersuite
5. Store state
alice.groups.set(team-chat, ClientState)
🎮 Try It Yourself
Question 1: Alice creates a group "team-chat" with createGroup(). What's the initial state?
Show Answer
Initial state after createGroup():
- Group ID: "team-chat" (converted to bytes)
- Epoch: 0 (first version)
- Members: ["alice@example.com"]
- Group secret: K₀ (random 32 bytes)
- Ratchet tree: Alice at leaf 0
- Tree hash: SHA-256 of tree structure
Answer: Alice is the only member, epoch 0, group secret K₀
Question 2: Can Alice encrypt a message to the group immediately after createGroup()?
Show Answer This
Yes After createGroup():
const groupInfo = await alice.createGroup('team-chat');
// Can encrypt
const envelope = await alice.encryptMessage('team-chat', 'Hello, empty room');
The message will be addressed to the group, but since Alice is the only one, she's talking to herself
Answer: Yes (but she's the only one in the group)
Question 3: What's the ciphersuite that MLS uses by default?
Show Answer
The tutorial uses:
- Name:
MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 - Components:
- KEM: X25519 (Diffie-Hellman key exchange)
- AEAD: AES-128-GCM (symmetric encryption)
- Hash: SHA-256
- Signature: Ed25519
This is one of standard MLS ciphersuites from RFC 9420
Answer: MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
💡 Code Walkthrough
Let's go through the complete setup:
// Complete initialization
// 1. Import MLSManager
import { MLSManager } from 'ts-mls';
// 2. Create Alice's manager
const alice = new MLSManager('alice@example.com');
// 3. Initialize with ciphersuite
await alice.initialize();
// 4. Generate key package (Alice's ID card)
const aliceKeyPackage = await alice.generateKeyPackage();
console.log('Alice public key package:', aliceKeyPackage.publicPackage);
// 5. Create the group
const groupInfo = await alice.createGroup('team-chat');
// 6. What we have:
console.log('Group ID:', new TextDecoder().decode(groupInfo.groupId));
console.log('Epoch:', groupInfo.epoch);
console.log('Members:', groupInfo.members);
// 7: Alice can now send a message
const envelope = await alice.encryptMessage('team-chat', 'First message in empty room');
console.log('Encrypted:', envelope.ciphertext);
✅ Quick Check
Can you explain creating an MLS group to a 5-year-old?
Try saying this out loud:
"Creating an MLS group is like building a tiny room with just you inside. You get a badge that proves who you are, you lock the door with a secret key you created, and now it's a secret meeting room where only people you invite can come in"
🎓 Key Takeaways
✅ Initialize = Setup crypto manager
✅ Key package = ID card for the user
✅ createGroup() = Create secret meeting room
✅ Epoch 0 = First version of the group
✅ Alice at index 0 = First person in ratchet tree
✅ Group secret K₀ = First shared secret
✅ Ratchet tree = Where keys live
🎉 What You'll Learn Next
Now Alice has created her group Let's see how she adds Bob and Charlie:
We'll learn how to add members to the MLS group using welcome messages
Now you can create an MLS group. Next: Let's add members to the group