Skip to main content

Module keys

Module keys 

Source
Expand description

Devices, E2E key material, to-device inbox, device-list change log, cross-signing, and key backup — the devices/keys/backup half of messenger.db (the rooms/events/state half is matrix_store.rs, a separate work item). See the messenger protocol notes §2 second SQL block for the DDL this module implements, §1.1 for the device-per-credential model, and §3.7 for the /sync delta shapes this module’s read functions serve.

Crypto stays entirely client-side here too: device_keys.keys, one_time_keys.key_json, fallback_keys.key_json, cross_signing_keys.key_json, cross_signing_signatures.signature_json, key_backup_versions.auth_data, and key_backup_sessions.session_data are all opaque JSON this module never inspects or verifies — pure storage/relay, identical in spirit to matrix_store.rs’s own treatment of event content.

§Single-writer discipline

Same rule as matrix_store.rs: every function here takes an already-open Connection; the caller holds it behind one std::sync::Mutex. Every stream-ordered table in this module (to_device_messages, device_list_changes) shares matrix_store’s one global stream_counter — this module never mints its own counter, it calls [crate::store::next_stream_id] inside the same transaction as the row it stamps, exactly like matrix_store.rs does for its own tables.

§Deviation from the plan’s literal DDL text

fallback_keys gains a key_id TEXT NOT NULL column not present in the plan’s printed DDL — see create_matrix_keys_schema’s doc comment for why: the plan’s own CRUD contract for claim_one_time_key requires a real key_id for a fallback-key claim, exactly like it already returns one for a real one-time-key claim, and there was no column to source that from.

Structs§

CrossSigningKey
CrossSigningSignature
Device
DeviceKeys
KeyBackupSession
KeyBackupVersion
ToDeviceMessage

Enums§

CredentialKind
Which of the two existing auth mechanisms (plan §1.1) minted a device.
CrossSigningUsage
A cross-signing key’s usage, per the Matrix cross-signing model.
MatrixKeysStoreError
Why a write into this store was refused, on top of a real database failure — same shape as crate::store::MatrixStoreError.
ToDeviceDedupOutcome
What enqueue_to_device_deduped did.

Functions§

add_one_time_keys
Upload a batch of one-time keys. Per key: a brand-new key_id is inserted; a key_id that already exists with byte-identical key_json is a silent no-op (idempotent resubmission); a key_id that already exists with DIFFERENT key_json refuses the WHOLE batch with MatrixKeysStoreError::OneTimeKeyConflict (one transaction — a refused call leaves no partial insert from this batch).
add_signatures
Append a batch of /keys/signatures/upload signatures — pure storage, never verified server-side (opaque, per this module’s own doc comment). One transaction.
backup_count_and_etag
(session count, current etag) for version — the GET /room_keys/version[/{version}] response shape’s count/etag pair.
claim_one_time_key
Claim one one-time key of algorithm for (user_id, device_id): an atomic DELETE ... RETURNING on the lowest key_id — the “exactly once” guarantee, no window where two claimants could race the same key. If none remain, falls back to the (reusable, never-deleted) fallback key for that algorithm and marks it used = 1 — the client reads its own unused_fallback_key_types to know when it should upload a fresh one.
clear_device_one_time_material
Wipe one-time and fallback keys for (user_id, device_id) — used when an authenticated device resets its Olm identity under the same device id. Does not touch device_keys itself (the caller replaces that row) or device_list_changes (the following upsert_device_keys logs the change).
count_one_time_keys
How many one-time keys remain per algorithm — /keys/upload’s response and /sync’s device_one_time_keys_count.
create_backup_version
Create a brand-new key-backup version — a version number is never reused (soft-delete only, see delete_backup_version), so this is a plain insert.
create_device
Mint a fresh device for user_id authenticated by (credential_kind, credential_ref), returning the new device id. Does not check for an existing row for this credential — callers use device_for_credential first (the get-or-create orchestration is P4’s device_id_for, not this module’s job).
create_matrix_keys_schema
Create every table/index this module needs — idempotent, called from crate::store::init_messenger_db right after create_matrix_schema, and directly by this module’s own tests.
cross_signing_key_for
One user’s cross-signing key of a specific usage, if uploaded — routes::matrix::keys’s own lookup when it needs exactly one (verifying a self/user-signing key against a caller’s stored master key; deciding whether a master key already exists before a /keys/device_signing/upload call). cross_signing_keys_for stays the batch entry point /keys/query uses.
cross_signing_keys_for
Every cross-signing key belonging to any of user_ids — the /keys/query batch shape. Empty input returns an empty vec.
current_backup_version
user_id’s current (highest-numbered, non-deleted) backup version, if any.
delete_backup_sessions
Delete backup sessions for version, same three-shape narrowing as get_backup_sessions. Bumps etag once iff at least one row was removed. One transaction. Returns the number of rows deleted.
delete_backup_version
Soft-delete a backup version (the version number is never reused, so its key_backup_sessions rows are left in place as inert history). Idempotent: deleting an already-deleted version returns false.
delete_device
The manual “log out this device” path (DELETE /devices/{deviceId}, P9): delete the device, cascade its key material and pending to-device rows, and append one [device_list_changes] row for user_id. One transaction. Returns whether a device existed to delete.
delete_device_by_credential
The credential-revoke path (plan §1.1, on_credential_revoked steps 1-3 — the wake fan-out, step 4, is the caller’s job in P4): find the device minted for (credential_kind, credential_ref), delete it and its key material and pending to-device rows, and append one device_list_changes row for its owner. One transaction. Returns Some((user_id, device_id)) on a hit, None if no device was ever minted for this credential.
delete_to_device_up_to
Delete every to-device row for (user_id, device_id) at or before stream_id — plan §3.7’s delete-after-ack rule: a /sync call with since=stream_id is itself the proof the client already durably received everything up to that point. Returns the number of rows removed.
device_for_credential
The device already minted for (credential_kind, credential_ref), if any (the unique-index lookup behind device_id_for, P4).
device_keys_for
Every device-keys row belonging to any of user_ids — the /keys/query batch shape. Empty input returns an empty vec without touching the database.
device_list_changes_between
Every distinct user_id whose device list changed in (from_exclusive, to_inclusive] — /sync’s device_lists.changed candidate set, before the caller restricts it to shared-room users (plan §3.7).
devices_for_reaper
Every device in the system, for the P14 boot+hourly reaper sweep (plan manager decision 3): the sweep itself checks each credential against the identity database and calls delete_device_by_credential for the ones that are gone or expired — not this module’s job.
enqueue_to_device
Fan out one PUT /sendToDevice call’s messages map (already flattened to one row per (recipient_user_id, recipient_device_id) — a * device wildcard is resolved by the caller before this function ever sees it) as one transaction sharing matrix_store’s global stream counter. Returns the last stream id minted, or the counter’s current value unchanged if messages is empty.
enqueue_to_device_deduped
enqueue_to_device, but dedup-checked and recorded in the SAME transaction as the inserts — mirrors crate::store::insert_timeline_event_deduped’s own shape for the to-device case, which records NULL for txn_dedup.event_id (that column’s own doc, matrix_store’s DDL, states this is the to-device case). A repeat of (sender_user_id, sender_device_id, txn_id) is a no-op: no second set of to_device_messages rows, matching PUT /sendToDevice/{eventType}/{txnId}’s own idempotency contract (routes::matrix::keys, P9).
get_backup_sessions
Read backup sessions for version, optionally narrowed to one room and/or one session (mirroring GET /room_keys/keys[/{roomId}[/{sessionId}]]’s three shapes). A session_id without a room_id is treated the same as neither being given — the wire path never allows that combination.
get_backup_version
One specific backup version by number, regardless of its is_deleted state — the caller decides how to treat a deleted version (a fetch by an explicit version number is a different question than “what’s current”).
get_device
One of user_id’s own devices, by id.
list_devices
Every device user_id owns.
log_device_list_change
Standalone entry point for a caller that is not already inside one of this module’s own multi-step transactions (e.g. a future piece that needs to log a change without also writing a keys row). Every write in THIS module that is documented to log a change does so inline, in the same transaction as that write — this function is for everyone else.
put_backup_sessions
Upload a batch of backup sessions into version — refuses with MatrixKeysStoreError::WrongBackupVersion unless version is user_id’s current non-deleted version (plan §2 manager decision 5). Bumps etag once for the whole batch. One transaction.
set_device_display_name
Rename (or clear, with None) a device’s display_name. Returns whether a row was found and updated.
signatures_for
Every signature filed against (target_user_id, target_key_id).
to_device_for
Every to-device message still pending for (user_id, device_id) after after_stream, oldest first — /sync’s to_device.events.
touch_device
Bump last_seen_at on an existing device — a no-op if the device does not exist.
unused_fallback_key_types
Every fallback-key algorithm that has not yet been claimed — the client uses this to decide which algorithms need a fresh fallback key uploaded.
update_backup_version_auth_data
Update a non-deleted backup version’s opaque auth_data, bumping its etag. Returns whether a row was found and updated.
upsert_cross_signing_key
Store (or replace) one of user_id’s three cross-signing keys. Appends one [device_list_changes] row, same as upsert_device_keys — a peer’s trust chain changed, not just a device.
upsert_device_keys
Store (or replace) POST /keys/upload’s device-keys object verbatim. Appends one [device_list_changes] row for user_id — every peer sharing a room learns about the change on their next /sync. One transaction.
upsert_fallback_key
Upload (or replace) the one active fallback key for algorithm — replacing always resets used back to 0, per spec (“a new fallback key is unused until it is actually claimed”).