Type Alias SenderVerification
SenderVerification:
| { state: "verified" }
| { reason: "unsigned_device"; state: "unverified" }
| { reason: "unverified_identity"; state: "unverified" }
| { reason: "verification_violation"; state: "unverified" }
| { reason: "mismatched_sender"; state: "unverified" }
| {
problem: "missing" | "insecure_source";
reason: "no_device";
state: "unverified";
}
What this library knew about the sender of one decrypted event, at the moment it decrypted it.
This is not TrustState, and the difference is why there are two.
TrustStatedescribes a device, and a completed comparison changes it. This describes one event's sender at one moment, and a completed comparison does not change it. Two subjects, two vocabularies. Folding them would lose the difference between an unverified identity, an unsigned device and a sender mismatch, which are three different things for a product to do about one event.Closed, like
TrustStateand VerificationStage: switch onstate, then onreason, and the compiler tells you when a later version adds a case.Which of these this release produces, and why the line falls where it
does
The distinction is whose cross-signing identity a value depends on, and it is not the distinction you would guess.
'unverified_identity'is produced by this release. It depends on the sender's identity, not on ours: the gate underneath asks only whether the sending device carries a signature from a self-signing key its own owner published, and this library is not consulted. So a peer whose client has cross-signing set up already produces it here, whatever this library holds, and that is most peers. Handle this branch. It is not a rare state and it is not a future one.'verified'and'verification_violation'are the two that turn on our side rather than the sender's.'verified'needs this library to hold a cross-signing identity and to have signed the sender's with it;'verification_violation'needs the sender's identity to have been verified by us once and to have changed since.'verified'arrives through this surface from this release, and the history of why it did not is worth one paragraph. It was unreachable by construction while this library had no way to create an identity of its own, which is what this paragraph used to say. Then the Rust core could create one and the TypeScript surface could not reach the call, which is what it said next. Both are now over:createCrossSigningIdentitymakes the account's first identity andbootstrapCrossSigningpublishes the one this device holds. The cryptography is proved where it can be, end to end against a counterparty the test process does not control, by the core's owntests/verified_sender.rs; that every step of it can be reached, in order, through the functions this package publishes is whatfacade.test.tsdrives. So this branch runs.'verification_violation'is the one still waiting, and it waits on a situation rather than on a missing call: it needs a sender whose chain completed and whose identity then changed. Write it anyway. They are declared because the union is closed, and widening a closed union later is a breaking change for every consumer that switched on it exhaustively, and because the alternative to a complete type is not a smaller true one but a different false one: a four-value type would say that four values is all this vocabulary has, which is not true of what it models.What arrives here today, without a count over it because a count is the part of a claim most likely to go stale:
'verified', at the end of the chain and nowhere else;'unverified_identity';'unsigned_device', the ordinary case for a peer with no cross-signing identity of their own;'no_device'in both its forms; and'mismatched_sender'.This paragraph was wrong in 0.1.0, and has been rewritten twice
It said all three of
'verified','unverified_identity'and'verification_violation'were "NOT PRODUCED BY THIS RELEASE".'unverified_identity'always was produced. That claim survived review because no test in the repository had a cross-signed counterparty, so nothing could contradict it, and it sounded like the two true sentences standing next to it. If you read it and skipped the branch, that branch is reachable and this is the correction.The other two sentences were true when they were written, and stopped being true for a different reason: the library improved. That is the lesson worth carrying rather than the specific mistake. A claim about what a build cannot produce is a claim about every peer it might meet and about every version of itself, so it needs re-reading whenever either changes, and it will not fail a test on its own when it goes stale.
'verified'in particularCompleting a verification with someone does not make their events read
'verified'. It makes their device read'verified'from getDeviceStatuses, which is a different question with a different answer. The decrypted-event path consults cross-signing; a short-string comparison sets local trust.That stays true now that the library can cross-sign, and the gap it leaves is wider than it looks. A comparison is one step of seven. The signature it produces has to be uploaded and then fetched back before any event can read
'verified', because nothing caches the signature locally and the check underneath reads the store. A chain that stops one step short returns success from every call, leaves the device reading'verified', and leaves every event from that device reading'unverified_identity', which is indistinguishable from never having verified the sender at all. If your product needs "did this specific event come from a device we have verified", it is this field that answers, and the device-level one that will mislead you. M3 design, section 7, questions 3 and 6; M4 design, section 3.1.'mismatched_sender'in particularThe only member here reporting an act rather than an absence of evidence: the event's claimed sender is not the owner of the session that encrypted it. Decryption succeeded -- the ciphertext really was encrypted with a session this device holds -- and the
senderfield is still false. Treat it as an impersonation signal, not as a weaker'no_device'.