eapply leRat_trans.
2:{
eapply eqRat_impl_leRat.
rewrite DistSingle_G1_equiv.
rewrite DistSingle_G2_equiv.
rewrite DistSingle_G2_equiv.
rewrite DistSingle_G3_c1_equiv.
rewrite DistSingle_G3_c2_equiv.
eapply eqRat_refl.
}
eapply leRat_trans.
2:{
eapply eqRat_impl_leRat.
unfold DistSingle_G3_c1, DistSingle_G3_c2.
rewrite rndNat_sumList.
rewrite rndNat_sumList.
rewrite sumList_factor_constant_l.
rewrite sumList_factor_constant_l.
rewrite ratMult_ratDistance_factor_l.
eapply eqRat_refl.
}
eapply leRat_trans.
2:{
eapply eqRat_impl_leRat.
rewrite <-ratMult_assoc.
rewrite ratMult_eq_rat1.
rewrite ratMult_1_l.
rewrite ratDistance_comm.
rewrite sumList_forNats_distance.
eapply eqRat_refl.
}
unfold DistMult_Adv.
unfold DistMult_G.
rewrite ratDistance_comm.
eapply eqRat_impl_leRat.
eapply ratDistance_eqRat_compat.
eapply evalDist_seq; intuition.
comp_simp.
eapply compMap_computeHybrid_0_equiv.
eapply evalDist_seq; intuition.
comp_simp.
eapply compMap_computeHybrid_n_equiv.
Grab Existential Variables.
econstructor; intuition.
Qed.
End DistSingle_impl_Mult.
Section RepeatCore.
Variable A B : Set.
Hypothesis B_EqDec : EqDec B.
Variable P : B -> bool.
Variable c1 c2 : A -> Comp B.
Variable A_State : Set.
Variable A1 : Comp (A * A_State ).
Variable A2 : A_State -> B -> Comp bool.
Definition RepeatCore_G(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
b <-$ Repeat (c a) P;
A2 s_A b.
Definition RepeatCore_Adv :=
| Pr[RepeatCore_G c1] - Pr[RepeatCore_G c2] |.
End RepeatCore.
Section DistMult_impl_RepeatCore.
Variable A B : Set.
Hypothesis B_EqDec : EqDec B.
Variable P : B -> bool.
Variable c1 c2 : A -> Comp B.
Variable A_State : Set.
Variable A1 : Comp (A * A_State).
Variable A2 : A_State -> B -> Comp bool.
Hypothesis A1_wf : well_formed_comp A1.
Hypothesis A2_wf : forall s_A b, well_formed_comp (A2 s_A b).
Hypothesis c1_wf : forall a s_A, In (a, s_A) (getSupport A1) -> well_formed_comp (c1 a).
Hypothesis c1_repeat_wf : forall a s_A, In (a, s_A) (getSupport A1) -> exists b, In b (filter P (getSupport (c1 a))).
Hypothesis c2_wf : forall a s_A, In (a, s_A) (getSupport A1) -> well_formed_comp (c2 a).
Hypothesis c2_repeat_wf : forall a s_A, In (a, s_A) (getSupport A1) -> exists b, In b (filter P (getSupport (c2 a))).
Variable n : nat.
(* Assume A1 can effectively distinguish the cores as in RepeatCore_G, construct an adversary B that can distinguish the entire distributions given multiple samples as in DistMult_G. *)
Definition DM_RC_G1(c : A -> Comp B) :=
[a, s_A] <-$2 A1;
p <-$ Repeat (b <-$ (c a); g <-$ (A2 s_A b); ret (b, g)) (fun p => P (fst p));
ret (snd p).

Theorem DM_RC_G1_equiv :
forall c x,
(forall a s_A, In (a, s_A) (getSupport A1) -> well_formed_comp (c a)) ->
(forall a s_A, In (a, s_A) (getSupport A1) -> exists b, In b (filter P (getSupport (c a)))) ->
evalDist (RepeatCore_G P A1 A2 c) x == evalDist (DM_RC_G1 c) x.