COMPAX

COMPAX와 MATRIX

한 가지 차이,
그리고 거기서 따라 나오는 것

Matrix는 성숙한 연합형 메신저이고, 둘을 비교하며 쓰인 글의 대부분은 두 코드베이스 중 어느 쪽도 써 보지 않은 사람들이 씁니다. 아래는 양쪽을 다 읽고 쓴 것입니다.

2026년 8월 27일에 측정했습니다. Synapse: Python 246,976줄 — 저장 계층만 71,349줄. Continuwuity, 같은 네트워크의 두 번째 구현은 Rust 95,220줄. 이 서버: 17,041줄. 양쪽 다 움직이고 있고, 아래 내용의 절반은 사물의 본성이 아니라 오늘에 관한 것입니다. 본성에 관한 부분은 표시해 두었습니다.

갈라지는 지점

방이 무엇인지
누가 정하는가

Matrix — 서버
  • 방은 이벤트들의 DAG이고, 각 이벤트는 자신의 인가 사슬을 지니고 있습니다.
  • 서버들이 서로 엇갈리면 state resolution v2가 정리합니다.
  • 그래서 상태 그룹, 앞뒤 말단, outlier, backfill이 생기고 — 저장 계층에서만 71,349줄이 됩니다.
  • 네트워크가 갈라져 있을 때도 commit은 로컬에서 받아들여지고, 나중에 합쳐집니다.
Compax — MLS 나무
  • 서버는 배달 서비스입니다. 순서는 하나뿐이고, 그것을 쥐고 있는 건 방의 본가입니다.
  • 에폭을 비교하고 같은 잠금 아래에서 덧붙입니다. 갈라질 것이 없습니다.
  • 그래서 DAG도, state resolution도, backfill도 없습니다.
  • 그리고 commit은 본가까지 다녀와야 하고, 경합이 나면 409를 받습니다.

이 맞바꿈은 양쪽 방향으로 정직하고, MLS는 여기에 선택의 여지를 두지 않습니다. commit을 적용하면 이전 에폭의 비밀이 파괴됩니다. 되돌아갈 곳이 없습니다.

정확하게 말할 값어치가 있는 주장

“저쪽 서버가 당신 메시지를 읽는다”는
양쪽 방향 모두 틀렸습니다

암호화된 Matrix 방에서 메시지의 본문은 암호문이고 서버는 그것을 읽지 못합니다 — Megolm, 여기서의 MLS와 똑같습니다. 사실인 쪽은 더 좁고, 대부분의 사람에게는 더 나쁩니다.

실제로 열려 있는 것
  • 암호화는 방에 달린 스위치입니다. 공개 방은 대개 켜져 있지 않고, 거기서는 모든 것이 읽힙니다.
  • 방 상태는 결코 암호화되지 않습니다: 이름, 주제, 아바타, 구성원, 초대, power levels — 암호화된 방에서도 평문입니다.
  • 이건 실수가 아닙니다. 서버가 이벤트에 인가 규칙을 적용하니, 그것을 읽을 수 있어야 하는 것입니다.
그러니 진짜 차이는 그래프입니다
  • 누가 누구와 한 방에 있는지, 누가 누구를 초대했는지, 언제인지 — 저쪽 서버에는 늘 보입니다.
  • 여기서는 그것이 MLS 나무 안에 삽니다. 서버가 보는 것은 group_id와 에폭입니다.
  • 그리고 놓치기 쉬운 결과 하나: 암호화된 방에서의 서버 측 검색은 저쪽에서 아예 되지 않습니다. Element는 로컬에서 찾습니다 — 그러니 검색에서 이것이 뒤처져 있는 상대는 Matrix가 아니라 Element입니다.

각자 힘을 어디에 쏟는가

힘이 향하는 곳

Matrix — 도달 범위와 운영
  • 네트워크가 갈라져도 살아남는 것. 나중에 DAG가 합쳐지기 때문입니다.
  • 돌아가는 네트워크 위에서 출시하고 이전한 열두 개의 방 버전.
  • 현장에서 입증된 규모: stream writer, 인스턴스 맵, Redis 복제.
  • 깊이 있는 운영 — 관리 API, 방 ACL, 미디어 격리, MSC 절차.
  • 제삼자 구현을 Complement가 블랙박스로 검사하는 것.
  • 모든 기기를 잃은 뒤의 복구. 서버 측 열쇠 백업을 통해서.
Compax — 서버가 할 수 없는 것
  • 밖으로 드러나는 것은 group_id와 에폭이고, 순서를 매기는 데 필요한 것은 그것뿐입니다.
  • 신원은 서버가 발급하지 않습니다. 루트 열쇠가 기기 증명에 서명하고, 각자가 로컬에서 확인합니다.
  • 순서는 한 행이면 됩니다 — compare-and-set 하나로, 한 방에서 초당 239건의 덧붙임을 측정했습니다.
  • 푸시는 아무것도 나르지 않습니다. 저쪽 푸시는 room_id를 나르므로, 방은 어차피 푸시 사업자에게 닿습니다.
  • 통화는 자기 방을 물려받습니다. 미디어 열쇠가 에폭 비밀에서 나오므로, 구성원을 빼면 부수적으로 미디어에서도 빠집니다.
  • 봇은 나무의 잎이지, 서버를 거치는 우회로가 아닙니다 — 봇을 위해 평문이 놓이는 자리는 어디에도 없습니다.
  • 항의는 증명할 수 있습니다: 메시지 증명이 누가 썼는지를 보여 줍니다. Megolm은 그룹 열쇠이고 아무것도 증명하지 못합니다.
  • 그룹이 함께 가진 돈. 이것은 Matrix에는 아예 없습니다.

그 결과

각 프로토콜이
할 수 없는 것

점수판이 아닙니다. 각 줄은 그 위에 있는 선택의 값이고, 두 열 모두 각자의 편이 차라리 없었으면 하는 것들을 담고 있습니다.

Matrix

Compax

암호화된 방의 메시지 본문

암호문. Megolm — 서버는 읽지 못합니다.

암호문. MLS — 같습니다.

암호화가 켜져 있는지

방마다 있는 스위치, m.room.encryption. 공개 방은 대개 켜져 있지 않고, 거기서는 서버가 전부 읽습니다.

스위치가 아닙니다. 암호화되지 않은 방이라는 것이 아예 없습니다.

방 상태 — 이름, 주제, 구성원, 초대, power levels

언제나 평문이고, 암호화된 방에서도 그렇습니다. 실수가 아닙니다: 서버가 인가 규칙을 적용하니 읽어야 합니다.

MLS 나무 안에. 서버가 보는 것은 group_id와 에폭입니다.

누가 누구와 한 방에 있는지

서버에는 보입니다, 언제나.

보이지 않습니다. 메시지 본문이 아니라 이것이 진짜 차이입니다.

암호화된 방에서의 서버 측 검색

아예 되지 않습니다 — 암호화된 이벤트에는 색인할 content.body가 없습니다. Element는 로컬에서 찾습니다.

여기서도 되지 않고, 이유도 같습니다. 빠져나가는 길도 Element가 택한 것과 같습니다: 클라이언트 안의 색인.

네트워크가 갈라진 동안 받아들여진 commit

됩니다. 이벤트는 로컬에서 받아들여지고 나중에 state resolution이 합칩니다.

불가능합니다. commit을 적용하면 이전 에폭의 비밀이 파괴됩니다 — 한 에폭 안의 두 commit은 양립할 수 없는 두 열쇠 상태입니다.

모든 기기를 잃은 뒤의 기록

복구 열쇠 아래의 서버 측 열쇠 백업 — 그것도 끝에서 끝까지입니다.

사라집니다. 구절만으로 열리는 포장은 아무도 취소할 수 없는 영구 접근이 되므로, 일부러 거절했습니다.

서버가 집행하는 방 규칙

있습니다 — power levels가 있고, 서버는 그것을 어기는 이벤트를 거부합니다.

없습니다. 정책은 그림자에서 돕니다: 어긋남을 세기만 하고 아무것도 거부하지 않습니다. 유효한 commit을 거부하는 것은 MLS 그룹을 상하게 하는 게 아니라 끝내 버리는 일이기 때문입니다.

링크 미리보기, 내용에 따른 운영, 본문을 나르는 푸시

방이 암호화되지 않은 곳이면 어디서든 가능합니다.

불가능합니다. 이것은 “아직”이 아닙니다 — 나머지 전부를 사는 데 치른 값입니다.

그룹이 가진 돈

프로토콜의 일부가 아닙니다.

다섯 체인, 서명자 각자의 열쇠는 각자의 기기에, 그리고 결제는 메시지로 도착합니다.

그리고 둘이 만나는 곳

양쪽에서 똑같은 것

오래 남아야 하는 것에는 Postgres, 빨라야 하는 것에는 Redis. 동작마다의 토큰 버킷. 두 번째 기기에서의 기록 — 저쪽은 열쇠 백업, 이쪽은 봉인된 창과 QR 전달. 죽은 상대에게 다시 시도할 때의 물러나는 대기. 여러 레코드를 한 요청에 묶기. 판올림을 HTTP로 알리기. 사업자 차단. 받을 때의 중복 제거. 첨부를 이벤트 로그 바깥에 두기. Prometheus와 경보 규칙. 그리고 암호화된 방에서의 서버 측 검색이 양쪽 모두 없다는 것.

다음

가장 먼저 나오는
질문들

열여섯 가지를 에두르지 않고 답했습니다 — 답이 편치 않은 그 두 가지까지 포함해서.