MKEM from a NIKE, an AEAD and a hash #
The only NIKE law used is NIKE.commutes.
ENCAPSULATE(keys, payload):
eph := GEN_KEYPAIR()
secret_i := HASH(DH(eph, keys[i])) -- error if DH output is all zero
msgKey := RANDOM(32)
envelope := nonce ‖ AEAD_seal(msgKey, payload)
dek_i := nonce_i ‖ AEAD_seal(secret_i, msgKey)
return eph, (eph_pub, [dek_i], envelope)
DECAPSULATE(sk, ct):
secret := HASH(DH(sk, ct.eph_pub))
for dek in ct.deks: first one that opens under secret gives msgKey
return open(msgKey, ct.envelope)
The pure functions take explicit randomness (Rand); the MKEM instance draws it from an
Adapter.St seed stream, which must be unpredictable.
The three primitives, and the fact that lets a hash output be an AEAD key.
- nike : NIKE.NIKE.NIKE
- aead : Cipher.AEAD.AEAD
- hash : Hash.Hash.Hash
Instances For
The sender's randomness, explicit so the pure construction is a function.
Instances For
List lemmas #
A raw byte string as an AEAD key, if it is the right length.
Equations
Instances For
Both parties derive the same key.
Sealing under a key: nonce, then AEAD ciphertext #
The construction, with explicit randomness #
Encrypt payload to every recipient. none if any Diffie-Hellman output is degenerate.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Open the first DEK that opens under the shared key, then the envelope.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Unpack a successful encapsulation.
One nonce + key + tag-byte DEK per recipient, and an envelope nonce + tag longer than the
payload.
Recipient i recovers the payload from the ciphertext carrying only its DEK.
Recipient i recovers the payload from the full ciphertext, provided no earlier DEK opens
under its key (hcross).
Replies #
Equations
- S.envelopeReplyP sk pub nonce pt = do let k ← S.deriveKey sk pub pure (S.sealUnder k nonce pt)
Instances For
Equations
- S.decryptEnvelopeP sk pub envelope = do let k ← S.deriveKey sk pub S.unsealUnder k envelope
Instances For
The MKEM instance #
i as 8 little-endian bytes.
Equations
- Cryptlib.Primitives.MKEM.Adapter.counterBytes i = { data := Array.map (fun (k : Nat) => (i >>> (8 * k)).toUInt8) (Array.range 8) }
Instances For
Randomness for encapsulating to n recipients, from stream position i: ephemeral seed,
message key, envelope nonce, then one nonce per recipient.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Cryptlib.Primitives.MKEM.Adapter.generateM S (i, str) = EStateM.Result.ok (S.nike.derivePublicKey (S.nike.privateKeyFromSeed (str i)), S.nike.privateKeyFromSeed (str i)) (i + 1, str)
Instances For
MKEM over the given NIKE, AEAD and hash.
Equations
- One or more equations did not get rendered due to their size.
Instances For
MKEM over a NIKE, an AEAD, and a hash whose digest is an AEAD key.
Equations
- Cryptlib.Primitives.MKEM.Adapter.mkemOfNike nike aead hash h = Cryptlib.Primitives.MKEM.Adapter.ofBase { nike := nike, aead := aead, hash := hash, digest_eq_key := h }