Skip to main content

🏗️ 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:

➕ Continue: Inviting Guests

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