Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cslib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ public import Cslib.Computability.URM.Defs
public import Cslib.Computability.URM.Execution
public import Cslib.Computability.URM.StandardForm
public import Cslib.Computability.URM.StraightLine
public import Cslib.Crypto.PerfectSecrecy.Basic
public import Cslib.Crypto.PerfectSecrecy.Defs
public import Cslib.Crypto.PerfectSecrecy.Encryption
public import Cslib.Crypto.PerfectSecrecy.Internal.OneTimePad
public import Cslib.Crypto.PerfectSecrecy.Internal.PerfectSecrecy
public import Cslib.Crypto.PerfectSecrecy.OneTimePad
public import Cslib.Foundations.Combinatorics.InfiniteGraphRamsey
public import Cslib.Foundations.Control.Monad.Free
public import Cslib.Foundations.Control.Monad.Free.Effects
Expand Down
53 changes: 53 additions & 0 deletions Cslib/Crypto/PerfectSecrecy/Basic.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/-
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/

module

public import Cslib.Crypto.PerfectSecrecy.Defs
public import Cslib.Crypto.PerfectSecrecy.Internal.PerfectSecrecy

@[expose] public section

/-!
# Perfect Secrecy

Characterisation theorems for perfect secrecy following
[KatzLindell2020], Chapter 2.

## Main results

- `Cslib.Crypto.PerfectSecrecy.EncScheme.perfectlySecret_iff_ciphertextIndist`:
ciphertext indistinguishability characterization ([KatzLindell2020], Lemma 2.5)
- `Cslib.Crypto.PerfectSecrecy.EncScheme.perfectlySecret_iff_posteriorEq`:
perfect secrecy as equality of posterior and prior distributions
- `Cslib.Crypto.PerfectSecrecy.EncScheme.perfectlySecret_keySpace_ge`:
Shannon's theorem, `|K| ≥ |M|` ([KatzLindell2020], Theorem 2.12)

## References

* [J. Katz, Y. Lindell, *Introduction to Modern Cryptography*][KatzLindell2020]
-/

namespace Cslib.Crypto.PerfectSecrecy.EncScheme

universe u
variable {M K C : Type u}

/-- A scheme is perfectly secret iff the ciphertext distribution is
independent of the plaintext ([KatzLindell2020], Lemma 2.5). -/
theorem perfectlySecret_iff_ciphertextIndist (scheme : EncScheme M K C) :
scheme.PerfectlySecret ↔ scheme.CiphertextIndist :=
⟨PerfectSecrecy.ciphertextIndist_of_perfectlySecret scheme,
PerfectSecrecy.perfectlySecret_of_ciphertextIndist scheme⟩

/-- Perfect secrecy requires `|K| ≥ |M|`
([KatzLindell2020], Theorem 2.12). -/
theorem perfectlySecret_keySpace_ge [Finite K]
(scheme : EncScheme M K C) (h : scheme.PerfectlySecret) :
Nat.card K ≥ Nat.card M :=
PerfectSecrecy.shannonKeySpace scheme h

end Cslib.Crypto.PerfectSecrecy.EncScheme
77 changes: 77 additions & 0 deletions Cslib/Crypto/PerfectSecrecy/Defs.lean
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double directory name?

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/-
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/

module

public import Cslib.Crypto.PerfectSecrecy.Encryption
public import Mathlib.Probability.ProbabilityMassFunction.Constructions

@[expose] public section

/-!
# Perfect Secrecy: Definitions

Core definitions for perfect secrecy following [KatzLindell2020], Chapter 2.

## Main definitions

- `Cslib.Crypto.PerfectSecrecy.EncScheme.ciphertextDist`:
ciphertext distribution for a given message
- `Cslib.Crypto.PerfectSecrecy.EncScheme.jointDist`:
joint (message, ciphertext) distribution given a message prior
- `Cslib.Crypto.PerfectSecrecy.EncScheme.marginalCiphertextDist`:
marginal ciphertext distribution given a message prior
- `Cslib.Crypto.PerfectSecrecy.EncScheme.posteriorMsgProb`:
posterior probability `Pr[M = m | C = c]`
- `Cslib.Crypto.PerfectSecrecy.EncScheme.posteriorMsgDist`:
posterior message distribution as a `PMF` (defined in the internal file)
- `Cslib.Crypto.PerfectSecrecy.EncScheme.PerfectlySecret`:
perfect secrecy ([KatzLindell2020], Definition 2.3)
- `Cslib.Crypto.PerfectSecrecy.EncScheme.CiphertextIndist`:
ciphertext indistinguishability ([KatzLindell2020], Lemma 2.5)
-/

namespace Cslib.Crypto.PerfectSecrecy.EncScheme

universe u
variable {M K C : Type u}

/-- The distribution of `Enc_K(m)` when `K ← Gen`. -/
noncomputable def ciphertextDist (scheme : EncScheme M K C) (m : M) : PMF C := do
let k ← scheme.gen
scheme.enc k m

/-- Joint distribution of `(M, C)` given a message prior. -/
noncomputable def jointDist (scheme : EncScheme M K C) (msgDist : PMF M) : PMF (M × C) := do
let m ← msgDist
let c ← scheme.ciphertextDist m
pure (m, c)

/-- Marginal ciphertext distribution given a message prior. -/
noncomputable def marginalCiphertextDist (scheme : EncScheme M K C)
(msgDist : PMF M) : PMF C := do
let m ← msgDist
scheme.ciphertextDist m

/-- Posterior probability `Pr[M = m | C = c]`. -/
noncomputable def posteriorMsgProb (scheme : EncScheme M K C)
(msgDist : PMF M) (c : C) (m : M) : ENNReal :=
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think scheme.posteriorMsgProb msgDist c is a distribution. It would be good to define it in these terms. It will require a little proof (but do we not already have this in Mathlib? Maybe not).

scheme.jointDist msgDist (m, c) / scheme.marginalCiphertextDist msgDist c

/-- An encryption scheme is perfectly secret if `Pr[M = m | C = c] = Pr[M = m]`
for every prior, message, and ciphertext with positive probability
([KatzLindell2020], Definition 2.3). -/
def PerfectlySecret (scheme : EncScheme M K C) : Prop :=
∀ (msgDist : PMF M) (m : M) (c : C),
c ∈ (scheme.marginalCiphertextDist msgDist).support →
scheme.posteriorMsgProb msgDist c m = msgDist m
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very nearly equivalent to:
∀ (msgDist : PMF M) (c : C),
c ∈ (scheme.marginalCiphertextDist msgDist).support →
scheme.posteriorMsgProb msgDist c = msgDist

The issue is that the types don't match. But I think scheme.posteriorMsgProb msgDist c is a distribution!


/-- Ciphertext indistinguishability: the ciphertext distribution is the same
for all messages ([KatzLindell2020], Lemma 2.5). -/
def CiphertextIndist (scheme : EncScheme M K C) : Prop :=
∀ m₀ m₁ : M, scheme.ciphertextDist m₀ = scheme.ciphertextDist m₁

end Cslib.Crypto.PerfectSecrecy.EncScheme
48 changes: 48 additions & 0 deletions Cslib/Crypto/PerfectSecrecy/Encryption.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/-
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/

module

public import Cslib.Init
public import Mathlib.Probability.ProbabilityMassFunction.Monad

@[expose] public section

/-!
# Private-Key Encryption Schemes (Information-Theoretic)

An information-theoretic private-key encryption scheme following
[KatzLindell2020], Definition 2.1. Key generation and encryption are
probability distributions over arbitrary types, with no computational
constraints.

## Main definitions

- `Cslib.Crypto.PerfectSecrecy.EncScheme`:
a private-key encryption scheme (Gen, Enc, Dec) with correctness

## References

* [J. Katz, Y. Lindell, *Introduction to Modern Cryptography*][KatzLindell2020]
-/

namespace Cslib.Crypto.PerfectSecrecy

/--
A private-key encryption scheme over message space `M`, key space `K`,
and ciphertext space `C` ([KatzLindell2020], Definition 2.1).
-/
structure EncScheme.{u} (M K C : Type u) where
/-- Probabilistic key generation. -/
gen : PMF K
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have briefly spoken about this, but it is worth considering whether rational probabilities might be desirable. The concern would be that sometimes you do want to be able to take limits of probabilities etc.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think given that this is really not going to be reused very much (the rest of the book defined encryption schemes totally differently), I feel we shouldn't define a custom notion of rational distributions just for this.

That said, I am very open to computable probability distributions being defined somewhere if they're going to be useful broadly.

/-- (Possibly randomized) encryption. -/
enc : K → M → PMF C
/-- Deterministic decryption. -/
dec : K → C → M
/-- Decryption inverts encryption for all keys in the support of `gen`. -/
correct : ∀ k, k ∈ gen.support → ∀ m c, c ∈ (enc k m).support → dec k c = m
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like the right statement of correctness to me. I wonder if "gen.support" (the set of valid keys) and (enc k m),support (the set of valid encryptions for a give k) want names/definitions (or at least abbreviations).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, support feels like the right phrasing, but I am open to suggestions.


end Cslib.Crypto.PerfectSecrecy
47 changes: 47 additions & 0 deletions Cslib/Crypto/PerfectSecrecy/Internal/OneTimePad.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/-
Copyright (c) 2026 Samuel Schlesinger. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/

module

public import Cslib.Init
public import Mathlib.Probability.Distributions.Uniform

@[expose] public section

/-!
# One-Time Pad: Internal proofs

The OTP ciphertext distribution is uniform regardless of message.
-/

namespace Cslib.Crypto.PerfectSecrecy.OTP

@[reducible] noncomputable def bitVecFintype (n : ℕ) : Fintype (BitVec n) :=
Fintype.ofEquiv (Fin (2 ^ n))
⟨BitVec.ofFin, BitVec.toFin, fun x => by simp, fun x => by simp⟩

/-- XOR by a fixed mask is self-inverse on `BitVec`: `c = k ^^^ m ↔ k = c ^^^ m`. -/
lemma xor_right_eq_iff {l : ℕ} (c m k : BitVec l) :
(c = k ^^^ m) ↔ (k = c ^^^ m) := by
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a special tactic to discharge bitvec goals. Ask around (I am not sure). This should definitely be upstream.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh neat. I can grep around in Mathlib for it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bv_decide doesn't seem to work, if that's what you meant

constructor
· rintro rfl
rw [BitVec.xor_assoc, BitVec.xor_self, BitVec.xor_zero]
· rintro rfl
rw [BitVec.xor_assoc, BitVec.xor_self, BitVec.xor_zero]

/-- The ciphertext distribution of the OTP is uniform, regardless of the message. -/
theorem otp_ciphertextDist_eq_uniform (l : ℕ) (m : BitVec l) :
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module

public import Cslib.Init
public import Mathlib.Probability.Distributions.Uniform
public import Mathlib.Data.BitVec

@[expose] public section

/-!
# One-Time Pad: Internal proofs

The OTP ciphertext distribution is uniform regardless of message.
-/

namespace Cslib.Crypto.PerfectSecrecy.OTP

instance (n : ℕ) : Fintype (BitVec n) :=
  Fintype.ofEquiv (Fin (2 ^ n)) BitVec.equivFin.symm.toEquiv

/-- XOR by a fixed mask is self-inverse on `BitVec`: `c = k ^^^ m ↔ k = c ^^^ m`. -/
lemma xor_right_eq_iff {l : ℕ} (c m k : BitVec l) :
    (c = k ^^^ m) ↔ (k = c ^^^ m) := by grind

/-- The ciphertext distribution of the OTP is uniform, regardless of the message. -/
theorem otp_ciphertextDist_eq_uniform {l : ℕ} (m : BitVec l) :
    (PMF.uniformOfFintype _).bind (PMF.pure <| · ^^^ m) = PMF.uniformOfFintype _ := by
  simp [PMF.ext_iff, xor_right_eq_iff]

end Cslib.Crypto.PerfectSecrecy.OTP

haveI := bitVecFintype l
(PMF.uniformOfFintype (BitVec l)).bind
(fun k => PMF.pure (k ^^^ m)) =
PMF.uniformOfFintype (BitVec l) := by
haveI := bitVecFintype l
ext c
simp only [PMF.bind_apply, PMF.uniformOfFintype_apply, PMF.pure_apply]
simp_rw [xor_right_eq_iff c m]
simp

end Cslib.Crypto.PerfectSecrecy.OTP
Loading