-- Cipher schema. The server is a "dumb" key directory + relay. -- It stores ONLY public keys and ciphertext. Private keys never leave the client. -- A user account. Identified by username; discoverable by other users. CREATE TABLE users ( id TEXT PRIMARY KEY, -- uuid username TEXT NOT NULL UNIQUE, -- lowercase handle, e.g. "alice" display_name TEXT NOT NULL, pw_hash TEXT NOT NULL, -- PBKDF2(password) — account auth only, unrelated to E2E keys pw_salt TEXT NOT NULL, created_at INTEGER NOT NULL ); CREATE INDEX idx_users_username ON users(username); -- A device belonging to a user. Each device has its own Signal identity. -- Multi-device: a user may register several (phone, desktop) via QR linking. CREATE TABLE devices ( id TEXT PRIMARY KEY, -- uuid user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, registration_id INTEGER NOT NULL, -- Signal registrationId identity_key TEXT NOT NULL, -- base64 public identity key signed_prekey_id INTEGER NOT NULL, signed_prekey_pub TEXT NOT NULL, -- base64 signed_prekey_sig TEXT NOT NULL, -- base64 signature over signed_prekey_pub created_at INTEGER NOT NULL, last_seen INTEGER NOT NULL ); CREATE INDEX idx_devices_user ON devices(user_id); -- One-time prekeys. Server hands one out per session-init request, then deletes it. CREATE TABLE one_time_prekeys ( device_id TEXT NOT NULL REFERENCES devices(id) ON DELETE CASCADE, prekey_id INTEGER NOT NULL, prekey_pub TEXT NOT NULL, -- base64 PRIMARY KEY (device_id, prekey_id) ); CREATE INDEX idx_otk_device ON one_time_prekeys(device_id); -- Bearer auth sessions (account-level). Token proves control of the account. CREATE TABLE sessions ( token TEXT PRIMARY KEY, -- random opaque token user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, device_id TEXT NOT NULL REFERENCES devices(id) ON DELETE CASCADE, created_at INTEGER NOT NULL, expires_at INTEGER NOT NULL ); CREATE INDEX idx_sessions_user ON sessions(user_id); -- Web Push subscriptions for wake-on-message notifications (endpoint is opaque). CREATE TABLE push_subs ( device_id TEXT PRIMARY KEY REFERENCES devices(id) ON DELETE CASCADE, endpoint TEXT NOT NULL, p256dh TEXT NOT NULL, auth TEXT NOT NULL, created_at INTEGER NOT NULL );