Microtoll Engine pre-1.0 · the locks, pre-built

THREATMODEL.md — Microtoll Engine

Status: each package's section was completed in its milestone, before that package's API was reviewed; the formats each claim rests on are in the packages' FORMATS.md and DESIGN.md. A limit is stated as plainly as a protection.

1. Adversaries

IDAdversaryCan do
A1Server operator or database copyReads every row, log and ciphertext; sees traffic timing and sizes; can drop, replay, reorder or roll back what it serves. It does not run the client.
A2Network observerSees TLS metadata and timing (TLS itself is assumed).
A3Co-memberLegitimately holds an object's key; sees other members' public keys and rows.
A4Removed memberHolds the old keys and everything they saw before removal.
A5Link holderHolds a share link (and therefore the object key) without being a member.
A6Stranger with an accountCan authenticate and send any well-formed message.
A7Harvest-now, decrypt-laterA1's copy plus a future large quantum computer.
A8Compromised device or pageMalicious script in the origin, malware, or someone holding the unlocked device or a copy of the browser profile.

2. Global limits (true of every package)

3. @microtoll/crypto-core

| Format | Refused, and how | |---|---| | AEAD v1 [0x01][IV][ct‖tag] | wrong key; any flipped bit in IV, ciphertext or tag; truncation; unknown version byte; additional data that differs or is missing — all fail at the GCM tag, before any plaintext is returned | | ECIES v3 [0x03][ephemeral][AEAD] | wrong recipient pair; the right private key with a swapped public half (the recipient is bound into the key); a relabelled version byte (authenticated as AAD); an ephemeral point off the curve; a blob from another namespace (the label is in the key); the retired v1 format, by name | | ECIES v2 [0x02][KEM ct][AEAD] | as v3, plus any flipped bit in the 1120-byte KEM ciphertext (the shared secret changes, then the tag fails); truncation; a v3 blob given to the v2 opener and the reverse | | Recovery code v3 (D-46) | wrong length, an invalid character, a failed check character, non-zero padding bits — each with an error code; every single wrong character and every swap of two different characters fails the check; a random typo passes it with probability 1/32 and then fails lookup, never opens another account. A version-2 code is read only when asked for by name |

4. @microtoll/identity

| Item | Bound to | So that | |---|---|---| | Wrapped root key | method type + SHA-256(credential id) or the recovery lookup hash | a blob cannot be presented under another row or on the other unlock path | | Identity blob | the routing public key; carries a revision | it cannot be moved between accounts; a rollback is refused on a device that saw a later revision (cooperative) | | Unlock-method label | the method: its type, and SHA-256(credential id) for a passkey (version 3, D-47) | it cannot be shown against another method, even another passkey of the same account, so a person removing a method is not misled about which one; nor moved between accounts (another K_master_symm) | | Trusted-device session | routing key, expiry, session generation | an edited expiry or generation in a copied profile fails to open; a stored routing key that disagrees with the derived one is refused | | Handshake signature | "<ns>/auth/v2", SHA-256(origin), the nonce (D-29) | the signature is useless for another purpose, another deployment or another connection |

5. @microtoll/access

| Item | Bound to | So that | |---|---|---| | Member-row signature | "<ns>/sig/member-row/v2", object id, row id | a row cannot be lifted into another row or object and still verify | | Member-row seal | object id, row id (AAD) | a row's ciphertext cannot be presented under another row id, quiet and unsigned rows included | | Content, second tier | object id, epoch (AAD) | content cannot be moved between objects; a reader can assert the epoch it was told | | Pointer | the account's routing key (AAD; D-37) | a pointer cannot be moved to another account or confused with another blob under K_master_symm; the object it names is inside it, since the server returns pointers without an id | | Share-link payload | the token hash (AAD) and, when signed, "<ns>/sig/share-link/v2" + the token hash | a payload cannot be served under another link's hash; a signed payload cannot be re-wrapped in a fresh link as its creator's | | Admin box | object id, epoch (AAD) | a box from another object or epoch does not open | | Sealed copy of K_object per member | the recipient key and version (ECIES v3/v2) — no additional data | a server that moves it to another of the same member's rows gains nothing the member could not do; binding it would need an ECIES v4 |

6. @microtoll/blind-store

7. @microtoll/mailbox (M3b, built inside M5)

8. Review triggers

Update this document when any of these happen: