Section ProofOfKnowledge.
Context `{p : SigmaProtocol}.
Variable P_State_EqDec : EqDec P_State.
Hypothesis P_commit_well_formed : forall x y,
well_formed_comp (P_commit x y).
Hypothesis V_challenge_wf : forall x a,
well_formed_comp (V_challenge x a).
Hypothesis P_respond_well_formed : forall a b,
well_formed_comp (P_respond a b).
(* The definition of soundness requires us to construct a knowledge extractor that only has the public input and uses P as an oracle.  We want to make sure the knowledge extractor can't cheat by looking at the auxiliary input or the state of P.  We do this by creating an equivalent P in a monadic style that takes a function describing what to do with the information we get from P. *)
(* We need a rewindable oracle, and we create it by supplying two functions.  The first is a predicate which determines when a configuration is acceptable.  The second is a function that uses that configuration to produce some desired result.  The first function also returns some information that is used by the second function.  We can generalize this a bit by producing a list of acceptable configurations which are used by the second function.  *)
Definition P_respond_oracle := Bvector t -> Comp Response.
Definition rewindable_P_oracle := forall (A : Set)(eqd : EqDec A), (Commitment -> P_respond_oracle -> Comp (A * bool)) -> forall (B: Set), (A -> Commitment -> P_respond_oracle -> Comp B) -> Comp B.
Definition mk_rewindable_P_oracle x w (A : Set)(eqd : EqDec A)(f1 : Commitment -> P_respond_oracle -> Comp (A * bool))(B : Set)(f2 : A -> Commitment -> P_respond_oracle -> Comp B)  : Comp B :=
[p1, p2] <-$2 Repeat
([s_P, a] <-$2 P_commit x w;
p <-$ (f1 a (P_respond s_P));
ret (p, (s_P, a)))
(fun p => (snd (fst p)));
e <- fst p1;
s_P <- fst p2;
a <- snd p2;
f2 e a (P_respond s_P).
Hypothesis unit_EqDec : EqDec unit.
Definition P_oracle := forall (B: Set), (Commitment -> P_respond_oracle -> Comp B) -> Comp B.
Definition mk_P_oracle x w (B : Set)(f2 : Commitment -> P_respond_oracle -> Comp B) : Comp B :=
@mk_rewindable_P_oracle x w unit _
(fun a b => ret (tt, true))
_
(fun a b c => f2 b c).
Definition queryRow (respond_oracle : P_respond_oracle) x a :=
e <-$ V_challenge x a;
z <-$ respond_oracle e;
ret (e, z).
Definition d := 16.
Definition emergencyBreak (x : Blist)(oracle : P_oracle) :=
n <-$ [0 .. d);
b <-$ oracle _
(fun a resp =>
[e, z] <-$2 queryRow resp x a;
ret (V_accept x a e z));
ret (b && eqb n O).
Definition queryRowWithEmergencyBreak (oracle : P_oracle)(resp : P_respond_oracle)(x : Blist) a :=
b <-$ emergencyBreak x oracle;
p <-$ queryRow resp x a;
ret (b, p).
Definition to_P_oracle (o : rewindable_P_oracle)(B : Set)(f : Commitment -> P_respond_oracle -> Comp B) :=
(@o unit _ (fun a b => ret (tt, true)) _ (fun a b c => f b c)).
Definition acceptance_prob x y :=
Pr[mk_P_oracle x y
(fun a resp =>
[e, z] <-$2 queryRow resp x a;
ret (V_accept x a e z))].
Definition heavy (resp : P_respond_oracle) x y a :=
(1 / 2) * acceptance_prob x y <= Pr[ [e, z] <-$2 queryRow resp x a; ret (V_accept x a e z) ].
Definition isHeavy (resp : P_respond_oracle) x y a :=
bleRat ((1 / 2) * acceptance_prob x y) (Pr[ [e, z] <-$2 queryRow resp x a; ret (V_accept x a e z) ]).
(* TODO: locate [expected_time_at_most] *) (* Definition knowledge_soundness(cost : forall (A : Set), A -> Rat -> Prop)(k : Blist -> Rat) := forall x y (pf : nz (length x)), exists c, let e := acceptance_prob x y in (~(ratSubtract e (k x)) == 0) -> exists (M : Blist -> rewindable_P_oracle -> Comp Blist), let oracle := (mk_rewindable_P_oracle x y) in expected_time_at_most cost 1 (P_commit x y) -> (forall s c e, In (s, e) (getSupport (P_commit x y)) -> (expected_time_at_most cost 1 (P_respond s c))) -> expected_time_at_most cost ((expRat (length x / 1) c) * ratInverse (ratSubtract e (k x))) (M x oracle) /\ Pr[y' <- M x oracle; ret (R x y')] == 1. *)
(* Lemma evalDist_bind_case_split : forall (B : Set)(e : B -> Comp bool) v1 v2 (A : Set)(c : Comp B)(f : B -> Comp A) a, well_formed_comp c -> (forall b, (e b) = true -> (evalDist (f b) a) == v1) -> (forall b, (e b) = false -> (evalDist (f b) a) == v2) -> evalDist (Bind c f) a == Pr[Bind c e] * *)

Lemma evalDist_bind_case_split_ge : forall (B : Set)(e : B -> bool) v1 v2 (A : Set)(c : Comp B)(f : B -> Comp A) a,
well_formed_comp c ->
(forall b, In b (getSupport c) -> (e b) = true -> v1 <= (evalDist (f b) a)) ->
(forall b, In b (getSupport c) -> (e b) = false -> v2 <= (evalDist (f b) a)) ->
let v := Pr[b <-$ c; ret (e b)]  in
v * v1 + (ratSubtract 1 v) * v2 <= evalDist (Bind c f) a.