mirror of
https://github.com/block/buzz.git
synced 2026-11-02 23:41:08 +00:00
Phase 1 of hybrid E2E encryption for DMs: 2-party pairwise NIP-44, reusing the engram/observer "store ciphertext the relay can't read" pattern. A new `encryption_activated_at` latch column on channels (migration 0004) marks a DM as E2E from creation. It is relay-owned and write-once at the `create_dm` INSERT -- `ChannelUpdate` has no such field, so the dynamic update path structurally cannot move or clear it, making the encryption-start boundary tamper-evident by construction. Only 2-party DMs latch; group DMs (3-9) stay plaintext until Phase 2 brings group keys, since pairwise NIP-44 has no single peer to encrypt to. Ingest rule 15c enforces the boundary fail-visible: a latched channel rejects any kind:9 that is not NIP-44 v2 ciphertext (strong validator: base64 + decoded-len >= 99 + 0x02 version byte). Enforcement is latch-PRESENCE only -- no `created_at` comparison -- so a backdated timestamp (drift window or the clamp-exempt proxy:submit path) cannot smuggle plaintext below the latch. Dispatch skips search indexing and workflow triggers for private/DM channels (fail-closed) so ciphertext never reaches Typesense. Desktop gains `nip44_encrypt_to_peer`/`nip44_decrypt_from_peer` Tauri commands (private key stays in Rust) plus TS bindings. Encrypt-on-send and decrypt-on-render in the message pipeline are a follow-up (Phase 1b). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
15 lines
847 B
SQL
15 lines
847 B
SQL
-- Add the E2E encryption activation latch to the channels table.
|
|
--
|
|
-- `encryption_activated_at` marks the point from which messages in this channel
|
|
-- MUST be NIP-44 v2 ciphertext. It is the tamper-evident encryption-start
|
|
-- marker for hybrid E2E: rather than a free-standing client event (which the
|
|
-- relay would have to locate per message via a sibling read, and which a member
|
|
-- could backdate), the boundary is relay-owned channel state. The relay sets it
|
|
-- and never lets a client write it, so it cannot be forged or moved.
|
|
--
|
|
-- Phase 1 sets this at DM creation (every message in a new DM is E2E). Existing
|
|
-- plaintext DMs leave it NULL and stay readable as legacy plaintext — no
|
|
-- re-encryption, which would change event IDs and break the audit hash-chain.
|
|
ALTER TABLE channels
|
|
ADD COLUMN encryption_activated_at TIMESTAMPTZ;
|