Section SigmaProtocol.
Variable R : Blist -> Blist -> bool.
Variable t : nat.
Variable (Commitment Response P_State : Set)
(P_commit : Blist -> Blist -> Comp (P_State * Commitment))
(V_challenge : Blist -> Commitment -> Comp (Bvector t))
(P_respond : P_State -> Bvector t -> Comp Response)
(V_accept :  Blist -> Commitment -> Bvector t -> Response -> bool).
Variable extract : Blist -> Commitment -> Bvector t -> Bvector t -> Response -> Response -> Comp Blist.
(* Also, extract must be efficient *)
Variable Commitment_EqDec : EqDec Commitment.
Variable Response_EqDec : EqDec Response.
Definition Protocol x w :=
[s_P, a] <-$2 P_commit x w;
e <-$ V_challenge x a;
z <-$ P_respond s_P e;
ret (a, e, z).
(* The ZK simulator *)
Variable M : Blist -> Bvector t -> Comp (Commitment * Response).
Definition G_S x :=
e <-$ {0, 1}^t;
[a, z] <-$2 M x e;
b <-$ ret (V_accept x a e z);
ret (b, (a, e, z)).
Definition G_P x w :=
[a, e, z] <-$3 Protocol x w;
b <-$ ret (V_accept x a e z);
ret (b, (a, e, z)).
Class SigmaProtocol
:= {
poly1 : nat -> nat;
w_length : forall x w, R x w = true -> (length w <= poly1 (length x))%nat;
completeness : forall x w,
R x w = true ->
Pr[[a, e, z] <-$3 Protocol x w; ret (V_accept x a e z)] == 1;
special_soundness : forall x a e e' z z',
e <> e' ->
(exists w, In (a, e, z) (getSupport (Protocol x w))) ->
(exists w, In (a, e', z') (getSupport (Protocol x w))) ->
V_accept x a e z = true ->
V_accept x a e' z' = true ->
Pr[w <-$ extract x a e e' z z'; ret (R x w)] == 1; (* Or perhaps just non-negligible *)
sHVZK : forall x w c,
evalDist (G_S x) (true, c) == evalDist (G_P x w) (true,c)
}.
End SigmaProtocol.
Ltac destruct_exists :=
match goal with
| [H : exists x, _ |- _ ] =>
destruct H
end.
intuition.
simpl in *.
apply in_getUnique_if in H.
eapply in_flatten in H.
destruct H.
intuition.
apply in_map_iff in H0.
destruct H0.
intuition.
subst.
econstructor.
intuition;
eauto.
Qed.
Ltac simp_in_support :=
match goal with
| [H : In _ (getSupport (Bind _ _)) |- _ ] =>
apply getSupport_Bind_In in H; destruct_exists; intuition
| [H : In _ (getSupport (if ?t then _ else _)) |- _ ] => let x := fresh "x" in remember t as x; destruct x
| [H : In _ (getSupport (ret _)) |- _ ] => simpl in H; intuition; try pairInv; subst
(*     | [H : false = inRange _ _ |- _] => symmetry in H *)
| [H : true = negb ?t |- _ ] => let x := fresh "x" in remember t as x; destruct x; simpl in H; try discriminate
end.

Lemma getSupport_In_Bind : forall (A B : Set) b (c : Comp B)(f : B -> Comp A) a,
In b (getSupport c) ->
In a (getSupport (f b)) ->
In a (getSupport (Bind c f)).