ModelTraces.lean
Declarations on this page (76)
- def setupAct
- inductive Step
- abbrev stepIn
-
def Step.
toInput -
def Step.
next -
def Step.
ok -
def Step.
PreCond - inductive StepClass
-
def Step.
cls -
def Step.
party? -
def Step.
decryptMsgIdx? - inductive VisEventKind
- inductive VisByteLayout
- structure VisEntry
- def randTerm
- def newIndices
- def newRandoms
- def received
- def rngEntry
- def eventIdx
- def isAliceDone
- def isBobDone
- def receivedPlaintext
- def lastSent
- def kyberCoinEntries
- def aliceDraws
- def aliceVis
- def bobOpkPk
- def bobVis
- def encDraws
-
def _root_.
DY. ExecTrace. getLocalStateAt - def sessionHandshakeEvents
- def sessionBaseKeys
- def decVis
- def pqExposureAt
- def trExposureAt
- def exposures
- structure ProtocolSetup
- def setupTrace
- def setupRandoms
- def setupSent
- def setupSecret
- def setupPublic
- def ecKey
- def kyberKey
- def pubBytes
- def setupRandomsAt
- def secretBytes
- def ikBSecTerm
- def spkSecTerm
- def pqskSecTerm
- def opkSecTerm
- def ikAPubTerm
- def ikBPubTerm
- def spkSigTerm
- def pqpkPubTerm
- def pqpkSigTerm
- def ikASecBytes
- def ikBSecBytes
- def spkSecBytes
- def opkSecBytes
- def storedStates
- def sessionHasDecrypted
- def pendingPreKey
- def encSendEntry
- def stepView
- def runSteps
- def runTrace
- def encryptOwnSpqrKeyIdx
- def encryptAbortAfterSpqrIdx
-
def Step.
publishedSpqrKey? -
def Step.
LocalOk - def StepsWF
-
def Step.
stateLoad? - def StepsStateFaithful
- def ModelRunWF
Composed Model Steps, Traces, and Visible Entries
First-order step representation (Step), initial PKI/pre-key setup (ProtocolSetup, setupTrace), observable entry projection (stepView), and faithful run predicate (ModelRunWF) for the composed symbolic state machine Composed..
@[expose] public sectionnamespace DY.Libsignal.Composed.Refinementopen DY DY.Comparseopen CryptoProofLib.Refinement (ExternInterpretation)open DY.Libsignal.Refinement (x25519PublicKeySymbol)open PQXDH (PQXDHEvent BundleHandles BobKeyHandles PreKeyMsgHandles)def setupAct
Provision Alice's and Bob's honest identities, Bob's signed X25519 and Kyber-1024 prekeys, and (when withOpk holds) one one-time prekey for Bob.
def setupAct (a b : Participant) (withOpk : Bool) : Traceful Unit := do
let _ ← PQXDH.registerIdentity a
let hB ← PQXDH.registerIdentity b
let _ ← PQXDH.genSignedPrekey b hB
let _ ← PQXDH.genPQPrekey b hB
if withOpk then do let _ ← PQXDH.genOneTimePrekey b; pure ()inductive Step
First-order inductive mirror of the 23 transitions in Composed..
inductive Step where
| network (msg : DY.Bytes)
| registerIdentity (p : Participant)
| registerCorruptIdentity (p : Participant) (skIdx : Nat)
| genSignedPrekey (b : Participant) (idStateIdx : Nat)
| genPQPrekey (b : Participant) (idStateIdx : Nat)
| genOneTimePrekey (b : Participant)
| aliceStart (a b : Participant) (idStateIdx regIdxB : Nat) (h : BundleHandles)
| bobStart (b a : Participant) (kh : BobKeyHandles) (regIdxA : Nat) (mh : PreKeyMsgHandles)
(pqIdx : Nat) (spqrMsgIdx : UInt32)
| messageEncrypt (me : Participant) (stateIdx coinsLen pqIdx : Nat)
| messageEncryptAbort (me : Participant) (stateIdx : Nat)
| messageDecrypt (me : Participant) (stateIdx msgIdx pqIdx : Nat) (spqrMsgIdx : UInt32)
| messageDecryptSkipped (me : Participant) (stateIdx msgIdx skippedKeyEventIdx pqIdx : Nat)
(spqrMsgIdx : UInt32)
| exposeKey (me : Participant) (stateIdx : Nat) (k : TripleRatchet.KeyComponent)
| exposeSpqr (me : Participant) (stateIdx : Nat)
| exposeSkipped (skippedKeyEventIdx : Nat)
| compromiseIK (p : Participant) (stateIdx : Nat)
| compromiseSPK (b : Participant) (stateIdx : Nat)
| compromisePQSPK (b : Participant) (stateIdx : Nat)
| compromiseOPK (b : Participant) (stateIdx : Nat)
| breakDH
| breakKEM
| invertDH (pkIdx : Nat)
| invertKEM (pkIdx : Nat)abbrev stepIn
abbrev stepIn (c : ReachabilityConfig) [i : ReachabilityConfig.HasStep c reachability]
(x : c.Input) : reachability.Input :=
i.inj x
def Step.
def Step.toInput : Step → reachability.Input
| .network msg => stepIn Network.reachability msg
| .registerIdentity p => stepIn PQXDH.registerIdentity.reachability p
| .registerCorruptIdentity p skIdx => stepIn PQXDH.registerCorruptIdentity.reachability (p, skIdx)
| .genSignedPrekey b i => stepIn PQXDH.genSignedPrekey.reachability (b, i)
| .genPQPrekey b i => stepIn PQXDH.genPQPrekey.reachability (b, i)
| .genOneTimePrekey b => stepIn PQXDH.genOneTimePrekey.reachability b
| .aliceStart a b idStateIdx regIdxB h =>
stepIn Composed.aliceStart.reachability (a, b, idStateIdx, regIdxB, h)
| .bobStart b a kh regIdxA mh pqIdx spqrMsgIdx =>
stepIn Composed.bobStart.reachability (b, a, kh, regIdxA, mh, pqIdx, spqrMsgIdx)
| .messageEncrypt me stateIdx coinsLen pqIdx =>
stepIn TripleRatchet.messageEncrypt.reachability (me, stateIdx, coinsLen, pqIdx)
| .messageEncryptAbort me stateIdx =>
stepIn TripleRatchet.messageEncryptAbort.reachability (me, stateIdx)
| .messageDecrypt me stateIdx msgIdx pqIdx spqrMsgIdx =>
stepIn TripleRatchet.messageDecrypt.reachability (me, stateIdx, msgIdx, pqIdx, spqrMsgIdx)
| .messageDecryptSkipped me stateIdx msgIdx skIdx pqIdx spqrMsgIdx =>
stepIn TripleRatchet.messageDecryptSkipped.reachability
(me, stateIdx, msgIdx, skIdx, pqIdx, spqrMsgIdx)
| .exposeKey me stateIdx k => stepIn TripleRatchet.exposeKey.reachability (me, stateIdx, k)
| .exposeSpqr me stateIdx => stepIn TripleRatchet.exposeSpqr.reachability (me, stateIdx)
| .exposeSkipped skIdx => stepIn TripleRatchet.exposeSkipped.reachability skIdx
| .compromiseIK p stateIdx => stepIn PQXDH.compromiseIK.reachability (p, stateIdx)
| .compromiseSPK b stateIdx => stepIn PQXDH.compromiseSPK.reachability (b, stateIdx)
| .compromisePQSPK b stateIdx => stepIn PQXDH.compromisePQSPK.reachability (b, stateIdx)
| .compromiseOPK b stateIdx => stepIn PQXDH.compromiseOPK.reachability (b, stateIdx)
| .breakDH => stepIn PQXDH.breakDH.reachability ()
| .breakKEM => stepIn PQXDH.breakKEM.reachability ()
| .invertDH pkIdx => stepIn PQXDH.invertDH.reachability pkIdx
| .invertKEM pkIdx => stepIn PQXDH.invertKEM.reachability pkIdx
def Step.
Resulting trace after running s on tr.
def Step.
Whether s succeeds on tr.
def Step.
Reachability precondition of s on tr.
inductive StepClass
Alignment category of a Step with respect to CLI trace events.
inductive StepClass where
/-- Honest party transition matched by one exit-0 CLI `RunEvent`. -/
| party
/-- Compromise, exposure, break, inversion, or corrupt registration matched by one `EnvEvent`. -/
| env
/-- Attacker `network` deduction step matched by no CLI event. -/
| invisible
/-- Key-provisioning step permitted only in the initial setup prefix. -/
| setup
deriving DecidableEq
def Step.
def Step.cls : Step → StepClass
| .network .. => .invisible
| .registerIdentity .. => .setup
| .genSignedPrekey .. => .setup
| .genPQPrekey .. => .setup
| .genOneTimePrekey .. => .setup
| .aliceStart .. => .party
| .bobStart .. => .party
| .messageEncrypt .. => .party
| .messageEncryptAbort .. => .party
| .messageDecrypt .. => .party
| .messageDecryptSkipped .. => .party
| .exposeKey .. => .env
| .exposeSpqr .. => .env
| .exposeSkipped .. => .env
| .compromiseIK .. => .env
| .compromiseSPK .. => .env
| .compromisePQSPK .. => .env
| .compromiseOPK .. => .env
| .breakDH => .env
| .breakKEM => .env
| .invertDH .. => .env
| .invertKEM .. => .env
| .registerCorruptIdentity .. => .env
def Step.
Acting or compromised participant of a step (none for exposeSkipped and global steps).
def Step.party? : Step → Option Participant
| .aliceStart a .. => some a
| .bobStart b .. => some b
| .messageEncrypt me .. => some me
| .messageEncryptAbort me _ => some me
| .messageDecrypt me .. => some me
| .messageDecryptSkipped me .. => some me
| .exposeKey me .. => some me
| .exposeSpqr me _ => some me
| .compromiseIK p _ => some p
| .compromiseSPK b _ => some b
| .compromisePQSPK b _ => some b
| .compromiseOPK b _ => some b
| _ => none
def Step.
Network handle read by messageDecrypt or messageDecryptSkipped (none otherwise).
def Step.decryptMsgIdx? : Step → Option Nat
| .messageDecrypt _ _ msgIdx .. => some msgIdx
| .messageDecryptSkipped _ _ msgIdx .. => some msgIdx
| _ => noneinductive VisEventKind
Observable kind of a VisEntry (pt, send, rng, accept, recv, or leak).
inductive VisEventKind where
| pt | send | rng | accept | recv | leak
deriving DecidableEqinductive VisByteLayout
inductive VisByteLayout where
| single
| whisper
| bundle
| preKeySend
| preKeyRecv
/-- `0x03 || PreKeySignalMessage` decrypted on an existing Bob session whose base key lies in
`eks` (`promote_matching_session`). -/
| preKeyInner (eks : List DY.Bytes)
| fresh (n : Nat)
| kyberCoin (j : Nat)
| unconstrained
| leakPq (pq : Bool)
| leakRecord
deriving DecidableEqstructure VisEntry
Observable entry emitted by a Step, with optional trace index anchor of its logged event.
structure VisEntry where
kind : VisEventKind
terms : List DY.Bytes
layout : VisByteLayout
anchor : Option Natdef randTerm
def randTerm (i n : Nat) : DY.Bytes := ({timestamp := i, size := n} : DY.Random.Random DY.Bytes).packdef newIndices
def newIndices (tr tr' : ExecTrace) : List Nat := List.range' tr.length (tr'.length - tr.length)def newRandoms
def newRandoms (tr tr' : ExecTrace) : List (DY.Bytes × Nat) :=
(newIndices tr tr').filterMap fun i =>
(tr'.at? i : Option DY.Random.ExecEntryT).map fun e => (randTerm i e.length, e.length)def received
def received (tr : ExecTrace) (hs : List Nat) : List DY.Bytes :=
hs.filterMap fun i => tr.getMessageSentAt idef eventIdx
def eventIdx (p : PQXDHEvent → Bool) (tr tr' : ExecTrace) : Option Nat :=
(newIndices tr tr').find? fun i => ((tr'.getEventAt PQXDHEvent i).map p).getD falsedef isAliceDone
def isAliceDone : PQXDHEvent → Bool
| .AliceDone .. => true
| _ => falsedef isBobDone
def isBobDone : PQXDHEvent → Bool
| .BobDone .. => true
| _ => falsedef receivedPlaintext
def receivedPlaintext (tr tr' : ExecTrace) : Option DY.Bytes :=
(newIndices tr tr').findSome? fun i =>
match tr'.getEventAt TREvent i with
| some (.Received _ _ _ _ m) => some m
| _ => nonedef lastSent
def lastSent (tr tr' : ExecTrace) : Option DY.Bytes :=
if tr.length < tr'.length then tr'.getMessageSentAt (tr'.length - 1) else nonedef kyberCoinEntries
def kyberCoinEntries (entropy : DY.Bytes) : List VisEntry :=
(List.range 32).map fun j => ⟨.rng, [entropy], .kyberCoin j, none⟩def aliceDraws
def aliceVis
def aliceVis (tr tr' : ExecTrace) (h : BundleHandles) : List VisEntry :=
⟨.recv, received tr ([h.spk, h.spkSig, h.pqpk, h.pqpkSig] ++ h.opk.toList), .bundle, none⟩ ::
aliceDraws (eventIdx isAliceDone tr tr') ((newRandoms tr tr').map (·.1))def bobOpkPk
def bobOpkPk (b : Participant) (h : BobKeyHandles) (tr : ExecTrace) : Option DY.Bytes :=
h.opk.bind fun i => ((PQXDH.getKey b i .oneTimePrekey).run tr).1.map DY.DiffieHellman.dhPkdef bobVis
def bobVis (tr tr' : ExecTrace) (mh : PreKeyMsgHandles) (opk : Option DY.Bytes) :
List VisEntry :=
⟨.recv, received tr [mh.ek, mh.ct, mh.msg] ++ opk.toList, .preKeyRecv, none⟩ ::
(newRandoms tr tr').map (fun r => rngEntry r.1) ++
((receivedPlaintext tr tr').map fun m =>
(⟨.accept, [m], .single, eventIdx isBobDone tr tr'⟩ : VisEntry)).toListdef encDraws
def _root_.
def _root_.DY.ExecTrace.getLocalStateAt (StateT : Type) [ExecTraceTypes]
[ExecTraceTypes.Has (PersistentGlobalState.State.ExecEntryT
(PersistentLocalState.LocalState StateT))]
(tr : ExecTrace) (i : Nat) : Option (PersistentLocalState.LocalState StateT) :=
(tr.at? i : Option (PersistentGlobalState.State.ExecEntryT
(PersistentLocalState.LocalState StateT))).map (·.st)def sessionHandshakeEvents
def sessionHandshakeEvents (tr : ExecTrace) (s0 : TripleRatchet.SessionInfo) : List PQXDHEvent :=
(List.range tr.length).filterMap fun i =>
match tr.getEventAt ComposedEvent i with
| some (.HandshakeSession s d) => if s = s0 then tr.getEventAt PQXDHEvent d else none
| none => nonedef sessionBaseKeys
Base keys (alice_base_key) recorded by BobDone events linked to the session stored at stateIdx on tr.
def sessionBaseKeys (tr : ExecTrace) (stateIdx : Nat) : List DY.Bytes :=
match tr.getLocalStateAt TRState stateIdx with
| some ls =>
(sessionHandshakeEvents tr (ls.state.sessionInfo ls.participant)).filterMap fun
| .BobDone _ _ _ _ _ _ _ ek _ _ => some ek
| _ => none
| none => []def decVis
def decVis (tr tr' : ExecTrace) (stateIdx msgIdx : Nat) (wrapped : Bool) : List VisEntry :=
((tr.getMessageSentAt msgIdx).map fun b =>
(⟨.recv, [b], if wrapped then .preKeyInner (sessionBaseKeys tr stateIdx) else .whisper,
none⟩ : VisEntry)).toList ++
(newRandoms tr tr').map (fun r => rngEntry r.1) ++
((receivedPlaintext tr tr').map fun m => (⟨.accept, [m], .single, none⟩ : VisEntry)).toListdef pqExposureAt
def pqExposureAt (tr' : ExecTrace) (j : Nat) : Option VisEntry :=
let term := (tr'.getMessageSentAt (j + 1)).toList
match tr'.getEventAt PQXDHEvent j with
| some (.CompromisedIK ..) | some (.CompromisedSPK ..) | some (.CompromisedOPK ..) =>
some ⟨.leak, term, .leakPq false, some j⟩
| some (.CompromisedPQSPK ..) => some ⟨.leak, term, .leakPq true, some j⟩
| _ => nonedef trExposureAt
def trExposureAt (tr' : ExecTrace) (j : Nat) : Option VisEntry :=
let term := (tr'.getMessageSentAt (j + 1)).toList
match tr'.getEventAt TREvent j with
| some (.ExposedRK ..) | some (.ExposedDHs ..) | some (.ExposedCKs ..)
| some (.ExposedCKr ..) | some (.ExposedMK ..) | some (.ExposedSpqr ..) =>
some ⟨.leak, term, .leakRecord, some j⟩
| _ => nonedef exposures
def exposures (tr tr' : ExecTrace) : List VisEntry :=
(newIndices tr tr').filterMap (pqExposureAt tr') ++ (newIndices tr tr').filterMap (trExposureAt tr')structure ProtocolSetup
Provisioned setup parameters: Alice and Bob identities, registration and prekey IDs, Bob's 3169-byte Kyber secret key, and concrete bytes for setup draws (fresh) and opaque public terms (opaqueBytes).
def setupTrace
Initial model trace produced by running setupAct on the empty trace.
def setupTrace (r : ProtocolSetup) : ExecTrace := ((setupAct r.alice r.bob r.withOpk).run Trace.nil).2.valdef setupRandoms
def setupRandoms (r : ProtocolSetup) : List DY.Bytes := (newRandoms Trace.nil (setupTrace r)).map (·.1)def setupSent
def setupSent (r : ProtocolSetup) : List DY.Bytes :=
(newIndices Trace.nil (setupTrace r)).filterMap fun i => (setupTrace r).getMessageSentAt idef setupSecret
def setupSecret (r : ProtocolSetup) (k : Nat) : DY.Bytes := ((setupRandoms r)[k]?).getD (randTerm 0 0)def setupPublic
def setupPublic (r : ProtocolSetup) (k : Nat) : DY.Bytes := ((setupSent r)[k]?).getD (randTerm 0 0)def pubBytes
X25519 public key bytes computed from clamped private key bytes b.
def pubBytes (interpretation : ExternInterpretation) (b : HwBytes) : HwBytes :=
(interpretation x25519PublicKeySymbol [clamp b]).getD []def setupRandomsAt
def setupRandomsAt (r : ProtocolSetup) : List (Nat × Nat) :=
(newIndices Trace.nil (setupTrace r)).filterMap fun i =>
((setupTrace r).at? i : Option DY.Random.ExecEntryT).map fun e => (i, e.length)def secretBytes
def secretBytes (r : ProtocolSetup) (k : Nat) : HwBytes :=
(((setupRandomsAt r)[k]?).map fun p => r.fresh p.1 p.2).getD []namespace ProtocolSetup1 declaration not shown (lines 366–366): theorems, which Lean checks, or definitions that no headline statement uses
DY.
def ikBSecTerm
def ikBSecTerm (r : ProtocolSetup) : DY.Bytes := setupSecret r 1def spkSecTerm
def spkSecTerm (r : ProtocolSetup) : DY.Bytes := setupSecret r 2def pqskSecTerm
def pqskSecTerm (r : ProtocolSetup) : DY.Bytes := setupSecret r 4def opkSecTerm
def opkSecTerm (r : ProtocolSetup) : DY.Bytes := setupSecret r 6def ikAPubTerm
def ikAPubTerm (r : ProtocolSetup) : DY.Bytes := setupPublic r 0def ikBPubTerm
def ikBPubTerm (r : ProtocolSetup) : DY.Bytes := setupPublic r 21 declaration not shown (lines 374–374): theorems, which Lean checks, or definitions that no headline statement uses
DY.
def spkSigTerm
def spkSigTerm (r : ProtocolSetup) : DY.Bytes := setupPublic r 5def pqpkPubTerm
def pqpkPubTerm (r : ProtocolSetup) : DY.Bytes := setupPublic r 6def pqpkSigTerm
def pqpkSigTerm (r : ProtocolSetup) : DY.Bytes := setupPublic r 71 declaration not shown (lines 378–378): theorems, which Lean checks, or definitions that no headline statement uses
DY.
def ikASecBytes
def ikASecBytes (r : ProtocolSetup) : HwBytes := secretBytes r 0def ikBSecBytes
def ikBSecBytes (r : ProtocolSetup) : HwBytes := secretBytes r 1def spkSecBytes
def spkSecBytes (r : ProtocolSetup) : HwBytes := secretBytes r 2def opkSecBytes
def opkSecBytes (r : ProtocolSetup) : HwBytes := secretBytes r 6end ProtocolSetupdef storedStates
def storedStates (r : ProtocolSetup) (tr : ExecTrace) :
List (PersistentLocalState.LocalState TRState) :=
(newIndices (setupTrace r) tr).filterMap (tr.getLocalStateAt TRState)def sessionHasDecrypted
Whether session s has decrypted any incoming message before stateIdx.
def sessionHasDecrypted (tr : ExecTrace) (s : TripleRatchet.SessionInfo) (stateIdx : Nat) : Bool :=
(List.range stateIdx).any fun j =>
match tr.getEventAt TREvent j with
| some (.MessageKey s' .receiver ..) => decide (s' = s)
| _ => falsedef pendingPreKey
Pending (ek, ct) pre-key items for an Alice session at stateIdx prior to decrypting a reply (none once acknowledged or for Bob sessions).
def pendingPreKey (tr : ExecTrace) (stateIdx : Nat) : Option (DY.Bytes × DY.Bytes) :=
match tr.getLocalStateAt TRState stateIdx with
| some ls =>
let s0 := ls.state.sessionInfo ls.participant
if sessionHasDecrypted tr s0 stateIdx then none
else
(sessionHandshakeEvents tr s0).findSome? fun
| .AliceDone _ _ _ _ _ _ _ ek ct _ => some (ek, ct)
| _ => none
| none => nonedef encSendEntry
Observable send entry of an encryption step on stateIdx, matching wrapped against pendingPreKey tr stateIdx.
def encSendEntry (tr tr' : ExecTrace) (stateIdx : Nat) (wrapped : Bool) : List VisEntry :=
match lastSent tr tr' with
| some w =>
match wrapped, pendingPreKey tr stateIdx with
| true, some (ek, ct) => [⟨.send, [ek, ct, w], .preKeySend, none⟩]
| false, none => [⟨.send, [w], .whisper, none⟩]
| _, _ => []
| none => []def stepView
Observable VisEntry sequence emitted by running s from tr (suppressing send and accept entries when s.).
def stepView (s : Step) (tr : ExecTrace) (wrapped : Bool) : List VisEntry :=
let tr' := s.next tr
let own : List VisEntry :=
match s with
| .aliceStart _ _ _ _ h => aliceVis tr tr' h
| .bobStart b _ kh _ mh _ _ => bobVis tr tr' mh (bobOpkPk b kh tr)
| .messageEncrypt _ stateIdx .. =>
encDraws (newRandoms tr tr') ++ encSendEntry tr tr' stateIdx wrapped
| .messageEncryptAbort .. => encDraws (newRandoms tr tr')
| .messageDecrypt _ stateIdx msgIdx .. => decVis tr tr' stateIdx msgIdx wrapped
| .messageDecryptSkipped _ stateIdx msgIdx .. => decVis tr tr' stateIdx msgIdx wrapped
| _ => []
(if s.ok tr then own else own.filter fun v => v.kind != .send && v.kind != .accept) ++
exposures tr tr'def runSteps
def runTrace
Trace produced by running ss starting from setupTrace r.
def runTrace (r : ProtocolSetup) (ss : List Step) : ExecTrace := runSteps ss (setupTrace r)def encryptOwnSpqrKeyIdx
Trace handle at which messageEncrypt run from tr publishes its SPQR send key.
def encryptOwnSpqrKeyIdx (tr : ExecTrace) : Nat := tr.length + 2def encryptAbortAfterSpqrIdx
Out-of-range pqIdx handle modeling an spqr::send failure after coin draw and key publication.
def encryptAbortAfterSpqrIdx (tr : ExecTrace) : Nat := tr.length + 3
def Step.
SPQR send key published by a non-aborting messageEncrypt step s on tr.
def Step.publishedSpqrKey? (s : Step) (tr : ExecTrace) : Option DY.Bytes :=
match s with
| .messageEncrypt _ _ _ pqIdx =>
if pqIdx = encryptAbortAfterSpqrIdx tr then none
else (s.next tr).getMessageSentAt (encryptOwnSpqrKeyIdx tr)
| _ => none
def Step.
Step-local refinement invariants on s at tr: exposures target current snapshots/chains, and messageEncrypt draws coinsLen ∈ {0, 32, 64} and reads its own SPQR key handle (or aborts via encryptAbortAfterSpqrIdx tr).
def Step.LocalOk (s : Step) (tr : ExecTrace) : Prop :=
match s with
| .exposeKey _ stateIdx _ | .exposeSpqr _ stateIdx =>
TripleRatchet.isCurrentSnapshot tr stateIdx = true
| .exposeSkipped skIdx =>
TripleRatchet.isSkippedChainCurrent tr skIdx = true
| .messageEncrypt _ _ coinsLen pqIdx =>
(coinsLen = 0 ∨ coinsLen = 32 ∨ coinsLen = 64) ∧
(pqIdx = encryptOwnSpqrKeyIdx tr ∨ pqIdx = encryptAbortAfterSpqrIdx tr)
| _ => Truedef StepsWF
def Step.
(me, stateIdx, storesSuccessor) for steps that load a stored TRState snapshot.
def Step.stateLoad? : Step → Option (Participant × Nat × Bool)
| .messageEncrypt me stateIdx .. => some (me, stateIdx, true)
| .messageEncryptAbort me stateIdx => some (me, stateIdx, false)
| .messageDecrypt me stateIdx .. => some (me, stateIdx, true)
| .messageDecryptSkipped me stateIdx .. => some (me, stateIdx, true)
| _ => nonedef StepsStateFaithful
Linear consumption of stored session snapshots: once a step loads snapshot k and succeeds in storing a successor, no later step loads k.
def StepsStateFaithful (r : ProtocolSetup) (ss : List Step) : Prop :=
∀ (i j : Nat) (si sj : Step) (p : Participant) (k : Nat) (b : Bool), i < j →
ss[i]? = some si → ss[j]? = some sj →
si.stateLoad? = some (p, k, true) →
si.ok (runTrace r (ss.take i)) = true →
sj.stateLoad? = some (p, k, b) → Falsedef ModelRunWF
Faithful model run ss from ProtocolSetup r: setup draws succeed and are reachable, every step satisfies PreCond and LocalOk, and stored session snapshots are consumed linearly.
def ModelRunWF (r : ProtocolSetup) (ss : List Step) : Prop :=
(setupRandoms r).length = (if r.withOpk then 7 else 6) ∧
(setupTrace r).Reachable reachability ∧
StepsWF ss (setupTrace r) ∧
StepsStateFaithful r ssend DY.Libsignal.Composed.Refinement