Secure Messaging

8.4. RKEM from KEM🔗

Definition8.4.1
Group: RKEM from KEM. (3)
Group member previews
Preview
Theorem 8.4.2
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 1
Used by 3
Reverse dependency previews
Preview
Theorem 8.4.2
Loading preview
Reverse dependency preview content is loaded from the rendered-fragment cache.
✓L∃∀N

\todo

fresh/updated ratcheting key generation

def rkeygen {m : Type → Type u} [Monad m] {K PK SK C : Type} (kem : KEMScheme m K PK SK C) : Unit → m (PK × SK) := fun _ => kem.keygen

encapsulation

def renc {m : Type → Type u} [Monad m] {K PK SK C : Type} (kem : KEMScheme m K PK SK C) (_par : Unit) (ekPeer : PK) (_dkSelf : SK) : m ((PK × C) × K × SK) := do let (ct, key) ← kem.encaps ekPeer let (ekSelfHat, dkSelfHat) ← kem.keygen return ((ekSelfHat, ct), key, dkSelfHat)

decapsulation

def rdec {m : Type → Type u} [Monad m] {K PK SK C : Type} (kem : KEMScheme m K PK SK C) (total : TotalDecaps kem) (_par : Unit) (dkSelfHat : SK) (ctSelf : PK × C) (_ekPeer : PK) : m (K × PK) := do let (ekPeerHat, ct) := ctSelf -- We have that kem.decaps dkSelfHat ct = some <$> decapsTotal dkSelfHat ct let key ← total.decapsTotal dkSelfHat ct return (key, ekPeerHat)

generic RKEM scheme

def scheme {m : Type → Type u} [Monad m] {K PK SK C : Type} (kem : KEMScheme m K PK SK C) (total : TotalDecaps kem) : RKEMScheme m Unit PK SK (PK × C) K where rsetup := pure () rkeygenAFresh := rkeygen kem rkeygenAUpdated := rkeygen kem rkeygenBFresh := rkeygen kem rkeygenBUpdated := rkeygen kem rencA := renc kem rdecA := rdec kem total rencB := renc kem rdecB := rdec kem total

Security notions that expose algorithm coins are stated relative to a randomness-leak package of the RKEM. For this construction it is built from one of the underlying KEM: fresh key generation leaks the coins of \KeyGen, and \REnc\text{-}\mathsf{P}, which runs \Enc and then \KeyGen, leaks the pair of their coins.

Leaking encapsulation

def rencRleak {kem : KEMScheme m K PK SK C} (kemLeak : kem.RandLeak) (_par : Unit) (ekPeer : PK) (_dkSelf : SK) : m (((PK × C) × K × SK) × kemLeak.Rand) := do let ((ct, key), encRand) ← kemLeak.encapsRleak ekPeer let ((ekSelfHat, dkSelfHat), keygenRand) ← kemLeak.keygenRleak return (((ekSelfHat, ct), key, dkSelfHat), (encRand, keygenRand))

Randomness-leak package

def randLeak (kem : KEMScheme m K PK SK C) (total : TotalDecaps kem) (kemLeak : kem.RandLeak) : (scheme kem total).RandLeak where KeygenRand := kemLeak.KeygenRand EncRand := kemLeak.Rand rkeygenAFreshRleak := fun _ => kemLeak.keygenRleak rkeygenBFreshRleak := fun _ => kemLeak.keygenRleak rencARleak := rencRleak kemLeak rencBRleak := rencRleak kemLeak rkeygenAFresh_fst := fun _ => kemLeak.keygen_fst rkeygenBFresh_fst := fun _ => kemLeak.keygen_fst rencA_fst := rencRleak_fst kemLeak rencB_fst := rencRleak_fst kemLeak
Lean code for Definition8.4.1●3 definitions
  • def kemRKEM.scheme.{u} {m : Type → Type u} [Monad m] {K PK SK C : Type}
      (kem : KEMScheme m K PK SK C) (total : kem.TotalDecaps) :
      RKEMScheme m Unit PK SK (PK × C) K
    def kemRKEM.scheme.{u} {m : Type → Type u}
      [Monad m] {K PK SK C : Type}
      (kem : KEMScheme m K PK SK C)
      (total : kem.TotalDecaps) :
      RKEMScheme m Unit PK SK (PK × C) K
    Generic RKEM scheme induced by a KEM ([TripleRatchet, Appendix A.1, Fig. 26]). Public
    parameters are vacuous; the ratcheting key spaces are the KEM's own key spaces, with fresh
    and updated distributions coinciding; ciphertexts bundle a freshly generated public key
    with the underlying KEM ciphertext. Requires a witness `total` that `kem`'s decapsulation is
    total, matching `RKEMScheme`'s decapsulation algorithms, which never fail.
    
    The encapsulation and decapsulation algorithms are the same for `A` and `B`. 
  • def kemRKEM.rencRleak.{u} {m : Type → Type u} [Monad m] {K PK SK C : Type}
      {kem : KEMScheme m K PK SK C} (kemLeak : kem.RandLeak) (_par : Unit)
      (ekPeer : PK) (_dkSelf : SK) : m (((PK × C) × K × SK) × kemLeak.Rand)
    def kemRKEM.rencRleak.{u} {m : Type → Type u}
      [Monad m] {K PK SK C : Type}
      {kem : KEMScheme m K PK SK C}
      (kemLeak : kem.RandLeak) (_par : Unit)
      (ekPeer : PK) (_dkSelf : SK) :
      m (((PK × C) × K × SK) × kemLeak.Rand)
    KEM-RKEM encapsulation `REnc-P` (`renc`), also returning its coins: the coins of the KEM
    encapsulation `Enc(êkP̄)` followed by those of the fresh key generation `KeyGen()`.
    
    P̄ above corresponds to Peer below, while P corresponds to Self. 
  • def kemRKEM.randLeak.{u} {m : Type → Type u} [Monad m] [LawfulMonad m]
      {K PK SK C : Type} (kem : KEMScheme m K PK SK C)
      (total : kem.TotalDecaps) (kemLeak : kem.RandLeak) :
      (kemRKEM.scheme kem total).RandLeak
    def kemRKEM.randLeak.{u} {m : Type → Type u}
      [Monad m] [LawfulMonad m]
      {K PK SK C : Type}
      (kem : KEMScheme m K PK SK C)
      (total : kem.TotalDecaps)
      (kemLeak : kem.RandLeak) :
      (kemRKEM.scheme kem total).RandLeak
    Randomness-leak package of the RKEM-from-KEM construction, built from a randomness-leak
    package `kemLeak` of the underlying KEM. Fresh key generation `RKeyGen-P(par, ⊥)` is KEM key
    generation and leaks its coins; `REnc-P` leaks the coins of its KEM encapsulation and of its
    fresh key generation (`rencRleak`). As for the construction itself, both parties coincide. 
Theorem8.4.2
Group: RKEM from KEM. (3)
Group member previews
Preview
Definition 8.4.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 8.1.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0✓L∃∀N

\todo

theorem deltaCorrect [DecidableEq K] (kem : KEMScheme ProbComp K PK SK C) (total : TotalDecaps kem) (δ : ℝ≥0∞) (hkem : kem.deltaCorrect ProbCompRuntime.probComp δ) : RKEMScheme.deltaCorrect (scheme kem total) ProbCompRuntime.probComp δ 0
Lean code for Theorem8.4.2●1 theorem
  • theorem kemRKEM.deltaCorrect {K PK SK C : Type} [DecidableEq K]
      (kem : KEMScheme ProbComp K PK SK C) (total : kem.TotalDecaps)
      (δ : ENNReal) (hkem : kem.deltaCorrect ProbCompRuntime.probComp δ) :
      (kemRKEM.scheme kem total).deltaCorrect ProbCompRuntime.probComp δ 0
    theorem kemRKEM.deltaCorrect {K PK SK C : Type}
      [DecidableEq K]
      (kem : KEMScheme ProbComp K PK SK C)
      (total : kem.TotalDecaps) (δ : ENNReal)
      (hkem :
        kem.deltaCorrect
          ProbCompRuntime.probComp δ) :
      (kemRKEM.scheme kem total).deltaCorrect
        ProbCompRuntime.probComp δ 0
    **Quantitative correctness** (Def. 5.3) of the RKEM-from-KEM construction: if the underlying
    KEM is `δ`-correct, the construction is `(δ, 0)`-correct — the update-key-distribution error is
    exactly zero regardless of `δ`, by `evalDist_ratchetRoundOutputA_eq_evalDist_keygen`; only the
    `K = K'` error inherits `δ` from the underlying KEM. 
Theorem8.4.3
Group: RKEM from KEM. (3)
Group member previews
Preview
Definition 8.4.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 8.1.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0✓L∃∀N

\todo

IND-CPA reduction adversary

def indCpaReduction (kem : KEMScheme ProbComp K PK SK C) (adversary : RKEMScheme.FSINDCPAAdversary Unit PK SK (PK × C) K) : kem.IND_CPA_Adversary where State := PK preChallenge := fun ekBHat => pure ekBHat postChallenge := fun ekBHat ct kb => do let (ekA, _dkA) ← kem.keygen let (ekAHat, dkAHat) ← kem.keygen let b' ← adversary () ekA ekAHat ekBHat (ekAHat, ct) dkAHat kb return !b'

FS-IND-CPA security

theorem FSINDCPASecure (kem : KEMScheme ProbComp K PK SK C) (total : TotalDecaps kem) (ε : ℝ) (hcpa : ∀ adv : kem.IND_CPA_Adversary, kem.IND_CPA_Advantage ProbCompRuntime.probComp adv ≤ ε) (adversaryA adversaryB : RKEMScheme.FSINDCPAAdversary Unit PK SK (PK × C) K) : RKEMScheme.FSINDCPASecure (scheme kem total) adversaryA adversaryB (ε / 2)
Lean code for Theorem8.4.3●1 theorem
  • complete
    theorem kemRKEM.FSINDCPASecure {K PK SK C : Type} [SampleableType K]
      (kem : KEMScheme ProbComp K PK SK C) (total : kem.TotalDecaps) (ε : ℝ)
      (hcpa :
        ∀ (adv : kem.IND_CPA_Adversary),
          KEMScheme.IND_CPA_Advantage ProbCompRuntime.probComp adv ≤ ε)
      (adversaryA adversaryB :
        RKEMScheme.FSINDCPAAdversary Unit PK SK (PK × C) K) :
      (kemRKEM.scheme kem total).FSINDCPASecure adversaryA adversaryB
        (ε / 2)
    theorem kemRKEM.FSINDCPASecure {K PK SK C : Type}
      [SampleableType K]
      (kem : KEMScheme ProbComp K PK SK C)
      (total : kem.TotalDecaps) (ε : ℝ)
      (hcpa :
        ∀ (adv : kem.IND_CPA_Adversary),
          KEMScheme.IND_CPA_Advantage
              ProbCompRuntime.probComp adv ≤
            ε)
      (adversaryA adversaryB :
        RKEMScheme.FSINDCPAAdversary Unit PK
          SK (PK × C) K) :
      (kemRKEM.scheme kem
            total).FSINDCPASecure
        adversaryA adversaryB (ε / 2)
    **FS-IND-CPA security** (Def. 5.4) of the RKEM-from-KEM construction: if the underlying KEM is
    `ε`-IND-CPA-secure, uniformly over every adversary, the construction is FS-IND-CPA-secure at
    `ε / 2`. The `/ 2` is a convention conversion, not a loss; see the module docstring. 
Theorem8.4.4
Group: RKEM from KEM. (3)
Group member previews
Preview
Definition 8.4.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 8.1.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0✓L∃∀N

Adapted from Dodis et al. (2025), Theorem A.2 and Figure 27.

The RKEM from KEM is perfectly ratchet simulatable: with the simulators below, the real and simulated distributions of base-key, updated-key and ciphertext simulatability coincide, so every distinguisher has advantage 0. This holds for any KEM whose decapsulation is total, which the construction itself already requires, with no correctness or security assumption.

Perfect ratchet simulatability

theorem RatchetSimulatable (kem : KEMScheme ProbComp K PK SK C) (total : TotalDecaps kem) (kemLeak : kem.RandLeak) : (scheme kem total).RatchetSimulatable (leak := randLeak kem total kemLeak) 0

Ratchet simulatability is stated relative to the construction's randomness-leak package, built from one of the underlying KEM (see the RKEM from KEM construction).

The simulators are the same for both parties \mathsf{P}\in\{\A,\B\}, with peer \mathsf{\bar P}. They follow Figure 27 of the paper, with the changes marked in comments, which make the simulation perfect: as printed, \RSimCtxt\text{-}\mathsf{P} reuses \ekh{P} as the fresh key \ek_\mathsf{P}, which the real distribution samples independently, and \RSimKey\text{-}\mathsf{P}_2 returns K twice, which would require a perfectly correct KEM. The figure also returns the outputs of \RSimKey\text{-}\mathsf{P}_1 in a different order.

\RSimKey\text{-}\mathsf{P}_1(\ek_\mathsf{P},\dk_\mathsf{P})

\begin{array}{l} (\ekh{P},\dkh{P})\sample\KeyGen(1^\lambda;\rand) \\ \aux_1:=(\ekh{P},\rand) \\ \Return(\ekh{P},\dkh{P},\aux_1) \end{array}

RSimKey-P₁

def rsimKey1 {kem : KEMScheme ProbComp K PK SK C} (kemLeak : kem.RandLeak) (_par : Unit) (_ekSelf : PK) (_dkSelf : SK) : ProbComp (PK × SK × (PK × kemLeak.KeygenRand)) := do let ((ekSelfHat, dkSelfHat), rand) ← kemLeak.keygenRleak return (ekSelfHat, dkSelfHat, (ekSelfHat, rand))
\RSimKey\text{-}\mathsf{P}_2(\ekh{\bar P},\dkh{\bar P},\aux_1)

\begin{array}{l} \textbf{parse}\;(\ekh{P},\rand)\gets\aux_1 \\ (\ct,K)\sample\Enc(\ekh{\bar P};\rand') \\ K'\gets\Dec(\dkh{\bar P},\ct) \\ \ct_{\mathsf{\bar P}}:=(\ekh{P},\ct) \\ \rand_2:=(\rand',\rand)\pcomment{\text{Fig. 27: }(\aux_1,\rand')} \\ \Return(\ct_{\mathsf{\bar P}},K,K',\rand_2)\pcomment{\text{Fig. 27: }K\text{ for }K'} \end{array}

RSimKey-P₂

def rsimKey2 {kem : KEMScheme ProbComp K PK SK C} (total : TotalDecaps kem) (kemLeak : kem.RandLeak) (_par : Unit) (ekPeerHat : PK) (dkPeerHat : SK) (aux : PK × kemLeak.KeygenRand) : ProbComp ((PK × C) × K × K × kemLeak.Rand) := do let (ekSelfHat, rand) := aux let ((ct, key), rand') ← kemLeak.encapsRleak ekPeerHat let key' ← total.decapsTotal dkPeerHat ct return ((ekSelfHat, ct), key, key', (rand', rand))
\RSimCtxt\text{-}\mathsf{P}(\ekh{P},\ekh{\bar P},\dkh{\bar P})

\begin{array}{l} (\ct,K)\sample\Enc(\ekh{\bar P}) \\ K'\gets\Dec(\dkh{\bar P},\ct) \\ \ct_{\mathsf{\bar P}}:=(\ekh{P},\ct) \\ (\ek_\mathsf{P},\_)\sample\KeyGen(1^\lambda)\pcomment{\text{Fig. 27: }\ek_\mathsf{P}:=\ekh{P}} \\ \Return(\ct_{\mathsf{\bar P}},\ek_\mathsf{P},K,K') \end{array}

RSimCtxt-P

def rsimCtxt (kem : KEMScheme ProbComp K PK SK C) (total : TotalDecaps kem) (_par : Unit) (ekSelfHat ekPeerHat : PK) (dkPeerHat : SK) : ProbComp ((PK × C) × PK × K × K) := do let (ct, key) ← kem.encaps ekPeerHat let key' ← total.decapsTotal dkPeerHat ct let (ekSelf, _) ← kem.keygen return ((ekSelfHat, ct), ekSelf, key, key')

Ratchet simulators

def ratchetSimulator (kem : KEMScheme ProbComp K PK SK C) (total : TotalDecaps kem) (kemLeak : kem.RandLeak) : (scheme kem total).RatchetSimulator (randLeak kem total kemLeak) where Aux := PK × kemLeak.KeygenRand rsimKeyA1 := rsimKey1 kemLeak rsimKeyA2 := rsimKey2 total kemLeak rsimCtxtA := rsimCtxt kem total rsimKeyB1 := rsimKey1 kemLeak rsimKeyB2 := rsimKey2 total kemLeak rsimCtxtB := rsimCtxt kem total
Lean code for Theorem8.4.4●5 declarations
  • def kemRKEM.rsimKey1 {K PK SK C : Type} {kem : KEMScheme ProbComp K PK SK C}
      (kemLeak : kem.RandLeak) (_par : Unit) (_ekSelf : PK) (_dkSelf : SK) :
      ProbComp (PK × SK × PK × kemLeak.KeygenRand)
    def kemRKEM.rsimKey1 {K PK SK C : Type}
      {kem : KEMScheme ProbComp K PK SK C}
      (kemLeak : kem.RandLeak) (_par : Unit)
      (_ekSelf : PK) (_dkSelf : SK) :
      ProbComp
        (PK × SK × PK × kemLeak.KeygenRand)
    `RSimKey-P₁` of [TripleRatchet, Fig. 27]:
    
    RSimKey-P₁(ekP, dkP):             -- ekP, dkP are unused
    (êkP, d̂kP) ← KeyGen(1^λ; rand)
    aux₁       := (êkP, rand)
    return (êkP, d̂kP, aux₁)
    
    The simulated updated key pair is a fresh KEM key pair, as `REnc-P` itself would produce. 
  • def kemRKEM.rsimKey2 {K PK SK C : Type} {kem : KEMScheme ProbComp K PK SK C}
      (total : kem.TotalDecaps) (kemLeak : kem.RandLeak) (_par : Unit)
      (ekPeerHat : PK) (dkPeerHat : SK) (aux : PK × kemLeak.KeygenRand) :
      ProbComp ((PK × C) × K × K × kemLeak.Rand)
    def kemRKEM.rsimKey2 {K PK SK C : Type}
      {kem : KEMScheme ProbComp K PK SK C}
      (total : kem.TotalDecaps)
      (kemLeak : kem.RandLeak) (_par : Unit)
      (ekPeerHat : PK) (dkPeerHat : SK)
      (aux : PK × kemLeak.KeygenRand) :
      ProbComp
        ((PK × C) × K × K × kemLeak.Rand)
    `RSimKey-P₂` of [TripleRatchet, Fig. 27]:
    
    RSimKey-P₂(êkP̄, d̂kP̄, aux₁):
      parse (êkP, rand) ← aux₁
      (ct, K)  ← Enc(êkP̄; rand')
      K'       ← Dec(d̂kP̄, ct)
      ctP̄     := (êkP, ct)
      rand₂    := (rand', rand)
      return (ctP̄, K, K', rand₂)
    
    P̄ above corresponds to Peer below, while P corresponds to Self. The figure returns `K` in
    place of `K'` and sets `rand₂ := (aux₁, rand')`; see the module docstring. 
  • def kemRKEM.rsimCtxt {K PK SK C : Type} (kem : KEMScheme ProbComp K PK SK C)
      (total : kem.TotalDecaps) (_par : Unit) (ekSelfHat ekPeerHat : PK)
      (dkPeerHat : SK) : ProbComp ((PK × C) × PK × K × K)
    def kemRKEM.rsimCtxt {K PK SK C : Type}
      (kem : KEMScheme ProbComp K PK SK C)
      (total : kem.TotalDecaps) (_par : Unit)
      (ekSelfHat ekPeerHat : PK)
      (dkPeerHat : SK) :
      ProbComp ((PK × C) × PK × K × K)
    `RSimCtxt-P` of [TripleRatchet, Fig. 27]:
    
    RSimCtxt-P(êkP, êkP̄, d̂kP̄):
      (ct, K)  ←$ Enc(êkP̄)
      K'       ←  Dec(d̂kP̄, ct)
      ctP̄     :=  (êkP, ct)
      (ekP, ·) ←  KeyGen(1^λ)
      return (ctP̄, ekP, K, K')
    
    P̄ above corresponds to Peer below, while P corresponds to Self. The figure sets
    `ekP := êkP` instead of sampling a fresh `ekP`; see the module docstring. 
  • def kemRKEM.ratchetSimulator {K PK SK C : Type}
      (kem : KEMScheme ProbComp K PK SK C) (total : kem.TotalDecaps)
      (kemLeak : kem.RandLeak) :
      (kemRKEM.scheme kem total).RatchetSimulator
        (kemRKEM.randLeak kem total kemLeak)
    def kemRKEM.ratchetSimulator
      {K PK SK C : Type}
      (kem : KEMScheme ProbComp K PK SK C)
      (total : kem.TotalDecaps)
      (kemLeak : kem.RandLeak) :
      (kemRKEM.scheme kem
            total).RatchetSimulator
        (kemRKEM.randLeak kem total kemLeak)
    The ratchet simulators of [TripleRatchet, Fig. 27] for the RKEM-from-KEM construction, with
    respect to `randLeak`. The auxiliary state `aux₁ = (êkP, rand)` is the simulated updated
    encapsulation key and its key-generation coins. As for the construction itself, the simulators
    are the same for `A` and `B`. 
  • theorem kemRKEM.RatchetSimulatable {K PK SK C : Type}
      (kem : KEMScheme ProbComp K PK SK C) (total : kem.TotalDecaps)
      (kemLeak : kem.RandLeak) :
      (kemRKEM.scheme kem total).RatchetSimulatable 0
    theorem kemRKEM.RatchetSimulatable
      {K PK SK C : Type}
      (kem : KEMScheme ProbComp K PK SK C)
      (total : kem.TotalDecaps)
      (kemLeak : kem.RandLeak) :
      (kemRKEM.scheme kem
            total).RatchetSimulatable
        0
    **Theorem A.2** ([TripleRatchet]) of the RKEM-from-KEM construction: it is perfectly
    (`ε = 0`) ratchet simulatable (Def. 5.5) with respect to `randLeak`, witnessed by the simulators
    `ratchetSimulator` of [TripleRatchet, Fig. 27]. Holds for any KEM with total decapsulation
    (`total`, already required by the construction), with no correctness or security assumption.