ITree.Extra.Secure.SecureEqProgInsens

From Coq Require Import Morphisms.

From ITree Require Import
     Axioms
     ITree
     ITreeFacts.

From ITree.Extra Require Import
     Secure.SecureEqHalt
.

From Paco Require Import paco.

Import Monads.
Import MonadNotation.
Local Open Scope monad_scope.

(* will need more propositional constraints on Preorders *)

Section SecureProgInsens.
  Context {E : Type Type} {R1 R2 : Type}.
  Context (Label : Preorder).
  Context (priv : A, E A L).
  Context (RR : Prop).

  (*
  Context (RE : forall A, E A -> E A -> A -> A -> Prop).
  want it to be an equivalence
  *)


  Variant pi_secure_eqitF (b1 b2 : bool) (l : L) vclo (sim : itree E itree E Prop) : itree' E itree' E Prop :=

    (* eqitF constructors *)
    | pisecEqRet r1 r2 : RR pi_secure_eqitF l vclo sim (RetF ) (RetF )
    | pisecEqTau t1 t2 : sim pi_secure_eqitF l vclo sim (TauF ) (TauF )
    | pisecEqTauL t1 t2 (CHECK : ) : sim pi_secure_eqitF l vclo sim (TauF ) (observe )
    | pisecEqTauR t1 t2 (CHECK : ) : sim pi_secure_eqitF l vclo sim (observe ) (TauF )
    (* info_flow protecting coinductive constructors *)
    | piEqVisPriv {A} (e : E A) k1 k2 (SECCHECK : leq (priv A e) l) :
        (( a, vclo sim ( a) ( a) : Prop)) pi_secure_eqitF l vclo sim (VisF e ) (VisF e )
    | piEqVisUnPrivTauLCo {A} (e : E A) k1 t2 (SECCHECK : ¬ leq (priv A e) l) :
        ( a, vclo sim ( a) ) pi_secure_eqitF l vclo sim (VisF e ) (TauF )
    | piEqVisUnPrivTauRCo {A} (e : E A) t1 k2 (SECCHECK : ¬ leq (priv A e) l) :
        ( a, vclo sim ( a)) pi_secure_eqitF l vclo sim (TauF ) (VisF e )
    | piEqVisUnPrivVisCo {A B} (e1 : E A) (e2 : E B) k1 k2 (SECCHECK1 : ¬ leq (priv A ) l) (SECCHECK2 : ¬ leq (priv B ) l)
        :
        ( a b, vclo sim ( a) ( b)) pi_secure_eqitF l vclo sim (VisF ) (VisF )
    (* info_flow protecting inductive constructors *)
    | piEqVisUnPrivLInd {A} (e : E A) k1 t2 (CHECK : ) (SECCHECK : ¬ leq (priv A e) l) :
        ( a, vclo sim ( a) )
        pi_secure_eqitF l vclo sim (VisF e ) (observe )
    | piEqVisUnPrivRInd {A} (e : E A) t1 k2 (CHECK : ) (SECCHECK : ¬ leq (priv A e) l) :
        ( a, vclo sim ( a) )
        pi_secure_eqitF l vclo sim (observe ) (VisF e )
  .

  Hint Constructors pi_secure_eqitF : itree.

  Definition pi_secure_eqit_ (b1 b2 : bool) (l : L) vclo (sim : itree E itree E Prop) : itree E itree E Prop :=
    fun t1 t2pi_secure_eqitF l vclo sim (observe ) (observe ).

  Hint Unfold pi_secure_eqit_ : itree.

  Lemma pi_secure_eqitF_mono b1 b2 l x0 x1 vclo vclo' sim sim'
        (IN: pi_secure_eqitF l vclo sim )
        (MON: vclo)
        (LEc: vclo <3= vclo')
        (LE: sim <2= sim'):
    pi_secure_eqitF l vclo' sim' .
  Proof.
    intros. induction IN; eauto with itree.
  Qed.


  Lemma pi_secure_eqit_mono b1 b2 l vclo (MON: vclo) : (pi_secure_eqit_ l vclo).
  Proof.
    do 2 red. intros; eapply pi_secure_eqitF_mono; eauto with itree.
  Qed.


  Hint Resolve pi_secure_eqit_mono : paco.

  Definition pi_eqit_secure b1 b2 l := (pi_secure_eqit_ l id) .

  (* want and eqitC_secure which could help prove some interesting stuff

   *)


End SecureProgInsens.

#[export] Hint Resolve pi_secure_eqit_mono : paco.
#[export] Hint Constructors pi_secure_eqitF : itree.

Ltac unpriv_pi := try apply piEqVisUnPrivVisCo;
                  try apply piEqVisUnPrivTauLCo;
                  try apply piEqVisUnPrivTauRCo;
                  try apply piEqVisUnPrivLInd;
                  try apply piEqVisUnPrivRInd;
                  auto with itree; intros.

Ltac contra_size :=
  match goal with
  | [ Hemp : empty ?A, Hne : nonempty ?A |- _ ] ⇒ inv Hemp; inv Hne; contradiction end.

Lemma eqit_secure_imp_pi_eqit_scure b1 b2 E R1 R2 RR Label priv l : (t1 : itree E ) (t2 : itree E ),
    eqit_secure Label priv RR l pi_eqit_secure Label priv RR l .
Proof.
  pcofix CIH. intros Hps. pfold. red. punfold Hps. red in Hps.
  hinduction Hps before r; intros.
  - constructor; auto with itree.
  - constructor. right. pclearbot. eauto with itree.
  - rewrite itree_eta'. constructor; auto with itree. right. eapply CIH. pfold. apply Hps.
  - rewrite itree_eta' at 1. constructor; auto with itree. right. eapply CIH. pfold. apply Hps.
  - pclearbot. constructor; auto with itree. right. eapply CIH; eauto with itree. apply H.
  - pclearbot. unpriv_pi. right. eapply CIH; apply H.
  - pclearbot. unpriv_pi. right. eapply CIH; apply H.
  - pclearbot. unpriv_pi. right. eapply CIH; apply H.
  - pclearbot. unpriv_pi. right. eapply CIH. pfold. apply H.
  - pclearbot. unpriv_pi. right. eapply CIH. pfold. apply H.
  - unpriv_pi. inv SIZECHECK. contradiction.
  - unpriv_pi. inv SIZECHECK. contradiction.
  - unpriv_pi. inv SIZECHECK. contradiction.
  - unpriv_pi. inv SIZECHECK. contradiction.
Qed.


Lemma pi_eqit_secure_sym b1 b2 E R1 R2 RR Label priv l : (t1 : itree E ) (t2 : itree E ),
    pi_eqit_secure Label priv RR l pi_eqit_secure Label priv (flip RR) l .
Proof.
  pcofix CIH. intros Hsec.
  punfold Hsec. pfold. red in Hsec. red. inversion Hsec; pclearbot; eauto;
  try (unpriv_pi; right; eapply CIH; apply ; fail).
  constructor; auto. right. eapply CIH; apply .
Qed.


Lemma pi_secure_eqit_mon : E (b1 b2 b3 b4 : bool) R1 R2 RR1 RR2 Label priv l
      (t1 : itree E ) (t2 : itree E ),
    ( ) ( ) ( <2= )
    pi_eqit_secure Label priv l pi_eqit_secure Label priv l .
Proof.
  intros. generalize dependent . revert . pcofix CIH.
  intros . pstep. red.
  punfold . red in .
  hinduction before r; intros; eauto; pclearbot;
  try (unpriv_pi; right; apply CIH; try red; eauto; fail);
  constructor; auto. right. eauto. apply CIH; apply .
Qed.


Lemma pi_eqit_secure_spin b E R1 R2 (RR : Prop) Label priv l : (t1 : itree E ),
    pi_eqit_secure Label priv RR b true l (ITree.spin).
Proof.
  pcofix CIH. intros. pfold. red. cbn. constructor; auto.
Qed.


Lemma pi_eqit_secure_private_halt b E R1 R2 (RR : Prop) Label priv l A (e : E A) k:
  empty A ¬ leq (priv A e) l (t1 : itree E ),
    pi_eqit_secure Label priv RR b true l (Vis e k).
Proof.
  intros HA . pfold. red. cbn. intros. unpriv_pi. inv HA; contradiction.
Qed.


Lemma pi_eqit_secure_mixed_trans_aux1:
   (E : Type Type) (R1 : Type) (b2 : bool) (R2 : Type) (RR1 : Prop)
    (Label : Preorder) (priv : A : Type, E A L) (l : L) t1 t2,
     (pi_secure_eqit_ Label priv true l id) (Tau )
    pi_eqit_secure Label priv true l .
Proof.
  intros E Label priv l. pcofix CIH.
  intros Htau. punfold Htau. red in Htau.
  pfold. red. cbn in ×. inv Htau; pclearbot; eauto.
  - constructor; auto. left. eapply paco2_mon; eauto. intros; contradiction.
  - constructor; auto. right. eapply CIH; eauto. pfold. red. rewrite .
    cbn. pstep_reverse.
  - pstep_reverse. eapply paco2_mon; eauto. intros; contradiction.
  - unpriv_pi. left. eapply paco2_mon; eauto. intros; contradiction.
  - unpriv_pi. right. eapply CIH. pfold. red. rewrite .
    cbn. pstep_reverse.
Qed.


Lemma pi_eqit_secure_mixed_trans b1 b2 E R1 R2 R3 (RR1 : Prop) (RR2 : Prop)
      Label priv l : (t1 : itree E ) t2 t3,
    pi_eqit_secure Label priv l eqit
    pi_eqit_secure Label priv (rcompose ) l .
Proof.
  pcofix CIH. intros Hsec Heq. punfold Heq.
  red in Heq. punfold Hsec. red in Hsec. pfold. red.
  hinduction Heq before r; intros; try inv CHECK; pclearbot.
  - inv Hsec; eauto with itree; unpriv_pi; pclearbot.
    + rewrite itree_eta'. constructor; auto with itree. right. eapply CIH; eauto.
      pfold. red. rewrite . constructor. auto.
    + rewrite itree_eta'. unpriv_pi. right. eapply CIH; eauto.
      apply . pfold. red. rewrite . constructor; auto.
  - inv Hsec; pclearbot; eauto with itree.
    + constructor. right. eapply CIH; eauto with itree.
      pfold. red. rewrite . constructor; auto. pstep_reverse.
    + unpriv_pi. right. eapply CIH; eauto. apply .
    + rewrite itree_eta'. unpriv_pi. right. eapply CIH; eauto.
      inv CHECK. apply pi_eqit_secure_mixed_trans_aux1.
      pfold. red. rewrite . cbn. pstep_reverse.
  - inv Hsec.
    + pclearbot. rewrite itree_eta'. constructor; auto. right. eapply CIH; eauto.
      pfold. red. rewrite . constructor. left. auto.
    + ddestruction. subst. constructor; auto with itree. right.
      pclearbot. eapply CIH; eauto with itree. apply .
    + ddestruction. subst. unpriv_pi. right. pclearbot.
      eapply CIH; eauto with itree. apply .
    + ddestruction. subst. unpriv_pi. right. pclearbot.
      eapply CIH; eauto with itree. apply .
    + pclearbot. remember (VisF e ) as ovis. rewrite itree_eta'.
      unpriv_pi. rewrite Heqovis. right. eapply CIH; eauto with itree. apply .
      pfold. red. rewrite . constructor. left. auto.
    + ddestruction. subst. unpriv_pi. right. eapply CIH; eauto with itree. pclearbot. apply .
  - eapply IHHeq; eauto. clear IHHeq. inv Hsec; pclearbot.
    + constructor; auto.
    + constructor; auto. left. apply pi_eqit_secure_mixed_trans_aux1. pfold. red.
      rewrite . cbn. pstep_reverse.
    + pstep_reverse.
    + unpriv_pi.
    + unpriv_pi. left. apply pi_eqit_secure_mixed_trans_aux1. pfold. red.
      rewrite . cbn. pstep_reverse.
  - constructor; auto. left. pfold. eapply IHHeq; eauto.
Qed.


Lemma pi_eqit_secure_RR_imp b1 b2 E R1 R2 (RR1 : Prop ) (RR2 : Prop)
      Label priv l : ( r1 r2, )
                      (t1 : itree E ) (t2 : itree E ),
      pi_eqit_secure Label priv l
      pi_eqit_secure Label priv l .
Proof.
  intro Himp. pcofix CIH.
  intros. pfold. red. punfold . red in .
  inv ; eauto;
  try (constructor; auto; pclearbot; eauto; fail);
  try (pclearbot; constructor; auto; right; eapply CIH; eauto; try apply ; fail).
Qed.


Lemma pi_eqit_secureC_wcompat_id : b1 b2 E R1 R2 (RR : Prop )
      Label priv l
, wcompatible2 (@pi_secure_eqit_ E Label priv RR l id)
                                         (eqitC RR ) .
Proof.
  econstructor. pmonauto_itree.
  intros. destruct PR.
  punfold EQVl. punfold EQVr. unfold_eqit. red in REL. red.
  hinduction REL before r; intros; clear ; try inv CHECK.
  - genobs_clear . genobs_clear .
    remember (RetF ) as x.
    hinduction EQVl before r; intros; inv Heqx; eauto.
    + remember (RetF ) as y.
      hinduction EQVr before r; intros; inv Heqy; eauto with itree.
      rewrite itree_eta' at 1. constructor; eauto with itree. gstep. red.
      eapply IHEQVr; eauto.
    + rewrite itree_eta'. constructor; auto. cbn. gstep. red. cbn.
      eauto.
  - remember (TauF ) as y.
    hinduction EQVl before r; intros; inv Heqy; try inv CHECK; subst; eauto.
    + remember (TauF ) as x.
      hinduction EQVr before r; intros; inv Heqx; try inv CHECK; subst; eauto.
      pclearbot. constructor. gclo. econstructor; eauto with paco.
      pclearbot.
      remember (TauF ) as . rewrite itree_eta' at 1.
      constructor; auto. rewrite . gstep. red. cbn. eauto.
    + constructor; auto. gstep. red. eapply IHEQVl; eauto.
  - inv EQVl; pclearbot; try inv CHECK.
    + constructor; auto. gclo. econstructor; eauto with paco itree.
    + constructor; auto. gclo. econstructor; eauto with paco itree.
      apply eqit_inv_Tau_r. pfold. auto.
  - inv EQVr; pclearbot; try inv CHECK.
    + constructor; auto. gclo. econstructor; eauto with paco itree.
    + constructor; auto. gclo. econstructor; eauto with paco itree.
      apply eqit_inv_Tau_r. pfold. auto.
  - remember (VisF e ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; eauto.
    + ddestruction. subst. remember (VisF ) as y.
      hinduction EQVr before r; intros; inv Heqy; try inv CHECK; eauto.
      × ddestruction. subst. constructor; auto.
        intros. apply gpaco2_clo. pclearbot. econstructor; eauto with itree. apply H.
      × pclearbot. remember (VisF ) as ovis. rewrite itree_eta' at 1.
        constructor; auto. rewrite Heqovis. gstep. red. eapply IHEQVr; eauto with itree.
    + constructor; auto. gstep. red. eapply IHEQVl; eauto.
  - remember (VisF e ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; subst; eauto.
    + ddestruction. subst. pclearbot. remember (TauF ) as y.
      hinduction EQVr before r; intros; inv Heqy; try inv CHECK; subst; pclearbot; eauto.
      × unpriv_pi. gclo. econstructor; cycle -1; eauto with paco itree. gfinal. left. apply H.
      × remember (VisF ) as ovis. rewrite itree_eta' at 1. constructor; auto.
        rewrite Heqovis. gstep. red. eapply IHEQVr; eauto.
    + constructor; auto. gstep. red. eapply IHEQVl; eauto.
  - remember (TauF ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; subst; eauto.
    + remember (VisF e ) as y.
      hinduction EQVr before r; intros; inv Heqy; try inv CHECK; subst; eauto.
      × ddestruction. subst.
        pclearbot. unpriv_pi. gclo. econstructor; cycle -1; eauto with paco itree.
        gfinal. left. apply H.
      × remember (TauF ) as . rewrite itree_eta' at 1. constructor; auto.
        gstep. rewrite . red. eapply IHEQVr; eauto.
   + constructor; auto. gstep. red. eapply IHEQVl; eauto.
  - remember (VisF ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; subst; eauto.
    + ddestruction. subst. remember (VisF ) as y.
      hinduction EQVr before r; intros; inv Heqy; try inv CHECK; subst; eauto.
      × ddestruction. subst. unpriv_pi. gclo. pclearbot.
        econstructor; eauto with paco itree. gfinal. left. apply H.
      × remember (VisF ) as ovis. rewrite itree_eta' at 1.
        constructor; auto. rewrite Heqovis. gstep. eapply IHEQVr; eauto.
    + remember (VisF ) as x.
      hinduction EQVr before r; intros; inv Heqx; try inv CHECK; subst; eauto.
      × ddestruction. subst. pclearbot. unpriv_pi.
         gclo. eapply eqit_trans_clo_intro with ( := Vis ); eauto with paco itree.
         gstep. red. cbn. unpriv_pi. gfinal. left. apply H.
       × remember (TauF ) as . rewrite itree_eta' at 1. constructor; auto.
         rewrite . gstep. red. eapply IHEQVr; eauto.
  - remember (VisF e ) as x.
    hinduction EQVl before r; intros; inv Heqx; try inv CHECK; eauto.
    + ddestruction. subst. pclearbot. unpriv_pi.
      gclo. econstructor; eauto with paco itree. gfinal. left. apply H.
    + constructor; auto. gstep. eapply IHEQVl; eauto.
  - remember (VisF e ) as x.
    hinduction EQVr before r; intros; inv Heqx; try inv CHECK; eauto.
    + ddestruction. subst. pclearbot. unpriv_pi.
      gclo. econstructor; eauto with paco itree. gfinal. left. apply H.
    + constructor; auto. gstep. eapply IHEQVr; eauto.
Qed.


#[export] Hint Resolve pi_eqit_secureC_wcompat_id : paco.

Global Instance geuttgen_cong_secure_eqit {E} {Label priv l} {R1 R2 : Type} {RR1 : Prop}
    {RR2 : Prop} {RS : Prop} (b1 b2 : bool) {r rg} :
    ( (x x' : ) (y : ), ( x x' : Prop) (RS x' y : Prop) RS x y)
    ( (x : ) (y y' : ), ( y y' : Prop) RS x y' RS x y)
    Proper (@eq_itree E eq_itree flip impl)
           ( (pi_secure_eqit_ Label priv RS l id) (eqitC RS ) r rg ).
Proof.
  repeat intro. gclo. econstructor; eauto with itree.
  - eapply eqit_mon, ; eauto; discriminate.
  - eapply eqit_mon, ; eauto; discriminate.
Qed.


Global Instance geuttgen_cong_eq_secure_eqit {E} {Label priv l} {R1 R2 : Type} {RS : Prop} (b1 b2 : bool) {r rg} :
    Proper (@eq_itree E eq eq_itree eq flip impl)
           ( (pi_secure_eqit_ Label priv RS l id) (eqitC RS ) r rg ).
Proof.
  eapply geuttgen_cong_secure_eqit; eauto; intros; subst; auto.
Qed.


Global Instance pi_eqit_secure_eq_itree_proper {E} {Label priv l} {R1 R2 : Type} {RS : Prop} (b1 b2 : bool) :
   Proper (@eutt E eq eutt eq flip impl)
          (pi_eqit_secure Label priv RS true true l).
Proof.
  intros . intros Hsec.
  apply pi_eqit_secure_RR_imp with ( := rcompose RS eq).
  { intros. inv H. auto. }
  eapply pi_eqit_secure_mixed_trans. 2: { symmetry in . apply . }
  apply pi_eqit_secure_sym in Hsec. apply pi_eqit_secure_sym.
  symmetry in .
  apply pi_eqit_secure_RR_imp with ( := rcompose (flip RS) eq).
  { intros. inv H. auto. }
  eapply pi_eqit_secure_mixed_trans; eauto.
Qed.


Global Instance pi_eqit_secure_eutt_proper {E} {Label priv l} {R1 R2 : Type} {RS : Prop} (b1 b2 : bool) :
   Proper (@eq_itree E eq eq_itree eq flip impl)
          (pi_eqit_secure Label priv RS l).
Proof.
  repeat intro. ginit. rewrite H, . gfinal. eauto.
Qed.


Lemma pi_eqit_secure_ret E Label priv l b1 b2 R1 R2 (RR : Prop) r1 r2 :
  RR @pi_eqit_secure E Label priv RR l (Ret ) (Ret ).
Proof.
  intros; pfold; constructor; auto.
Qed.


Lemma pi_eqit_secure_bind E Label priv l b1 b2 R1 R2 S1 S2 (RR : Prop) (RS : Prop) k1 k2 :
   (t1 : itree E ) (t2 : itree E ),
    ( (r1 : ) (r2 : ), RR pi_eqit_secure Label priv RS l ( ) ( ) )
    pi_eqit_secure Label priv RR l
    pi_eqit_secure Label priv RS l (ITree.bind ) (ITree.bind ).
Proof.
  ginit. gcofix CIH. intros. pinversion .
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    repeat rewrite bind_ret_l. gfinal. right. eapply paco2_mon; try apply ; auto.
    intros; contradiction.
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    repeat rewrite bind_tau. gstep. constructor. gfinal. left. eapply CIH; eauto.
  - apply simpobs in H. apply simpobs in . rewrite . rewrite H. rewrite bind_tau.
    gstep. constructor; auto. gfinal. left. eapply CIH; eauto.
    pfold. red. cbn. pstep_reverse.
  - apply simpobs in H. apply simpobs in . rewrite . rewrite H. rewrite bind_tau.
    gstep. constructor; auto. gfinal. left. eapply CIH; eauto.
    pfold. red. cbn. pstep_reverse.
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    repeat rewrite bind_vis. gstep. constructor; auto.
    gfinal. left. eapply CIH; eauto. apply .
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    rewrite bind_vis. rewrite bind_tau. gstep. red. cbn. unpriv_pi.
    gfinal. left. eapply CIH; eauto. apply .
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    rewrite bind_vis. rewrite bind_tau. gstep. red. cbn. unpriv_pi.
    gfinal. left. eapply CIH; eauto. apply .
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    repeat rewrite bind_vis. gstep. red. cbn. unpriv_pi.
    gfinal. left. eapply CIH; eauto. apply .
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    rewrite bind_vis. gstep. red. unpriv_pi.
    gfinal. left. eapply CIH; eauto. pfold. red. cbn. pstep_reverse.
  - apply simpobs in H. apply simpobs in . rewrite H. rewrite .
    rewrite bind_vis. gstep. red. unpriv_pi.
    gfinal. left. eapply CIH; eauto. pfold. red. cbn. pstep_reverse.
Qed.


Lemma pi_eqit_secure_iter_bind_aux:
   (E : Type Type) (B2 B1 A1 A2 : Type) (RA : Prop)
    (RB : Prop) (b1 b2 : bool) (Label : Preorder)
    (priv : A : Type, E A L) (l : L) (body1 : itree E ( + ))
    (body2 : itree E ( + )) (r : itree E itree E Prop),
    ( (a1 : ) (a2 : ), RA r (ITree.iter ) (ITree.iter ))
     (t1 : itree E ( + )) (t2 : itree E ( + )),
       (pi_secure_eqit_ Label priv (HeterogeneousRelations.sum_rel RA RB) l id)
            
       (pi_secure_eqit_ Label priv RB l id) (eqitC RB ) r r
             (ITree.bind
                         (fun lr : +
                            match lr with
                            | inl Tau (ITree.iter )
                            | inr Ret
                            end))
             (ITree.bind
                         (fun lr : +
                            match lr with
                            | inl Tau (ITree.iter )
                            | inr Ret
                            end)).
Proof.
  intros E RA RB Label priv l r CIH .
  generalize dependent . revert . gcofix CIH'. intros .
  pinversion ; apply simpobs in H; apply simpobs in .
  - rewrite H, . repeat rewrite bind_ret_l. inv .
    + gstep. constructor. gfinal. left. apply . eapply CIH; eauto.
    + gstep. constructor; auto.
  - rewrite H, . repeat rewrite bind_tau. gstep. constructor.
    gfinal. left. eapply CIH'; eauto.
  - rewrite H. rewrite itree_eta in . rewrite . rewrite bind_tau. gstep.
    constructor; auto. gfinal.
    left. eapply CIH'; eauto.
  - rewrite . rewrite itree_eta in H. rewrite H. rewrite bind_tau. gstep.
    constructor; auto. gfinal.
    left. eapply CIH'; eauto.
  - rewrite H, . repeat rewrite bind_vis. gstep. constructor; auto.
    intros. gfinal. left. eauto.
  - rewrite H, . rewrite bind_vis, bind_tau. gstep. unpriv_pi; auto.
    intros. gfinal. left. eauto.
  - rewrite H, . rewrite bind_vis, bind_tau. gstep. unpriv_pi; auto.
    intros. gfinal. left. eauto.
  - rewrite H, . repeat rewrite bind_vis. gstep. unpriv_pi.
    gfinal. left. eauto.
  - rewrite H. rewrite itree_eta in . rewrite . rewrite bind_vis.
    gstep. unpriv_pi. gfinal. left. eauto.
  - rewrite . rewrite itree_eta in H. rewrite H. rewrite bind_vis.
    gstep. unpriv_pi. gfinal. left. eauto.
Qed.


Lemma secure_eqit_iter E A1 A2 B1 B2 (RA : Prop) (RB : Prop)
                           b1 b2 Label priv l
                           (body1 : itree E ( + ) ) (body2 : itree E ( + ) ):
  ( a1 a2, RA pi_eqit_secure Label priv (HeterogeneousRelations.sum_rel RA RB) l ( ) ( ) )
                            (a1 : ) (a2 : ), RA
    pi_eqit_secure Label priv RB l (ITree.iter ) (ITree.iter ).
Proof.
  intro Hbody. ginit. gcofix CIH. intros. rewrite unfold_iter. rewrite unfold_iter.
  apply Hbody in . pinversion ; apply simpobs in H; apply simpobs in .
  - rewrite H. rewrite . repeat rewrite bind_ret_l. inv .
    + gstep. constructor. gfinal. left. eapply CIH; eauto.
    + gstep. constructor; auto.
  - rewrite H. rewrite . repeat rewrite bind_tau. gstep.
    constructor. eapply pi_eqit_secure_iter_bind_aux; eauto.
  - rewrite H. rewrite bind_tau. gstep. constructor; auto.
    eapply pi_eqit_secure_iter_bind_aux; eauto.
    assert ( ).
    { rewrite H. rewrite tau_eutt. reflexivity. }
    inv CHECK. rewrite itree_eta in . rewrite . auto.
  - rewrite . rewrite bind_tau. gstep. constructor; auto.
    eapply pi_eqit_secure_iter_bind_aux; eauto. rewrite H.
    rewrite itree_eta. apply .
  - rewrite H, . repeat rewrite bind_vis. gstep. constructor; auto.
    intros. red.
    eapply pi_eqit_secure_iter_bind_aux; eauto.
  - rewrite H, . rewrite bind_vis, bind_tau. gstep. unpriv_pi.
    eapply pi_eqit_secure_iter_bind_aux; eauto.
  - rewrite H, . rewrite bind_vis, bind_tau. gstep. unpriv_pi.
    eapply pi_eqit_secure_iter_bind_aux; eauto.
  - rewrite H, . repeat rewrite bind_vis. gstep. unpriv_pi.
    eapply pi_eqit_secure_iter_bind_aux; eauto.
  - rewrite H. rewrite bind_vis. gstep. unpriv_pi.
    eapply pi_eqit_secure_iter_bind_aux; eauto.
    rewrite . rewrite itree_eta. apply .
  - rewrite . rewrite bind_vis. gstep. unpriv_pi. red.
    rewrite H. rewrite itree_eta.
    eapply pi_eqit_secure_iter_bind_aux; eauto.
Qed.