Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
18356e2
refactor: modify statements for clarity
ashandoak Feb 22, 2026
4624e6b
refactor: modify name of public parameters class
ashandoak Feb 22, 2026
6b288b5
refactor: change order of core lemmas and defs
ashandoak Feb 22, 2026
12dfdc4
refactor: change name of dlogadv def
ashandoak Feb 22, 2026
8fb6a51
refactor: modify lemma to mathlib style; update associated proof
ashandoak Feb 22, 2026
b413d21
fix: missed adding dlogadv name change
ashandoak Feb 22, 2026
2f5ef5a
refactor: rename binding lemmas for clarity
ashandoak Feb 22, 2026
8db1669
refactor: remove unnecessary hypothesis
ashandoak Feb 23, 2026
9038e83
refactor: remove unnecessary parentheses
ashandoak Feb 23, 2026
7f68897
refactor: clean up lemma statements and have blocks
ashandoak Feb 24, 2026
1bbbce5
refactor: update proof of pedersen uniformity to use commit directly
ashandoak Feb 25, 2026
527885b
Add commitment scheme docstrings and clean up definitions; update ped…
ashandoak Feb 28, 2026
911b86e
Tweak language for perfect hiding and binding
ashandoak Feb 28, 2026
886a573
Reorder noncomputable section
ashandoak Feb 28, 2026
c460ba8
Reconfigure some aspects of commitment spec
ashandoak Mar 1, 2026
5e564eb
refactor: reorder elgamal definitions
ashandoak Mar 1, 2026
87a3900
feat: add proof of elgamal binding
ashandoak Mar 1, 2026
c9751cd
refactor: remove unnecessary elements
ashandoak Mar 1, 2026
705fb7a
refactor: fix line break in defs
ashandoak Mar 1, 2026
f8f86ec
wip: minor refactoring
ashandoak Mar 11, 2026
4ab2133
wip: remove coprime hypothesis from binding lemma (grind handles it)
ashandoak Mar 11, 2026
616d2c1
wip: minor refactoring
ashandoak Mar 11, 2026
60e4ddd
wip: refactor some defs
ashandoak Mar 11, 2026
f38dd96
Merge branch 'main' into thesis-edits
ashandoak Mar 11, 2026
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
115 changes: 69 additions & 46 deletions VerifiedCommitments/CommitmentScheme.lean
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,99 @@ import Mathlib.Probability.ProbabilityMassFunction.Constructions
import Mathlib.Probability.Distributions.Uniform
import Mathlib.Data.ZMod.Defs

/-- A CommitmentScheme is a structure over four spaces:
M: Message space
C: Commitment space
O: Opening value space
K: Key space

And that contains three algorithms:
setup: returns a public parameter and associated randomness
commit: given the public parameter and a message produces a commitment and an opening value
verify: given the public parameter, message and associated commit and opening value returns 1 when the commit opens to the given message and 0 otherwise.-/
structure CommitmentScheme (M C O K : Type) where
setup : PMF (K × O)
commit : K → M → PMF (C × O)
verify : K → M → C → O → ZMod 2


/-- The structure of binding adversary guesses for use in the computational binding game.-/
structure BindingGuess (M C O : Type) where
c : C
m : M
m' : M
o : O
o': O
o' : O

/-- The structure of the hiding adversary for use in the computational hiding game.-/
structure TwoStageAdversary (K M C : Type) where
State : Type
stage1 : K → PMF ((M × M) × State)
stage2 : C → State → PMF (ZMod 2)
state : Type
stage1 : K → PMF ((M × M) × state)
stage2 : C → state → PMF (ZMod 2)

namespace Commitment

noncomputable section
variable {M C O K : Type}
variable (scheme : CommitmentScheme M C O K)

/-- For any public parameters `h` and any message `m` if `commit` outputs a commitment `c` and opening value `o`, then `verify h m c o` accepts with probability 1.-/
def correctness (scheme : CommitmentScheme M C O K) : Prop :=
∀ (h : K) (m : M),
PMF.bind (scheme.commit h m) (fun (commit, opening_val) => pure $ scheme.verify h m commit opening_val) = pure 1
∀ (h : K) (m : M), (scheme.commit h m |>.bind fun (c, o) =>
pure <| scheme.verify h m c o) = pure 1

-- Perfect binding
/-- A commitment scheme with public parameter `h` is perfectly binding if no commitment `c` can be opened to two different messages. For two purported openings `(m,o)` and `(m',o')` both verifying for the same `c`, the messages must be equal (`m = m'`). -/
def perfect_binding (scheme : CommitmentScheme M C O K) : Prop :=
∀ (h : K) (c : C) (m m' : M) (o o' : O),
scheme.verify h m c o = 1 →
scheme.verify h m' c o' = 1 →
m = m'
-- Equivalent to:
--if scheme.verify h m c o = scheme.verify h m' c o' then true else false

-- Computational binding game
-- Security depends on generating the parameters correctly, but at this level probably alright to have the group and generator fixed
-- h should be inside the game, because its unique to a specific run
def comp_binding_game (scheme : CommitmentScheme M C O K)
(A' : K → PMF (BindingGuess M C O)) : PMF $ ZMod 2 :=
open scoped Classical in
PMF.bind scheme.setup (fun (h, _) =>
PMF.bind (A' h) (fun guess =>
if scheme.verify h guess.m guess.c guess.o = 1 ∧ scheme.verify h guess.m' guess.c guess.o' = 1 ∧ guess.m ≠ guess.m' then pure 1 else pure 0 ))

def computational_binding [DecidableEq M] (scheme : CommitmentScheme M C O K) (ε : ENNReal) : Prop :=
∀ (A' : K → PMF (BindingGuess M C O )), comp_binding_game scheme A' 1 ≤ ε


-- Perfect hiding
def do_commit (scheme: CommitmentScheme M C O K) (m : M) : PMF C :=
PMF.bind scheme.setup (fun (h, _) =>
PMF.bind (scheme.commit h m) (fun (c, _) => pure c))
scheme.verify h m' c o' = 1 →
m = m'

/-- A commitment scheme is perfectly hiding if for any messages `m` and `m'`, the induced distribution on commitments is the same. Sampling `h ← setup` and then committing to `m` or `m'` under `h` yields identical commitment distributions. -/
def perfect_hiding (scheme: CommitmentScheme M C O K) : Prop :=
∀ (m m' : M) (c : C), (do_commit scheme m) c = (do_commit scheme m') c

-- Computational hiding game
def comp_hiding_game (scheme : CommitmentScheme M C O K) (A : TwoStageAdversary K M C) :=
PMF.bind scheme.setup (fun (h, _) =>
PMF.bind (A.stage1 h) (fun ((m₀, m₁), state) =>
PMF.bind (PMF.uniformOfFintype (ZMod 2)) (fun b =>
PMF.bind (scheme.commit h (if b = 0 then m₀ else m₁)) (fun (c, _) =>
PMF.bind (A.stage2 c state) (fun b' =>
pure (1 + b + b'))))))

def computational_hiding (scheme : CommitmentScheme M C O K) (ε : ENNReal) : Prop :=
∀ (A : TwoStageAdversary K M C), comp_hiding_game scheme A 1 - 1/2 ≤ ε
∀ (m m' : M) (c : C),
PMF.bind scheme.setup (fun (h, _) =>
PMF.bind (scheme.commit h m) (fun (c, _) =>
pure c)) c
=
PMF.bind scheme.setup (fun (h, _) =>
PMF.bind (scheme.commit h m') (fun (c, _) =>
pure c)) c

/- Computational Binding -/

/-- For any adversary `A` that accepts `h ← setup` and outputs a single commitment `c` together with two purported openings `(m,o)` and `(m',o')`, the computational binding game outputs `1` if `c` opens to both `(m,o)` and `(m',o') and the messages differ (`m ≠ m'`). -/
noncomputable def comp_binding_game
[DecidableEq M] (scheme : CommitmentScheme M C O K)
(A : K → PMF (BindingGuess M C O)) : PMF (ZMod 2) := do
let (h, _) ← scheme.setup
let guess ← A h
pure (
if scheme.verify h guess.m guess.c guess.o = 1 ∧
scheme.verify h guess.m' guess.c guess.o' = 1 ∧
guess.m ≠ guess.m'
then 1 else 0 )

/-- A commitment scheme is computationally binding if every adversary’s probability of winning the computational binding game is at most `ε`. -/
def computational_binding [DecidableEq M] (scheme : CommitmentScheme M C O K)
(ε : ENNReal) : Prop :=
∀ (A' : K → PMF (BindingGuess M C O )), comp_binding_game scheme A' 1 ≤ ε

end
/- Computational Hiding -/

/-- For any `TwoStageAdversary` `A`, sample `h ← setup` and give `h` to the adversary’s first stage to produce two challenge messages `m₀, m₁. The computational hiding game samples a uniform bit `b`, computes a commitment to `m_b`, and gives the commitment `c` to the adversary’s second stage. The game outputs a bit indicating whether the adversary’s guess matches `b`. -/
noncomputable def comp_hiding_game
(scheme : CommitmentScheme M C O K)
(A : TwoStageAdversary K M C) := do
let (h, _) ← scheme.setup
let ((m₀, m₁), state) ← A.stage1 h
let b ← PMF.uniformOfFintype (ZMod 2)
let (c, _) ← scheme.commit h (if b = 0 then m₀ else m₁)
let b' ← A.stage2 c state
pure (1 + b + b')

/-- A commitment scheme is computationally hiding if every adversary’s advantage
over random guessing in the hiding game is at most `ε`. -/
def computational_hiding (scheme : CommitmentScheme M C O K)
(ε : ENNReal) : Prop :=
∀ (A : TwoStageAdversary K M C), comp_hiding_game scheme A 1 - 1/2 ≤ ε

end Commitment
Loading
Loading