Multi-recipient hybrid encryption, over a KEM #
Like MKEM, but over a KEM, which cannot combine a private key with another party's public key.
There is one KEM ciphertext per recipient. The payload is sealed once under a message key, which
is wrapped under each recipient's derived key (a DEK). Replies are sealed directly under the
derived key, which the sender keeps per recipient and the recipient recovers on decapsulation.
IND-CCA2 and recipient anonymity are computational and not laws. The ciphertext byte encoding is
not modelled. The generic construction is Adapter.hybridOfKEM.
decapFailed covers any error from the underlying KEM.decap.
- invalidKeySize : MultiRecipientHybridError
- ciphertextTooShort : MultiRecipientHybridError
- trialDecryptFailed : MultiRecipientHybridError
- decapFailed : MultiRecipientHybridError
Instances For
The ciphertext with only recipient i's KEM ciphertext and DEK.
Equations
Instances For
- PrivateKey : Type
- PublicKey : Type
- KEMCiphertext : Type
- ctI : Inhabited self.KEMCiphertext
- State : Type
- name : String
- publicKeySize : Nat
- kemCiphertextSize : Nat
- dekSize : Nat
- envelopeOverhead : Nat
- derivePublicKey : self.PrivateKey → self.PublicKey
- encodePublicKey : self.PublicKey → Vector UInt8 self.publicKeySize
- decodePublicKey : Vector UInt8 self.publicKeySize → Option self.PublicKey
States from which no recipient's encapsulation fails, as
KEM.Reliable.- generate : EStateM MultiRecipientHybridError self.State (self.PublicKey × self.PrivateKey)
- encapsulate : List self.PublicKey → ByteArray → EStateM MultiRecipientHybridError self.State (List ByteArray × Ciphertext self.KEMCiphertext)
Also returns the per-recipient derived keys, in order, for reading replies.
- decapsulate : self.PrivateKey → Ciphertext self.KEMCiphertext → Except MultiRecipientHybridError (ByteArray × ByteArray)
Returns the derived key and the payload.
A reply sealed under a derived key.
- decryptEnvelope : ByteArray → ByteArray → Except MultiRecipientHybridError ByteArray
- encapsulate_shape (keys : List self.PublicKey) (payload : ByteArray) (s : self.State) (derivedKeys : List ByteArray) (ct : Ciphertext self.KEMCiphertext) (s' : self.State) : self.encapsulate keys payload s = EStateM.Result.ok (derivedKeys, ct) s' → ct.kemCiphertexts.length = keys.length ∧ ct.deks.length = keys.length ∧ derivedKeys.length = keys.length ∧ (∀ (d : ByteArray), d ∈ ct.deks → d.size = self.dekSize) ∧ ct.envelope.size = payload.size + self.envelopeOverhead
One KEM ciphertext, one
dekSizeDEK and one derived key per recipient, and an envelopeenvelopeOverheadlonger than the payload. - decapsulate_encapsulate (keys : List self.PublicKey) (payload : ByteArray) (s : self.State) : self.Reliable s → ∀ (derivedKeys : List ByteArray) (ct : Ciphertext self.KEMCiphertext) (s' : self.State), self.encapsulate keys payload s = EStateM.Result.ok (derivedKeys, ct) s' → ∀ (i : Nat) (hi : i < keys.length) (sk : self.PrivateKey) (k : ByteArray), keys[i] = self.derivePublicKey sk → derivedKeys[i]? = some k → self.decapsulate sk (ct.forRecipient i) = Except.ok (k, payload)
From a
Reliablestate, recipientirecovers the payload and the sender's derived keykfromct.forRecipient i. - decryptEnvelope_envelopeReply (key pt : ByteArray) (s : self.State) (env : ByteArray) (s' : self.State) : self.envelopeReply key pt s = EStateM.Result.ok env s' → self.decryptEnvelope key env = Except.ok pt
Replies round-trip under the same key.