.ch
Governed by Swiss law · Zürich
The Salginatobel bridge over its gorge
Guarantees

Every guarantee has an edge.

The threat model the engine is built against, and — stated plainly — what it does not protect. We will tell you what we do not protect. Decide against facts.

Salginatobel Bridge · Schiers · Robert Maillart · 90 m span · 1930
Threat model
#AdversaryDefense
T1Key-less reader of the file — stolen backup, seized disk, curious host adminAEAD on every blob and audit payload; plaintext columns expose shape only; the two-byte bucket index denies the equality graph.
T2Key-less writer altering history — roll back a rotated credential, delete a revision, resurrect a tombstone, reparent into a granted subtreeAAD-bound seals, metadata-bound checksums, gapless seq, hash-chained audit, verify_store / verify_deep, external witness.
T3Authenticated but unauthorized caller probing beyond their grantsOne arbiter at every choke point; discovery scoped like reads; dossier-scoped uniqueness; bounded delegation; four-character search floor; everything audited.
T4Erasure obligations against immutabilityCrypto-shred including index and object-name purge.
T5Whole-file rollbackUndetectable from inside; detected by the witness comparing anchored heads.

Non-goals: an attacker holding the vault key; hiding tree shape or type names from a file reader; storage-page side channels; multi-writer concurrency. Values you encrypted client-side are opaque to the engine at every layer — their secrecy never depends on it.

Residue

The file, as a key-less holder sees it.

Steal the file, seize the disk, restore the backup: this is what you get. Shape in the clear, content sealed, keys not present. Nothing here is a slogan; every line is a column.

In the clear

A standard SQLite header. Per record: entry id, version, type name, parent id, status, timestamps, sequence number, checksum bytes. The index: two-byte buckets against entry ids. Object names, owners and sealed lengths. Per audit row: seq, previous hash, row hash, event id, timestamp. The schema document — type and field names, labels, templates — plaintext configuration that describes shape, never content. Grants: countable per tenant, by type and parent.

Sealed

Every payload — zstd, then AES-256-GCM, bound to its row. Every audit body — actor, actee, action, outcome, address. Every grant — grantee, ops, relation, grantor. Every object body. Every content key, wrapped with AES-KW; the master secret, wrapped under your key material.

Not in the file at all

Your key material — never stored, only supplied at open. The live access decisions — an in-memory table rebuilt from the sealed grants on open, never written to disk. Any plaintext, ever.

The two-byte bucket is the largest thing an index reveals: one of about twenty-six four-character prefixes. Length and compressibility of a payload leak (see below). Everything else a file holder learns is the tree, the types and the timing.

What it does not protect

Ciphertext length leaks.

Payloads are compressed before sealing and nothing is padded. A file holder learns roughly how big a record is and whether it is mostly prose or mostly ciphertext. Pad client-side if you need size privacy; the engine seals your padding without comment.

Shred erases the file, not the world around it.

Once shred returns, the file holds no recoverable key for that record — proven by test, including the rollback journal. Backups, replicas and filesystem snapshots taken before the shred still do. That retention sweep is part of your erasure procedure.

Truncating the tail needs a witness.

Any edit to history is detectable with no key. Deleting the newest rows leaves a shorter chain that verifies clean. Anchor the head somewhere the writer cannot reach, and reconcile on a schedule.

Rotation is custody hygiene, not compromise recovery.

Rotating your key re-wraps the master secret; it never changes it. Right for scheduled hygiene, custody handover, moving to an HSM. After a suspected compromise, re-encrypt into a fresh store.

What a file holder can infer about grants.

Grants are sealed, and the live authorization table never touches disk — but each grant row's type and its parent tenant are plaintext columns. A file holder can count grants per tenant; never who holds them, at what permission, or why.

What a file holder can infer from the index.

At most two bytes per indexed value — a bucket that around twenty-six four-character prefixes share. No value, plaintext or otherwise, is ever in the index; a stolen file yields buckets, not names.

Uniqueness is one bit.

A writer holding a branch of a tenant can provoke a uniqueness violation against a record elsewhere in the same tenant and learn that a value exists there. That bit is the price of “unique” meaning the same thing for every writer in a tenant — and it never crosses tenants.

System is a boundary you own.

Applications must construct the System accessor for their own maintenance paths; nothing on the wire can. Any code linked into your process can bypass the arbiter — keep System off request paths, tokens and headers.