Skip to content

Offline Services

Status: Self-reviewed draft
Scope: optional mailbox and object storage services after the online MVP

Offline services improve availability when devices are not online at the same time.

They do not become trusted authorities. They provide hints and encrypted bytes that clients verify against signatures, hashes, membership, epochs, and local anti-rollback state.

Offline services are not required for the production online MVP.

They should be implemented only after:

  • online v2 sync is reliable
  • application session authorization is complete
  • anti-rollback persistence is crash-safe
  • membership and revocation behavior are implemented
  • resource transfer is correct for attachments and custom icons

A mailbox stores encrypted hints for a recipient device.

Allowed mailbox contents:

  • blinded mailbox ID
  • encrypted envelope
  • expiry time
  • small encrypted head hint
  • storage or peer fetch hints
  • admission metadata

Forbidden mailbox contents:

  • full KDBX snapshots
  • attachment payloads
  • custom icon payloads
  • durable revision history
  • canonical latest-head pointer

Mailbox delivery is best effort. Absence of a mailbox message is not evidence that no newer revision exists.

Mailbox IDs are blinded and epoch-scoped:

mailbox_id = BLAKE3("lattice-mailbox-id" || repo_secret || recipient_device_encryption_key || epoch)

Membership changes rotate mailbox IDs.

Recommended first supported mode:

capability-token mailbox

Capability tokens should be scoped by:

  • mailbox ID
  • operation
  • maximum bytes
  • maximum messages
  • expiry time
  • optional sender identity

Account-authenticated mailbox mode is acceptable for hosted products and organizations.

Proof-of-work and unauthenticated mailbox deposits are excluded from the production MVP. They can be reconsidered only after there is an explicit abuse budget and operational policy.

The first post-MVP mailbox profile is mailbox-capability-v1.

admission: capability token
max envelope size: 32 KiB
max envelopes per mailbox ID: 50
max total bytes per mailbox ID: 1 MiB
max TTL: 14 days
max writes per mailbox ID per day: 500
max polls per mailbox ID per hour: 120
drop policy: reject newest when quota is full

Operators may lower these limits. Operators may raise them only for authenticated or paid contexts with explicit quota accounting.

Future unauthenticated mailbox profiles, if any, must use a separate profile ID and a separate resource pool.

max TTL for any future unauthenticated mode: 24-72 hours

The mailbox server must expose its policy so clients can decide whether deposits are useful.

mailbox-capability-v1 uses /lattice/mailbox/1 over an authenticated, encrypted libp2p connection. The service capability is an HMAC-authenticated claim set scoped to one mailbox ID, an operation set (deposit, poll, and/or acknowledge), byte and message ceilings, an expiry time, and an optional libp2p peer ID. Capability failures do not reveal whether a mailbox exists.

Each mailbox envelope contains only an expiry, an ephemeral X25519 public key, AEAD parameters, and recipient ciphertext. The ciphertext contains a signed head hint: vault and membership bindings, epoch, sender and recipient device IDs, revision head and manifest hash, bounded peer-fetch addresses, and an optional object-manifest hash. It cannot contain records, resource payloads, or a full revision manifest. The sender signs the hint with its membership device key, then encrypts it to the recipient device encryption key using XChaCha20-Poly1305 and a key derived from ephemeral X25519 with HKDF-SHA-256.

Deposit is idempotent by a ciphertext-bound envelope ID. Poll does not delete; the recipient acknowledges envelope IDs only after decrypting and validating the hint. The service atomically persists deposits, acknowledgements, expiry pruning, and rate counters before reporting success. Quota exhaustion rejects the new envelope and retains previously accepted envelopes.

Object storage stores immutable encrypted objects addressed by hash.

Allowed objects:

  • encrypted resource chunks
  • encrypted manifests
  • future encrypted snapshot checkpoints
  • advisory signed head pointers

Required verification:

  • object hash
  • manifest signature
  • membership epoch
  • writer authority
  • resource descriptor hash
  • local anti-rollback state

The storage server may provide convenience indexes, but clients must treat them as advisory.

Public unauthenticated durable storage is not supported.

Allowed admission modes:

  • account authentication
  • storage capability token
  • self-hosted credentials
  • private allowlist
  • paid or quota-backed hosted plan

Object storage must enforce quotas before accepting bytes.

The first post-MVP object storage profile is object-storage-capability-v1.

admission: account auth, storage capability token, or self-hosted credentials
max object size: 4 MiB
target chunk size: 256 KiB
max manifest size: 1 MiB
max chunks per manifest: 8192
max repo size: provider policy, advertised before upload
max retained revisions: provider policy, advertised before upload
max pinned objects: provider policy, advertised before upload
max writes per token per day: provider policy, advertised before upload
garbage collection: never collect pinned objects; unpinned objects may be collected after 30 days

Providers may choose smaller repo, retention, pin, write, and bandwidth limits, but must advertise them before clients upload. Clients must treat quota rejection as sync backpressure, not data loss.

Opaque KDBX snapshots, if added later, are quota-sensitive because attachments can make vault files large.

Storage may expose signed head pointers for convenience.

Rules:

  • A head pointer is never canonical by itself.
  • Clients verify the pointed-to signed manifest.
  • Clients compare the result against local rollback floors.
  • Clients treat stale, missing, or conflicting head pointers as sync hints, not final truth.
  • A storage server cannot make a client forget locally known heads.

Offline services protect content but not all metadata.

Servers may observe:

  • update timing
  • ciphertext sizes
  • mailbox polling times
  • object fetch groupings
  • network addresses
  • account or token usage patterns

Mitigations:

  • padded mailbox envelopes
  • fixed or bucketed chunk sizes
  • batching deposits
  • rotating mailbox IDs by epoch
  • avoiding human-readable vault names
  • optional multi-provider storage
  • privacy-heavy mode with no mailbox or object storage

The product must not claim anonymity.

  • Mailbox-only mode can notify a device about missing work but does not claim full offline catch-up.
  • Mailbox plus object storage can catch up when no other user device is online.
  • Object storage cannot forge, modify, or silently roll back accepted state.
  • Stateful services have quota and abuse controls before public deployment.
  • Proof-of-work and unauthenticated durable storage remain out of MVP defaults.

The mailbox implementation includes the exact epoch/recipient blinded ID, signed recipient-encrypted hints, scoped capability authentication, the fixed mailbox-capability-v1 limits, idempotent deposit, explicit acknowledgement, expiry and rate enforcement, crash-safe persistence, a bounded libp2p codec, and a separately packaged mailbox process with operator capability issuance. Pinned per-vault client endpoints and bearer capabilities stored in the encrypted credential-cache KDBX are also implemented. The daemon performs periodic deposit/poll cycles, persists exact outbound envelopes for restart and lost-response idempotency, isolates capability failures, and acknowledges only hints already present in the authenticated local revision graph.

Object storage implements immutable epoch-encrypted record/resource bundles, including historical conflict records, with scoped capabilities, pinning, garbage collection, quotas, advisory signed heads, a bounded libp2p protocol, and a separately packaged process. The daemon publishes a verified bundle before depositing its hint, reuses cached bundle bytes across retries, and fetches and verifies the advertised manifest, records, conflicts, and resources before materialization. The offline outage/restart E2E proves catch-up after the publishing user device goes offline and proves that stale redelivery cannot roll back a newer local edit. Phases 4 and 5 are complete.