Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
82129b2
build(deps): pin openmls to the post-quantum revision
emil-wire Jul 10, 2026
bf6d2d1
build(deps): upgrade hpke to 0.14 for post-quantum KEMs
emil-wire Jul 10, 2026
decca25
build(deps): add ml-dsa
emil-wire Jul 11, 2026
b6be2a4
build(deps): unify the zeroize feature onto x-wing and ml-dsa
emil-wire Jul 12, 2026
d973c48
feat: implement ML-DSA-44, 65 and 87 signatures
emil-wire Jul 13, 2026
d0e9a0e
feat: add X-Wing hybrid KEM (ML-KEM-768 + X25519)
emil-wire Jul 14, 2026
576ced5
feat: add ML-KEM-768 + P-256 HPKE KEM
emil-wire Jul 14, 2026
ffe4768
feat: add ML-KEM-1024 + P-384 HPKE KEM
emil-wire Jul 16, 2026
0f68eff
feat: add standalone ML-KEM-768 and ML-KEM-1024 HPKE KEMs
emil-wire Jul 16, 2026
d1de1a1
feat: add the nine post-quantum cipher suites
emil-wire Jul 17, 2026
ae32c1e
feat: add MLS-128 with ML-KEM-768 + Ed25519 cipher suite
emil-wire Jul 18, 2026
a20f5d7
feat: add ChaCha20Poly1305 HPKE config
emil-wire Jul 19, 2026
c9985be
feat: add MLS-128 X-Wing cipher suite
emil-wire Jul 20, 2026
4126f8d
test: cover the post-quantum provider primitives
emil-wire Jul 20, 2026
7bdc26b
test: cover the post-quantum cipher suites end to end
emil-wire Jul 21, 2026
72a8ae4
chore: simplify test
emil-wire Aug 3, 2026
8d97924
feat: expose PQ cipher suites through the FFI
emil-wire Aug 4, 2026
b79cc0d
ci: add nightly post-quantum benchmarks
emil-wire Sep 3, 2026
fac7ef8
chore: fix rustfmt import ordering
emil-wire Sep 3, 2026
c6a45f9
fix: harden HPKE secret zeroization with upstream fixes
emil-wire Sep 10, 2026
98966e5
build(deps): update OpenMLS PQ revision
emil-wire Sep 10, 2026
b0194a1
test: call every HPKE entry point for every suite
emil-wire Sep 11, 2026
cd91ae1
fix: support the post-quantum KEMs in HPKE PSK mode
emil-wire Sep 11, 2026
2d86785
fix: make an unsupported thumbprint an explicit error
emil-wire Sep 11, 2026
a8cfaae
test: gate the pq matrix behind test-all-cipher
emil-wire Sep 11, 2026
4697b4f
build: fail the build if x-wing ever resolves twice
emil-wire Sep 11, 2026
d0878e8
refactor: use the shared ML-DSA module
emil-wire Sep 11, 2026
156ed2d
build(deps): update OpenMLS PQ revision
emil-wire Sep 30, 2026
6f51a6d
build(deps): update OpenMLS PQ revision
emil-wire Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/benchmark-jvm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ on:
required: false
type: string
benchmark_cipher_suites:
description: Comma-separated benchmark cipher suite names
description: Comma-separated benchmark cipher suite IDs
required: false
type: string
publish:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/benchmark-ts-browser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ on:
required: false
type: string
benchmark_cipher_suites:
description: Comma-separated benchmark cipher suite names
description: Comma-separated benchmark cipher suite IDs
required: false
type: string
publish:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/benchmark-ts-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ on:
required: false
type: string
benchmark_cipher_suites:
description: Comma-separated benchmark cipher suite names
description: Comma-separated benchmark cipher suite IDs
required: false
type: string
publish:
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/benchmarks-pq.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: benchmarks-pq
on:
schedule:
- cron: "0 4 * * *"
workflow_dispatch:

jobs:
benchmark-jvm:
uses: ./.github/workflows/benchmark-jvm.yml
with:
runs_on: '["self-hosted", "benchmark"]'
benchmark_cipher_suites: "61441,61442,61443,61444,61445,61446,61447,61448,61449,61450,61451" # 0xF001-0xF00B
secrets:
METRICS_WRITER_PASSWORD: ${{ secrets.METRICS_WRITER_PASSWORD }}

benchmark-ts-browser:
uses: ./.github/workflows/benchmark-ts-browser.yml
with:
runs_on: '["self-hosted", "benchmark"]'
benchmark_cipher_suites: "61441,61442,61443,61444,61445,61446,61447,61448,61449,61450,61451" # 0xF001-0xF00B
secrets:
METRICS_WRITER_PASSWORD: ${{ secrets.METRICS_WRITER_PASSWORD }}

benchmark-ts-native:
uses: ./.github/workflows/benchmark-ts-native.yml
with:
runs_on: '["self-hosted", "benchmark"]'
benchmark_cipher_suites: "61441,61442,61443,61444,61445,61446,61447,61448,61449,61450,61451" # 0xF001-0xF00B
secrets:
METRICS_WRITER_PASSWORD: ${{ secrets.METRICS_WRITER_PASSWORD }}
51 changes: 37 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ reqwest = { version = "0.12", default-features = false, features = [
testcontainers = { version = "0.28", features = ["reusable-containers"] }

# our OpenMLS fork
openmls = { git = "https://github.com/wireapp/openmls", rev = "9252caa031d874b2e6e2157db6b8024882eb72f3", version = "1" }
openmls_basic_credential = { git = "https://github.com/wireapp/openmls", rev = "9252caa031d874b2e6e2157db6b8024882eb72f3", version = "0.2" }
openmls_traits = { git = "https://github.com/wireapp/openmls", rev = "9252caa031d874b2e6e2157db6b8024882eb72f3", version = "0.2" }
openmls_x509_credential = { git = "https://github.com/wireapp/openmls", rev = "9252caa031d874b2e6e2157db6b8024882eb72f3", version = "0.2" }
openmls = { git = "https://github.com/wireapp/openmls", rev = "770733456132521ff13eb5212efcf56503f25a79", version = "1" }
openmls_basic_credential = { git = "https://github.com/wireapp/openmls", rev = "770733456132521ff13eb5212efcf56503f25a79", version = "0.2" }
openmls_traits = { git = "https://github.com/wireapp/openmls", rev = "770733456132521ff13eb5212efcf56503f25a79", version = "0.2" }
openmls_x509_credential = { git = "https://github.com/wireapp/openmls", rev = "770733456132521ff13eb5212efcf56503f25a79", version = "0.2" }

# proteus
proteus-traits = { git = "https://github.com/wireapp/proteus", tag = "v3.0.1" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ open class AddUser {
"5",
"7"
)
var cipherSuite: UShort = 1u
var cipherSuite: Int = 1

@Param("1", "10", "100")
var userCount: Int = 0
Expand All @@ -35,7 +35,7 @@ open class AddUser {
@Setup(Level.Invocation)
fun setup() {
runBlocking {
val cipherSuite = CipherSuite.entries.first { it.value == cipherSuite }
val cipherSuite = CipherSuite.entries.first { it.value.toInt() == cipherSuite }
val options = CcInitOptions(CcInitOptions.Mode.WithBasicCredential(cipherSuite))
aliceCc = ccInit(options)
conversationId = createConversation(aliceCc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ open class CreateMessage {
"5",
"7"
)
var cipherSuite: UShort = 1u
var cipherSuite: Int = 1

@Param("1", "10", "100")
var messageCount: Int = 0
Expand All @@ -37,7 +37,7 @@ open class CreateMessage {

@Setup(Level.Iteration)
fun setup() = runBlocking {
val cipherSuite = CipherSuite.entries.first { it.value == cipherSuite }
val cipherSuite = CipherSuite.entries.first { it.value.toInt() == cipherSuite }
cc = ccInit(CcInitOptions(CcInitOptions.Mode.WithBasicCredential(cipherSuite)))
conversationId = createConversation(cc)
messages = List(messageCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ open class JoinGroup {
"5",
"7"
)
var cipherSuite: UShort = 1u
var cipherSuite: Int = 1

@Param("1", "10", "100")
var userCount: Int = 0
Expand All @@ -33,7 +33,7 @@ open class JoinGroup {
@Setup(Level.Invocation)
fun setup() {
runBlocking {
val cipherSuite = CipherSuite.entries.first { it.value == cipherSuite }
val cipherSuite = CipherSuite.entries.first { it.value.toInt() == cipherSuite }
val options = CcInitOptions(CcInitOptions.Mode.WithBasicCredential(cipherSuite))
val aliceCc = ccInit(options)
conversationId = createConversation(aliceCc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ open class ProcessMessage {
"5",
"7"
)
var cipherSuite: UShort = 1u
var cipherSuite: Int = 1

@Param("1", "10", "100")
var messageCount: Int = 0
Expand All @@ -39,7 +39,7 @@ open class ProcessMessage {

@Setup(Level.Invocation)
fun setup() = runBlocking {
val cipherSuite = CipherSuite.entries.first { it.value == cipherSuite }
val cipherSuite = CipherSuite.entries.first { it.value.toInt() == cipherSuite }
val options = CcInitOptions.Mode.WithBasicCredential(cipherSuite)
val aliceCc = ccInit(CcInitOptions(options))
conversationId = createConversation(aliceCc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ open class RemoveUser {
"5",
"7"
)
var cipherSuite: UShort = 1u
var cipherSuite: Int = 1

@Param("1", "10", "100")
var userCount: Int = 0
Expand All @@ -35,7 +35,7 @@ open class RemoveUser {
@Setup(Level.Invocation)
fun setup() {
runBlocking {
val cipherSuite = CipherSuite.entries.first { it.value == cipherSuite }
val cipherSuite = CipherSuite.entries.first { it.value.toInt() == cipherSuite }
aliceCc = ccInit(CcInitOptions(CcInitOptions.Mode.WithBasicCredential(cipherSuite)))
conversationId = createConversation(aliceCc)

Expand Down
33 changes: 33 additions & 0 deletions crypto-ffi/src/cipher_suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,39 @@ pub enum CipherSuite {

/// DH KEM P384 | AES-GCM 256 | SHA2-384 | EcDSA P384
MLS_256_DHKEMP384_AES256GCM_SHA384_P384 = 0x0007,

/// PQ: ML-KEM-768 + x25519 | AES-GCM 128 | SHA2-256 | Ed25519
MLS_128_MLKEM768X25519_AES128GCM_SHA256_Ed25519 = 0xF001,

/// PQ: ML-KEM-768 + x25519 | AES-GCM 256 | SHA2-384 | Ed25519
MLS_128_MLKEM768X25519_AES256GCM_SHA384_Ed25519 = 0xF002,

/// PQ: ML-KEM-768 + P256 | AES-GCM 128 | SHA2-256 | P256
MLS_128_MLKEM768P256_AES128GCM_SHA256_P256 = 0xF003,

/// PQ: ML-KEM-768 + P256 | AES-GCM 256 | SHA2-384 | P256
MLS_128_MLKEM768P256_AES256GCM_SHA384_P256 = 0xF004,

/// PQ: ML-KEM-1024 + P384 | AES-GCM 256 | SHA2-384 | P384
MLS_192_MLKEM1024P384_AES256GCM_SHA384_P384 = 0xF005,

/// PQ: ML-KEM-768 | AES-GCM 256 | SHA2-384 | P256
MLS_128_MLKEM768_AES256GCM_SHA384_P256 = 0xF006,

/// PQ: ML-KEM-1024 | AES-GCM 256 | SHA2-384 | P384
MLS_192_MLKEM1024_AES256GCM_SHA384_P384 = 0xF007,

/// PQ: ML-KEM-768 | AES-GCM 256 | SHA2-384 | ML-DSA-65
MLS_192_MLKEM768_AES256GCM_SHA384_MLDSA65 = 0xF008,

/// PQ: ML-KEM-1024 | AES-GCM 256 | SHA2-384 | ML-DSA-87
MLS_256_MLKEM1024_AES256GCM_SHA384_MLDSA87 = 0xF009,

/// PQ: ML-KEM-768 | AES-GCM 256 | SHA2-384 | Ed25519
MLS_128_MLKEM768_AES256GCM_SHA384_Ed25519 = 0xF00A,

/// PQ: ML-KEM-768 + x25519 | Chacha20Poly1305 | SHA2-384 | ML-DSA-44
MLS_128_MLKEM768X25519_CHACHA20POLY1305_SHA384_MLDSA44 = 0xF00B,
}

impl From<CipherSuite> for MlsCipherSuite {
Expand Down
Loading