Zulip Chat Archive
Stream: new members
Topic: Getting the witnesses from a Sigma type
Mukesh Tiwari (Dec 06 2020 at 06:28):
How can I get t = ↑g ^ w.val, c = ↑(hash [g, h, ↑t]), and s = w + c * x from H₁ (see proof_of_completeness proof)?
1 goal
pq: ℕ
g: zmod p
hash: list (zmod p) → zmod p
wx: zmod q
h: zmod p
H₀: h = g ^ x.val
tcs: zmod q
H₂: zkp_transcript p q g hash w x h H₀ (response ↑t ↑c ↑s)
H₁: ⟨t, ⟨c, ⟨s, H₂⟩⟩⟩ = let t : zmod q := ↑g ^ w.val, c : zmod q := ↑(hash [g, h, ↑t]), s : zmod q := w + c * x in ⟨t, ⟨c, ⟨s, response_step t c s _ (challenge_step t c _ (commitment_step t _))⟩⟩⟩
⊢ g ^ s.val = ↑t * h ^ c.val
Complete source code:
import data.zmod.basic data.nat.prime
number_theory.quadratic_reciprocity
tactic.find tactic.omega
namespace nzkp
variables
(p q k : ℕ) (g h : zmod p)
(Hk : 2 ≤ k) (Hp : fact (nat.prime p)) (Hq : fact (nat.prime q))
(Hdiv : p = q * k + 1) (H₁ : h ≠ 0) (H₂ : h^k ≠ 1)
(H₃ : g = h^k)
variables
hash : list (zmod p) -> zmod p
inductive communication : Type*
| commitment : Π (t : zmod q), communication
| challenge : Π (t c : zmod q), communication
| response : Π (t c s : zmod q), communication
open communication
/- Add more data to hash function https://tools.ietf.org/html/rfc8235 -/
inductive zkp_transcript (w x : zmod q) (h : zmod p) (Hf : h = g^x.val) : communication p -> Type*
| commitment_step (t : zmod q) : t = g^w.val -> zkp_transcript (commitment t)
| challenge_step (t c : zmod q) : c = hash [g, h, t] -> zkp_transcript (commitment t) -> zkp_transcript (challenge t c)
| response_step (t c s : zmod q) : s = w + c * x -> zkp_transcript (challenge t c) -> zkp_transcript (response t c s)
open zkp_transcript
/-
We can construct a sigma protocol (discrete logarithm).
we can always construct a valid certificate. Moreover, we will prove this
formally that this function always constructs a valid certificate which checks out
-/
def construct_nzkp_certificate (w x : zmod q) (h : zmod p) (H : h = g^x.val) :
Σ (t c s : zmod q), zkp_transcript p q g hash w x h H (response t c s) :=
let
t : zmod q := g^w.val,
c : zmod q := hash [g, h, t],
s : zmod q := w + c * x
in ⟨t, c, s, response_step t c s rfl (challenge_step t c rfl (commitment_step t rfl)) ⟩
/- a given certificate is a valid one -/
def accept_nzkp_certificate (w x : zmod q) (h : zmod p) (H : h = g^x.val)
(t c s : zmod q) (Hnzkp : zkp_transcript p q g hash w x h H (response t c s)) :=
g^s.val = t * h^c.val
/- invalid transcript -/
def reject_nzkp_certificate (w x : zmod q) (h : zmod p) (H : h = g^x.val)
(t c s : zmod q) (Hnzkp : zkp_transcript p q g hash w x h H (response t c s)) :=
g^s.val ≠ t * h^c.val
/-
Proof that the construct_nzkp_certificate function always constructs
a valid certificate. Each valid certificate always checks out.
Completeness
-/
theorem proof_of_completeness : ∀ (w x : zmod q) (h : zmod p) (H₀ : h = g^x.val) cert
(H₁ : cert = construct_nzkp_certificate p q g hash w x h H₀),
accept_nzkp_certificate p q g hash w x h H₀ cert.1 cert.2.1 cert.2.2.1 cert.2.2.2 = true :=
λ w x h H₀ ⟨t, c, s, H₂⟩ H₁,
begin
unfold accept_nzkp_certificate, simp,
clear _fun_match _x,
unfold construct_nzkp_certificate at H₁,
/- I am struck here -/
end
end nzkp
Mario Carneiro (Dec 06 2020 at 06:38):
cases H1
should mostly work
Mukesh Tiwari (Dec 06 2020 at 06:52):
@Mario Carneiro Thanks, and now I have a straight forward goal, but library_search is not suggesting anything. How to get rid of this one? (In general, how should a newcomer search for a lemma in mathlib library?)
g ^ (comm_ring.add w (↑(hash [g, g ^ x.val, ↑(↑g ^ w.val)]) * x)).val = ↑(↑g ^ w.val) * (g ^ x.val) ^ (hash [g, g ^ x.val, ↑(↑g ^ w.val)]).cast.val
Mario Carneiro (Dec 06 2020 at 06:55):
alternatively, you can use injection H1
a few times to avoid substituting everything in and making a mess of the goal
Mario Carneiro (Dec 06 2020 at 06:55):
I wouldn't expect library search to find anything for that - would you expect that exact theorem to be in the library?
Mario Carneiro (Dec 06 2020 at 06:57):
instead, try to think of the reason you think this goal is straightforward, and write down the general theorem statement that you think will be in the library. Then library_search
will be able to prove it
Mario Carneiro (Dec 06 2020 at 07:08):
Here's a slightly more refined unfolding of the assumption:
begin
unfold accept_nzkp_certificate, simp,
clear _fun_match _x,
unfold construct_nzkp_certificate at H₁,
obtain ⟨rfl, rfl⟩ : t = g ^ w.val ∧ s = w + c * x, {cases H₁, split; refl},
clear H₁,
subst H₀,
rw [← pow_mul],
-- ⊢ g ^ (w + c * x).val = ↑(↑g ^ w.val) * g ^ (x.val * c.val)
end
However the next steps aren't so easy. There are two things in the way of the obvious proof: the zmod.val
function is not a homomorphism, which is blocking simplifying things like (w + c * x).val = w.val + c.val * x.val
, and there is a coercion around the power ↑(↑g ^ w.val)
which is the zmod q -> zmod p
coercion, which has really bad properties unless p
divides q
(and I haven't read the rest of the file carefully but I would assume these are primes so that wouldn't be the case)
Mukesh Tiwari (Dec 06 2020 at 07:38):
@Mario Carneiro Yep, p and q are prime (p = k * q + 1 where k >= 2). I feel if I turn zmod p and zmod q into finite field, it would much simpler to prove this, and later, I can instantiate with these concrete instances.
Mario Carneiro (Dec 06 2020 at 07:39):
that sounds likely
Mario Carneiro (Dec 06 2020 at 07:40):
all this casting zmod to nat does real damage to the number theoretic properties; it would be easier if you use only "approved" operations from field theory
Mukesh Tiwari (Dec 06 2020 at 07:46):
(deleted)
Last updated: Dec 20 2023 at 11:08 UTC