(* Copyright 2012-2015 by Adam Petcher.				* * Use of this source code is governed by the license described	* * in the LICENSE file at the root of the source tree.		*)
(* This file contains two high level arguments:  1) (DistSingle) When an adversary cannot distinguish two distributions when given one sample, then he cannot distinguish the distributions when given polynomially many samples.  2) (RepeatCore) When an adversary cannot distinguish two distributions when given a polynomial number of samples, he cannot distinguish the distributions when given one sample from some "core" of the distributions that has polynomial size.  *)
Set Implicit Arguments.
Require Export FCF.Hybrid.
Local Open Scope list_scope.
(* An argument showing that two distributions are indistinguishable even when multiple samples are given to the adversary. *)
Section DistMult.
Variable A B : Set.
Hypothesis B_EqDec : EqDec B.
Variable c1 c2 : A -> Comp B.
Variable A_State : Set.
Variable A1 : Comp (A * A_State).
Variable A2 : A_State -> list B -> Comp bool.
Variable n : nat.
Definition DistMult_G(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
b <-$ compMap _ (fun _ => (c a)) (forNats n);
A2 s_A b.
Definition DistMult_Adv :=
| Pr[DistMult_G c1] - Pr[DistMult_G c2] |.
End DistMult.
Section DistSingle_impl_Mult.
Variable A B : Set.
Variable A_EqDec : EqDec A.
Variable B_EqDec : EqDec B.
Variable c1 c2 : A -> Comp B.
Variable A_State : Set.
Variable A_State_EqDec : EqDec A_State.
Variable A1 : Comp (A * A_State).
Variable A2 : A_State -> list B -> Comp bool.
Hypothesis c1_wf : forall a, well_formed_comp (c1 a).
Hypothesis c2_wf : forall a, well_formed_comp (c2 a).
(* Produce a list of length n derived from c1, and c2.  The first i values come from c1, and the rest come from c2. *)
Definition computeHybrid(n i : nat) a : Comp (list B) :=
b1 <-$ compMap _ (fun _ => (c1 a)) (forNats i);
b2 <-$ compMap _ (fun _ => (c2 a)) (forNats (minus n i));
ret (b1 ++ b2).
Variable n : nat.
Hypothesis n_pos : n > 0.

Theorem hybrid_replace_c1_equiv :
forall i x a,
i < n ->
evalDist
(b <-$ (c1 a);
hybrid <-$ computeHybrid n i a;
ret (listReplace hybrid i b b)) x ==
evalDist (computeHybrid n (S i) a) x.