Theory Constructive_Cryptography

section β€ΉSecurityβ€Ί

theory Constructive_Cryptography imports
  Wiring
begin

definition "advantage π’œ res1 res2 = Β¦spmf (connect π’œ res1) True - spmf (connect π’œ res2) TrueΒ¦"

locale constructive_security_aux =
  fixes real_resource :: "security β‡’ ('a + 'e, 'b + 'f) resource"
    and ideal_resource :: "security β‡’ ('c + 'e, 'd + 'f) resource"
    and sim :: "security β‡’ ('a, 'b, 'c, 'd) converter"
    and ℐ_real :: "security β‡’ ('a, 'b) ℐ"
    and ℐ_ideal :: "security β‡’ ('c, 'd) ℐ"
    and ℐ_common :: "security β‡’ ('e, 'f) ℐ"
    and bound :: "security β‡’ enat"
    and lossless :: "bool"
  assumes WT_real [WT_intro]: "β‹€Ξ·. ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒res real_resource Ξ· √"
    and WT_ideal [WT_intro]: "β‹€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒res ideal_resource Ξ· √"
    and WT_sim [WT_intro]: "β‹€Ξ·. ℐ_real Ξ·, ℐ_ideal Ξ· ⊒C sim Ξ· √"
    and adv: "β‹€π’œ :: security β‡’ ('a + 'e, 'b + 'f) distinguisher. 
    ⟦ β‹€Ξ·. ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’œ Ξ· √; 
      β‹€Ξ·. interaction_bounded_by (Ξ»_. True) (π’œ Ξ·) (bound Ξ·);
      β‹€Ξ·. lossless ⟹ plossless_gpv (ℐ_real Ξ· βŠ•β„ ℐ_common Ξ·) (π’œ Ξ·) ⟧
    ⟹ negligible (λη. advantage (π’œ Ξ·) (sim Ξ· |= 1C ⊳ ideal_resource Ξ·) (real_resource Ξ·))"


locale constructive_security =
  constructive_security_aux real_resource ideal_resource sim ℐ_real ℐ_ideal ℐ_common bound lossless
  for real_resource :: "security β‡’ ('a + 'e, 'b + 'f) resource"
    and ideal_resource :: "security β‡’ ('c + 'e, 'd + 'f) resource"
    and sim :: "security β‡’ ('a, 'b, 'c, 'd) converter"
    and ℐ_real :: "security β‡’ ('a, 'b) ℐ"
    and ℐ_ideal :: "security β‡’ ('c, 'd) ℐ"
    and ℐ_common :: "security β‡’ ('e, 'f) ℐ"
    and bound :: "security β‡’ enat"
    and lossless :: "bool"
    and w :: "security β‡’ ('c, 'd, 'a, 'b) wiring"
  +
  assumes correct: "βˆƒcnv. βˆ€π’Ÿ :: security β‡’ ('c + 'e, 'd + 'f) distinguisher.
    (βˆ€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √) 
  ⟢ (βˆ€Ξ·. interaction_bounded_by (Ξ»_. True) (π’Ÿ Ξ·) (bound Ξ·))
  ⟢ (βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·))
  ⟢ (βˆ€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)) ∧
       negligible (λη. advantage (π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·))"

locale constructive_security2 =
  constructive_security_aux real_resource ideal_resource sim ℐ_real ℐ_ideal ℐ_common bound lossless
  for real_resource :: "security β‡’ ('a + 'e, 'b + 'f) resource"
    and ideal_resource :: "security β‡’ ('c + 'e, 'd + 'f) resource"
    and sim :: "security β‡’ ('a, 'b, 'c, 'd) converter"
    and ℐ_real :: "security β‡’ ('a, 'b) ℐ"
    and ℐ_ideal :: "security β‡’ ('c, 'd) ℐ"
    and ℐ_common :: "security β‡’ ('e, 'f) ℐ"
    and bound :: "security β‡’ enat"
    and lossless :: "bool"
    and w :: "security β‡’ ('c, 'd, 'a, 'b) wiring"
  +
  assumes sim: "βˆƒcnv. βˆ€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·) ∧ wiring (ℐ_ideal Ξ·) (ℐ_ideal Ξ·) (cnv Ξ· βŠ™ sim Ξ·) (id, id)"
begin

lemma constructive_security:
  "constructive_security real_resource ideal_resource sim ℐ_real ℐ_ideal ℐ_common bound lossless w"
proof
  from sim obtain cnv
    where w: "β‹€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)"
      and inverse: "β‹€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_ideal Ξ·) (cnv Ξ· βŠ™ sim Ξ·) (id, id)"
    by blast
  show "βˆƒcnv. βˆ€π’Ÿ. (βˆ€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √)
    ⟢ (βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound Ξ·))
    ⟢ (βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·))
    ⟢ (βˆ€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)) ∧
        negligible (λη. advantage (π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·))"
  proof(intro strip exI conjI)
    fix π’Ÿ :: "security β‡’ ('c + 'e, 'd + 'f) distinguisher"
    assume WT_D [rule_format, WT_intro]: "βˆ€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √"
      and bound [rule_format, interaction_bound]: "βˆ€Ξ·. interaction_bounded_by (Ξ»_. True) (π’Ÿ Ξ·) (bound Ξ·)"
      and lossless [rule_format]: "βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·)"
    
    show "wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)" for Ξ· by fact

    let ?A = "λη. outs_ℐ (ℐ_ideal Ξ·)"
    let ?cnv = "λη. restrict_converter (?A Ξ·) (ℐ_real Ξ·) (cnv Ξ·)"
    let ?π’œ = "λη. absorb (π’Ÿ Ξ·) (?cnv Ξ· |= 1C)"

    have eq: "advantage (π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·) =
    advantage (?π’œ Ξ·) (sim Ξ· |= 1C ⊳ ideal_resource Ξ·) (real_resource Ξ·)" for Ξ·
    proof -
      from w[of Ξ·] have [WT_intro]: "ℐ_ideal Ξ·, ℐ_real Ξ· ⊒C cnv Ξ· √" by cases
      have "ℐ_ideal Ξ·, ℐ_ideal Ξ· ⊒C ?cnv Ξ· βŠ™ sim Ξ· ∼ cnv Ξ· βŠ™ sim Ξ·"
        by(rule eq_ℐ_comp_cong eq_ℐ_restrict_converter WT_intro order_refl eq_ℐ_converter_reflI)+
      also from inverse[of Ξ·] have "ℐ_ideal Ξ·, ℐ_ideal Ξ· ⊒C cnv Ξ· βŠ™ sim Ξ· ∼ 1C" by cases simp
      finally have inverse': "ℐ_ideal Ξ·, ℐ_ideal Ξ· ⊒C ?cnv Ξ· βŠ™ sim Ξ· ∼ 1C" .
      hence "ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·, ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒C ?cnv Ξ· βŠ™ sim Ξ· |= 1C ∼ 1C |= 1C"
        by(rule parallel_converter2_eq_ℐ_cong)(intro eq_ℐ_converter_reflI WT_intro)
      also have "ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·, ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒C 1C |= 1C ∼ 1C"
        by(rule parallel_converter2_id_id)
      also
      have eq1: "connect (π’Ÿ Ξ·) (?cnv Ξ· |= 1C ⊳ sim Ξ· |= 1C ⊳ ideal_resource Ξ·) = 
        connect (π’Ÿ Ξ·) (1C ⊳ ideal_resource Ξ·)"
        unfolding attach_compose[symmetric] comp_converter_parallel2 comp_converter_id_right
        by(rule connect_eq_resource_cong WT_intro eq_ℐ_attach_on' calculation)+(fastforce intro: WT_intro)+

      have *: "ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·, ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒C ?cnv Ξ· |= 1C ∼ cnv Ξ· |= 1C"
        by(rule parallel_converter2_eq_ℐ_cong eq_ℐ_restrict_converter)+(auto intro: WT_intro eq_ℐ_converter_reflI)
      have eq2: "connect (π’Ÿ Ξ·) (?cnv Ξ· |= 1C ⊳ real_resource Ξ·) = connect (π’Ÿ Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·)"
        by(rule connect_eq_resource_cong WT_intro eq_ℐ_attach_on' *)+(auto intro: WT_intro)
      show ?thesis unfolding advantage_def by(simp add: distinguish_attach[symmetric] eq1 eq2)
    qed
    have "ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒g ?π’œ Ξ· √" for Ξ·
    proof -
      from w have [WT_intro]: "ℐ_ideal Ξ·, ℐ_real Ξ· ⊒C cnv Ξ· √" by cases
      show ?thesis by(rule WT_intro)+
    qed
    moreover
    have "interaction_any_bounded_by (absorb (π’Ÿ Ξ·) (?cnv Ξ· |= 1C)) (bound Ξ·)" for Ξ·
    proof -
      from w[of Ξ·] obtain f g where [simp]: "w Ξ· = (f, g)"
        and [WT_intro]: "ℐ_ideal Ξ·, ℐ_real Ξ· ⊒C cnv Ξ· √"
        and eq: "ℐ_ideal Ξ·, ℐ_real Ξ· ⊒C cnv Ξ· ∼ map_converter id id f g 1C" by cases
      from eq_ℐ_restrict_converter_cong[OF eq order_refl]
      have *: "restrict_converter (?A Ξ·) (ℐ_real Ξ·) (cnv Ξ·) =
      restrict_converter (?A Ξ·) (ℐ_real Ξ·) (map_converter f g id id 1C)"
        by(subst map_converter_id_move_right) simp
      show ?thesis unfolding * by interaction_bound_converter simp
    qed
    moreover have "plossless_gpv (ℐ_real Ξ· βŠ•β„ ℐ_common Ξ·) (?π’œ Ξ·)"
      if "lossless" for Ξ· 
    proof -
      from w[of Ξ·] obtain f g where [simp]: "w Ξ· = (f, g)"
        and cnv [WT_intro]: "ℐ_ideal Ξ·, ℐ_real Ξ· ⊒C cnv Ξ· √"
        and eq: "ℐ_ideal Ξ·, ℐ_real Ξ· ⊒C cnv Ξ· ∼ map_converter id id f g 1C" by cases
      from eq_ℐ_converterD_WT1[OF eq cnv] have ℐ: "ℐ_ideal Ξ· ≀ map_ℐ f g (ℐ_real Ξ·)"
        by(rule WT_map_converter_idD)
      with WT_converter_id have [WT_intro]: "ℐ_ideal Ξ·, map_ℐ f g (ℐ_real Ξ·) ⊒C 1C √" 
        by(rule WT_converter_mono) simp
      have id: "plossless_converter (ℐ_ideal Ξ·) (map_ℐ f g (ℐ_real Ξ·)) 1C"
        by(rule plossless_converter_mono)(rule plossless_id_converter order_refl ℐ WT_intro)+
      show ?thesis unfolding eq_ℐ_restrict_converter_cong[OF eq order_refl]
        by(rule plossless_gpv_absorb lossless[OF that] plossless_parallel_converter2 plossless_restrict_converter plossless_map_converter)+
          (fastforce intro: WT_intro id WT_converter_map_converter)+
    qed
    ultimately show "negligible (λη. advantage (π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·))"
      unfolding eq by(rule adv)
  qed
qed

sublocale constructive_security real_resource ideal_resource sim ℐ_real ℐ_ideal ℐ_common bound lossless w
  by(rule constructive_security)

end

subsection β€ΉComposition theoremsβ€Ί

theorem composability:
  fixes real
  assumes "constructive_security middle ideal sim_inner ℐ_middle ℐ_inner ℐ_common bound_inner lossless_inner w1"
  assumes "constructive_security real middle sim_outer ℐ_real ℐ_middle ℐ_common bound_outer lossless_outer w2"
  and bound [interaction_bound]: "β‹€Ξ·. interaction_any_bounded_converter (sim_outer Ξ·) (bound_sim Ξ·)"
  and bound_le: "β‹€Ξ·. bound_outer Ξ· * max (bound_sim Ξ·) 1 ≀ bound_inner Ξ·"
  and lossless_sim [plossless_intro]: "β‹€Ξ·. lossless_inner ⟹ plossless_converter (ℐ_real Ξ·) (ℐ_middle Ξ·) (sim_outer Ξ·)"
  shows "constructive_security real ideal (λη. sim_outer Ξ· βŠ™ sim_inner Ξ·) ℐ_real ℐ_inner ℐ_common bound_outer (lossless_outer ∨ lossless_inner) (λη. w1 Ξ· ∘w w2 Ξ·)"
proof
  interpret inner: constructive_security middle ideal sim_inner ℐ_middle ℐ_inner ℐ_common bound_inner lossless_inner w1 by fact
  interpret outer: constructive_security real middle sim_outer ℐ_real ℐ_middle ℐ_common bound_outer lossless_outer w2 by fact

  show "ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒res real Ξ· √"
    and "ℐ_inner Ξ· βŠ•β„ ℐ_common Ξ· ⊒res ideal Ξ· √"
    and "ℐ_real Ξ·, ℐ_inner Ξ· ⊒C sim_outer Ξ· βŠ™ sim_inner Ξ· √" for Ξ· by(rule WT_intro)+

  { fix π’œ :: "security β‡’ ('g + 'b, 'h + 'd) distinguisher"
    assume WT [WT_intro]: "ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’œ Ξ· √" for Ξ·
    assume bound_outer [interaction_bound]: "interaction_bounded_by (Ξ»_. True) (π’œ Ξ·) (bound_outer Ξ·)" for Ξ·
    assume lossless [plossless_intro]:
      "lossless_outer ∨ lossless_inner ⟹ plossless_gpv (ℐ_real Ξ· βŠ•β„ ℐ_common Ξ·) (π’œ Ξ·)" for Ξ·

    let ?π’œ = "λη. absorb (π’œ Ξ·) (sim_outer Ξ· |= 1C)"
    have "ℐ_middle Ξ· βŠ•β„ ℐ_common Ξ· ⊒g ?π’œ Ξ· √" for Ξ· by(rule WT_intro)+
    moreover have "interaction_any_bounded_by (?π’œ Ξ·) (bound_inner Ξ·)" for Ξ·
      by interaction_bound_converter(rule bound_le)
    moreover have "plossless_gpv (ℐ_middle Ξ· βŠ•β„ ℐ_common Ξ·) (?π’œ Ξ·)" if lossless_inner for Ξ·
      by(rule plossless_intro WT_intro | simp add: that)+
    ultimately have "negligible (λη. advantage (?π’œ Ξ·) (sim_inner Ξ· |= 1C ⊳ ideal Ξ·) (middle Ξ·))"
      by(rule inner.adv)
    also have "negligible (λη. advantage (π’œ Ξ·) (sim_outer Ξ· |= 1C ⊳ middle Ξ·) (real Ξ·))"
      by(rule outer.adv[OF WT bound_outer lossless]) simp
    finally (negligible_plus)
    show "negligible (λη. advantage (π’œ Ξ·) (sim_outer Ξ· βŠ™ sim_inner Ξ· |= 1C ⊳ ideal Ξ·) (real Ξ·))"
      apply(rule negligible_mono)
      apply(simp add: bigo_def)
      apply(rule exI[where x=1])
      apply simp
      apply(rule always_eventually)
      apply(clarsimp simp add: advantage_def)
      apply(rule order_trans)
       apply(rule abs_diff_triangle_ineq2)
      apply(rule add_right_mono)
      apply(clarsimp simp add: advantage_def distinguish_attach[symmetric] attach_compose[symmetric] comp_converter_parallel2 comp_converter_id_left)
      done
  next
    from inner.correct obtain cnv_inner
      where correct_inner: "β‹€π’Ÿ. ⟦ β‹€Ξ·. ℐ_inner Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √;
             β‹€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound_inner Ξ·);
             β‹€Ξ·. lossless_inner ⟹ plossless_gpv (ℐ_inner Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·) ⟧
           ⟹ (βˆ€Ξ·. wiring (ℐ_inner Ξ·) (ℐ_middle Ξ·) (cnv_inner Ξ·) (w1 Ξ·)) ∧
               negligible (λη. advantage (π’Ÿ Ξ·) (ideal Ξ·) (cnv_inner Ξ· |= 1C ⊳ middle Ξ·))"
      by blast
    from outer.correct obtain cnv_outer
      where correct_outer: "β‹€π’Ÿ. ⟦ β‹€Ξ·. ℐ_middle Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √;
             β‹€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound_outer Ξ·);
             β‹€Ξ·. lossless_outer ⟹ plossless_gpv (ℐ_middle Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·) ⟧
           ⟹ (βˆ€Ξ·. wiring (ℐ_middle Ξ·) (ℐ_real Ξ·) (cnv_outer Ξ·) (w2 Ξ·)) ∧
               negligible (λη. advantage (π’Ÿ Ξ·) (middle Ξ·) (cnv_outer Ξ· |= 1C ⊳ real Ξ·))"
      by blast
    show "βˆƒcnv. βˆ€π’Ÿ. (βˆ€Ξ·. ℐ_inner Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √) ⟢
               (βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound_outer Ξ·)) ⟢
               (βˆ€Ξ·. lossless_outer ∨ lossless_inner ⟢ plossless_gpv (ℐ_inner Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·)) ⟢
               (βˆ€Ξ·. wiring (ℐ_inner Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w1 Ξ· ∘w w2 Ξ·)) ∧
               negligible (λη. advantage (π’Ÿ Ξ·) (ideal Ξ·) (cnv Ξ· |= 1C ⊳ real Ξ·))"
    proof(intro exI strip conjI)
      fix π’Ÿ :: "security β‡’ ('e + 'b, 'f + 'd) distinguisher"
      assume WT_D [rule_format, WT_intro]: "βˆ€Ξ·. ℐ_inner Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √"
        and bound [rule_format, interaction_bound]: "βˆ€Ξ·. interaction_bounded_by (Ξ»_. True) (π’Ÿ Ξ·) (bound_outer Ξ·)"
        and lossless [rule_format]: "βˆ€Ξ·. lossless_outer ∨ lossless_inner ⟢ plossless_gpv (ℐ_inner Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·)"

      let ?cnv = "λη. cnv_inner Ξ· βŠ™ cnv_outer Ξ·"

      have bound': "interaction_any_bounded_by (π’Ÿ Ξ·) (bound_inner Ξ·)" for Ξ· using bound[of Ξ·] bound_le[of Ξ·]
        by(clarsimp elim!: interaction_bounded_by_mono order_trans[rotated] simp add: max_def)
          (metis (full_types) linorder_linear more_arith_simps(6) mult_left_mono zero_le)
      from correct_inner[OF WT_D bound' lossless]
      have w1: "β‹€Ξ·. wiring (ℐ_inner Ξ·) (ℐ_middle Ξ·) (cnv_inner Ξ·) (w1 Ξ·)"
        and adv1: "negligible (λη. advantage (π’Ÿ Ξ·) (ideal Ξ·) (cnv_inner Ξ· |= 1C ⊳ middle Ξ·))"
        by auto

      obtain f g where WT_inner [WT_intro]: "β‹€Ξ·. ℐ_inner Ξ·, ℐ_middle Ξ· ⊒C cnv_inner Ξ· √"
        and fg [simp]: "β‹€Ξ·. w1 Ξ· = (f Ξ·, g Ξ·)"
        and eq1: "β‹€Ξ·. ℐ_inner Ξ·, ℐ_middle Ξ· ⊒C cnv_inner Ξ· ∼ map_converter id id (f Ξ·) (g Ξ·) 1C"
        using w1
        apply(atomize_elim)
        apply(fold all_conj_distrib)
        apply(subst choice_iff[symmetric])+
        apply(fastforce elim!: wiring.cases)
        done

      from w1 have [WT_intro]: "ℐ_inner Ξ·, ℐ_middle Ξ· ⊒C cnv_inner Ξ· √" for Ξ· by cases

      let ?π’Ÿ = "λη. absorb (π’Ÿ Ξ·) (map_converter id id (f Ξ·) (g Ξ·) 1C |= 1C)"
      have ℐ: "ℐ_inner Ξ· ≀ map_ℐ (f Ξ·) (g Ξ·) (ℐ_middle Ξ·)" for Ξ·
        using eq_ℐ_converterD_WT1[OF eq1 WT_inner, of Ξ·] by(rule WT_map_converter_idD)
      with WT_converter_id have [WT_intro]: "ℐ_inner Ξ·, map_ℐ (f Ξ·) (g Ξ·) (ℐ_middle Ξ·) ⊒C 1C √" 
        for Ξ· by(rule WT_converter_mono) simp

      have WT_D': "ℐ_middle Ξ· βŠ•β„ ℐ_common Ξ· ⊒g ?π’Ÿ Ξ· √" for Ξ· by(rule WT_intro | simp)+
      have bound': "interaction_any_bounded_by (?π’Ÿ Ξ·) (bound_outer Ξ·)" for Ξ·
        by(subst map_converter_id_move_left)(interaction_bound; simp)
      have [simp]: "plossless_converter (ℐ_inner Ξ·) (map_ℐ (f Ξ·) (g Ξ·) (ℐ_middle Ξ·)) 1C " for Ξ·
        using plossless_id_converter _ ℐ[of Ξ·] by(rule plossless_converter_mono) auto
      from lossless
      have "plossless_gpv (ℐ_middle Ξ· βŠ•β„ ℐ_common Ξ·) (?π’Ÿ Ξ·)" if lossless_outer for Ξ·
        by(rule plossless_gpv_absorb)(auto simp add: that intro!: WT_intro plossless_parallel_converter2 plossless_map_converter)
      from correct_outer[OF WT_D' bound' this]
      have w2: "β‹€Ξ·. wiring (ℐ_middle Ξ·) (ℐ_real Ξ·) (cnv_outer Ξ·) (w2 Ξ·)"
        and adv2: "negligible (λη. advantage (?π’Ÿ Ξ·) (middle Ξ·) (cnv_outer Ξ· |= 1C ⊳ real Ξ·))"
        by auto
      from w2 have [WT_intro]: "ℐ_middle Ξ·, ℐ_real Ξ· ⊒C cnv_outer Ξ· √" for Ξ· by cases

      show "wiring (ℐ_inner Ξ·) (ℐ_real Ξ·) (?cnv Ξ·) (w1 Ξ· ∘w w2 Ξ·)" for Ξ·
        using w1 w2 by(rule wiring_comp_converterI)

      have eq1': "connect (π’Ÿ Ξ·) (cnv_inner Ξ· |= 1C ⊳ middle Ξ·) = connect (?π’Ÿ Ξ·) (middle Ξ·)" for Ξ·
        unfolding distinguish_attach[symmetric]
        by(rule connect_eq_resource_cong WT_intro eq_ℐ_attach_on' parallel_converter2_eq_ℐ_cong eq1 eq_ℐ_converter_reflI order_refl)+
      have eq2': "connect (?π’Ÿ Ξ·) (cnv_outer Ξ· |= 1C ⊳ real Ξ·) = connect (π’Ÿ Ξ·) (?cnv Ξ· |= 1C βŠ™ 1C ⊳ real Ξ·)" for Ξ·
        unfolding distinguish_attach[symmetric] attach_compose comp_converter_parallel2[symmetric]
        by(rule connect_eq_resource_cong WT_intro eq_ℐ_attach_on' parallel_converter2_eq_ℐ_cong eq1[symmetric] eq_ℐ_converter_reflI order_refl|simp)+

      show "negligible (λη. advantage (π’Ÿ Ξ·) (ideal Ξ·) (?cnv Ξ· |= 1C ⊳ real Ξ·))"
        using negligible_plus[OF adv1 adv2] unfolding advantage_def eq1' eq2' comp_converter_id_right
        by(rule negligible_le) simp
    qed
  }
qed

theorem (in constructive_security) lifting:
  assumes WT_conv [WT_intro]: "β‹€Ξ·. ℐ_common' Ξ·, ℐ_common Ξ· ⊒C conv Ξ· √"
    and bound [interaction_bound]: "β‹€Ξ·. interaction_any_bounded_converter (conv Ξ·) (bound_conv Ξ·)"
    and bound_le: "β‹€Ξ·. bound' Ξ· * max (bound_conv Ξ·) 1 ≀ bound Ξ·"
    and lossless [plossless_intro]: "β‹€Ξ·. lossless ⟹ plossless_converter (ℐ_common' Ξ·) (ℐ_common Ξ·) (conv Ξ·)"
  shows "constructive_security
     (λη. 1C |= conv η ⊳ real_resource η) (λη. 1C |= conv η ⊳ ideal_resource η) sim
     ℐ_real ℐ_ideal ℐ_common' bound' lossless w"
proof
  fix π’œ :: "security β‡’ ('a + 'g, 'b + 'h) distinguisher"
  assume WT_π’œ [WT_intro]: "ℐ_real Ξ· βŠ•β„ ℐ_common' Ξ· ⊒g π’œ Ξ· √" for Ξ·
  assume bound_π’œ [interaction_bound]: "interaction_any_bounded_by (π’œ Ξ·) (bound' Ξ·)" for Ξ·
  assume lossless_π’œ [plossless_intro]: "lossless ⟹ plossless_gpv (ℐ_real Ξ· βŠ•β„ ℐ_common' Ξ·) (π’œ Ξ·)" for Ξ·

  let ?π’œ = "λη. absorb (π’œ Ξ·) (1C |= conv Ξ·)"

  have ideal: "connect (π’œ Ξ·) (sim Ξ· |= 1C ⊳ 1C |= conv Ξ· ⊳ ideal_resource Ξ·) = connect (?π’œ Ξ·) (sim Ξ· |= 1C ⊳ ideal_resource Ξ·)" for Ξ·
    by(simp add: distinguish_attach[symmetric] attach_compose[symmetric] comp_converter_parallel2 comp_converter_id_left comp_converter_id_right)
  have real: "connect (π’œ Ξ·) (1C |= conv Ξ· ⊳ real_resource Ξ·) = connect (?π’œ Ξ·) (real_resource Ξ·)" for Ξ·
    by(simp add: distinguish_attach[symmetric])
  have "ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒g ?π’œ Ξ· √" for Ξ· by(rule WT_intro)+
  moreover have "interaction_any_bounded_by (?π’œ Ξ·) (bound Ξ·)" for Ξ·
    by interaction_bound_converter(use bound_le[of Ξ·] in β€Ήsimp add: max.commuteβ€Ί)
  moreover have " plossless_gpv (ℐ_real Ξ· βŠ•β„ ℐ_common Ξ·) (absorb (π’œ Ξ·) (1C |= conv Ξ·))" if lossless for Ξ·
    by(rule plossless_intro WT_intro | simp add: that)+
  ultimately show "negligible (λη. advantage (π’œ Ξ·) (sim Ξ· |= 1C ⊳ 1C |= conv Ξ· ⊳ ideal_resource Ξ·) (1C |= conv Ξ· ⊳ real_resource Ξ·))"
    unfolding advantage_def ideal real by(rule adv[unfolded advantage_def])
next
  from correct obtain cnv 
    where correct': "β‹€π’Ÿ. ⟦ β‹€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √;
          β‹€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound Ξ·);
          β‹€Ξ·. lossless ⟹ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·) ⟧
          ⟹ (βˆ€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)) ∧
              negligible (λη. advantage (π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·))"
    by blast
  show "βˆƒcnv. βˆ€π’Ÿ. (βˆ€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common' Ξ· ⊒g π’Ÿ Ξ· √) ⟢
         (βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound' Ξ·)) ⟢
         (βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common' Ξ·) (π’Ÿ Ξ·)) ⟢
         (βˆ€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)) ∧
         negligible (λη. advantage (π’Ÿ Ξ·) (1C |= conv Ξ· ⊳ ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ 1C |= conv Ξ· ⊳ real_resource Ξ·))"
  proof(intro exI conjI strip)
    fix π’Ÿ :: "security β‡’ ('c + 'g, 'd + 'h) distinguisher"
    assume WT_D [rule_format, WT_intro]: "βˆ€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common' Ξ· ⊒g π’Ÿ Ξ· √"
      and bound [rule_format, interaction_bound]: "βˆ€Ξ·. interaction_bounded_by (Ξ»_. True) (π’Ÿ Ξ·) (bound' Ξ·)"
      and lossless [rule_format]: "βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common' Ξ·) (π’Ÿ Ξ·)"

    let ?π’Ÿ = "λη. absorb (π’Ÿ Ξ·) (1C |= conv Ξ·)"
    have WT_D' [WT_intro]: "ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒g ?π’Ÿ Ξ· √" for Ξ· by(rule WT_intro)+
    have bound': "interaction_any_bounded_by (?π’Ÿ Ξ·) (bound Ξ·)" for Ξ·
      by interaction_bound(use bound_le[of Ξ·] in β€Ήauto simp add: max_def split: if_split_asmβ€Ί)
    have "plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·) (?π’Ÿ Ξ·)" if lossless for Ξ·
      by(rule lossless that WT_intro plossless_intro)+
    from correct'[OF WT_D' bound' this]
    have w1: "wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)" 
      and adv': "negligible (λη. advantage (?π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·))" for Ξ·
      by auto
    show "wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)" for Ξ· by(rule w1)
    have "cnv η |= 1C ⊳ 1C |= conv η ⊳ real_resource η = 1C |= conv η ⊳ cnv η |= 1C ⊳ real_resource η" for η
      by(simp add: attach_compose[symmetric] comp_converter_parallel2 comp_converter_id_left comp_converter_id_right)
    with adv'
    show "negligible (λη. advantage (π’Ÿ Ξ·) (1C |= conv Ξ· ⊳ ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ 1C |= conv Ξ· ⊳ real_resource Ξ·))"
      by(simp add: advantage_def distinguish_attach[symmetric])
  qed
qed(rule WT_intro)+

theorem constructive_security_trivial:
  fixes res
  assumes [WT_intro]: "β‹€Ξ·. ℐ Ξ· βŠ•β„ ℐ_common Ξ· ⊒res res Ξ· √"
  shows "constructive_security res res (Ξ»_. 1C) ℐ ℐ ℐ_common bound lossless (Ξ»_. (id, id))"
proof
  show "ℐ Ξ· βŠ•β„ ℐ_common Ξ· ⊒res res Ξ· √" and "ℐ Ξ·, ℐ Ξ· ⊒C 1C √" for Ξ· by(rule WT_intro)+

  fix π’œ :: "security β‡’ ('a + 'b, 'c + 'd) distinguisher"
  assume WT [WT_intro]: "ℐ Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’œ Ξ· √" for Ξ·
  have "connect (π’œ Ξ·) (1C |= 1C ⊳ res Ξ·) = connect (π’œ Ξ·) (1C ⊳ res Ξ·)" for Ξ·
    by(rule connect_eq_resource_cong[OF WT])(fastforce intro: WT_intro eq_ℐ_attach_on' parallel_converter2_id_id)+
  then show "negligible (λη. advantage (π’œ Ξ·) (1C |= 1C ⊳ res Ξ·) (res Ξ·))"
    unfolding advantage_def by simp
next
  show "βˆƒcnv. βˆ€π’Ÿ. (βˆ€Ξ·. ℐ Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √) ⟢
         (βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound Ξ·)) ⟢
         (βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·)) ⟢
         (βˆ€Ξ·. wiring (ℐ Ξ·) (ℐ Ξ·) (cnv Ξ·) (id, id)) ∧
         negligible (λη. advantage (π’Ÿ Ξ·) (res Ξ·) (cnv Ξ· |= 1C ⊳ res Ξ·))"
  proof(intro exI strip conjI)
    fix π’Ÿ :: "security β‡’ ('a + 'b, 'c + 'd) distinguisher"
    assume WT_D [rule_format, WT_intro]: "βˆ€Ξ·. ℐ Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √"
      and bound [rule_format, interaction_bound]: "βˆ€Ξ·. interaction_bounded_by (Ξ»_. True) (π’Ÿ Ξ·) (bound Ξ·)"
      and lossless [rule_format]: "βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·)"
    show "wiring (ℐ Ξ·) (ℐ Ξ·) 1C (id, id)" for Ξ· by simp
    have "connect (π’Ÿ Ξ·) (1C |= 1C ⊳ res Ξ·) = connect (π’Ÿ Ξ·) (1C ⊳ res Ξ·)" for Ξ·
      by(rule connect_eq_resource_cong)(rule WT_intro eq_ℐ_attach_on' parallel_converter2_id_id order_refl)+
    then show "negligible (λη. advantage (π’Ÿ Ξ·) (res Ξ·) (1C |= 1C ⊳ res Ξ·))"
      by(auto simp add: advantage_def)
  qed
qed

theorem parallel_constructive_security:
  assumes "constructive_security real1 ideal1 sim1 ℐ_real1 ℐ_inner1 ℐ_common1 bound1 lossless1 w1"
  assumes "constructive_security real2 ideal2 sim2 ℐ_real2 ℐ_inner2 ℐ_common2 bound2 lossless2 w2"
    (* TODO: add symmetric case for lossless1/2 *)
    and lossless_real1 [plossless_intro]: "β‹€Ξ·. lossless2 ⟹ lossless_resource (ℐ_real1 Ξ· βŠ•β„ ℐ_common1 Ξ·) (real1 Ξ·)"
    and lossless_sim2 [plossless_intro]: "β‹€Ξ·. lossless1 ⟹ plossless_converter (ℐ_real2 Ξ·) (ℐ_inner2 Ξ·) (sim2 Ξ·)"
    and lossless_ideal2 [plossless_intro]: "β‹€Ξ·. lossless1 ⟹ lossless_resource (ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ·) (ideal2 Ξ·)"
  shows "constructive_security (λη. parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·) (λη. parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ·) (λη. sim1 Ξ· |= sim2 Ξ·) 
    (λη. ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) (λη. ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) (λη. ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)
    (λη. min (bound1 η) (bound2 η)) (lossless1 ∨ lossless2) (λη. w1 η |w w2 η)"
proof
  interpret sec1: constructive_security real1 ideal1 sim1 ℐ_real1 ℐ_inner1 ℐ_common1 bound1 lossless1 w1 by fact
  interpret sec2: constructive_security real2 ideal2 sim2 ℐ_real2 ℐ_inner2 ℐ_common2 bound2 lossless2 w2 by fact

  show "(ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒res parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ· √"
    and "(ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒res parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ· √"
    and "ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·, ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ· ⊒C sim1 Ξ· |= sim2 Ξ· √" for Ξ· by(rule WT_intro)+

  fix π’œ :: "security β‡’ (('a + 'g) + 'b + 'h, ('c + 'i) + 'd + 'j) distinguisher"
  assume WT [WT_intro]: "(ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒g π’œ Ξ· √" for Ξ·
  assume bound [interaction_bound]: "interaction_any_bounded_by (π’œ Ξ·) (min (bound1 Ξ·) (bound2 Ξ·))" for Ξ·
  assume lossless [plossless_intro]: "lossless1 ∨ lossless2 ⟹ plossless_gpv ((ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)) (π’œ Ξ·)" for Ξ·

  let ?π’œ = "λη. absorb (π’œ Ξ·) (parallel_wiring βŠ™ parallel_converter (converter_of_resource (real1 Ξ·)) 1C)"

  have *:"ℐ_uniform (outs_ℐ ((ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)))
     UNIV,(ℐ_real1 Ξ· βŠ•β„ ℐ_common1 Ξ·) βŠ•β„ (ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒C
    ((1C |= sim2 Ξ·) |= 1C) βŠ™ parallel_wiring ∼ ((1C |= sim2 Ξ·) |= 1C |= 1C) βŠ™ parallel_wiring" for Ξ·
    by(rule eq_ℐ_comp_cong, rule eq_ℐ_converter_mono)
      (auto simp add: le_ℐ_def intro: parallel_converter2_eq_ℐ_cong eq_ℐ_converter_reflI WT_converter_parallel_converter2
        WT_converter_id sec2.WT_sim parallel_converter2_id_id[symmetric] eq_ℐ_converter_reflI WT_parallel_wiring)

  have **: "outs_ℐ ((ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)) ⊒R
    ((1C |= sim2 Ξ·) |= 1C |= 1C) βŠ™ parallel_wiring ⊳ real1 Ξ· βˆ₯ ideal2 Ξ· ∼
    parallel_wiring βŠ™ (converter_of_resource (real1 Ξ·) |∝ 1C) ⊳ sim2 Ξ· |= 1C ⊳ ideal2 Ξ·" for Ξ·
    unfolding comp_parallel_wiring
    by(rule eq_resource_on_trans, rule eq_ℐ_attach_on[where conv'="parallel_wiring βŠ™ (1C |= sim2 Ξ· |= 1C)"]
        , (rule WT_intro)+, rule eq_ℐ_comp_cong, rule eq_ℐ_converter_mono)
      (auto simp add: le_ℐ_def attach_compose attach_parallel2 attach_converter_of_resource_conv_parallel_resource
        intro: WT_intro parallel_converter2_eq_ℐ_cong parallel_converter2_id_id eq_ℐ_converter_reflI)

  have ideal2:
    "connect (π’œ Ξ·) ((1C |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ ideal2 Ξ·) =
     connect (?π’œ Ξ·) (sim2 Ξ· |= 1C ⊳ ideal2 Ξ·)" for Ξ·
    unfolding distinguish_attach[symmetric]
  proof (rule connect_eq_resource_cong[OF WT, rotated], goal_cases)
    case 2
    then show ?case 
      by(subst attach_compose[symmetric], rule eq_resource_on_trans
          , rule eq_ℐ_attach_on[where conv'="((1C |= sim2 Ξ·) |= 1C |= 1C) βŠ™ parallel_wiring"])
        ((rule WT_intro)+ | intro * | intro ** )+
  qed (rule WT_intro)+
  have real2: "connect (π’œ Ξ·) (parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·) = connect (?π’œ Ξ·) (real2 Ξ·)" for Ξ·
    unfolding distinguish_attach[symmetric]
    by(simp add: attach_compose attach_converter_of_resource_conv_parallel_resource)
  have "ℐ_real2 Ξ· βŠ•β„ ℐ_common2 Ξ· ⊒g ?π’œ Ξ· √" for Ξ· by(rule WT_intro)+
  moreover have "interaction_any_bounded_by (?π’œ Ξ·) (bound2 Ξ·)" for Ξ·
    by interaction_bound_converter simp
  moreover have "plossless_gpv (ℐ_real2 Ξ· βŠ•β„ ℐ_common2 Ξ·) (?π’œ Ξ·)" if "lossless2" for Ξ· 
    by(rule plossless_intro WT_intro | simp add: that)+
  ultimately
  have negl2: "negligible (λη. advantage (π’œ Ξ·)
     ((1C |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ ideal2 Ξ·)
     (parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·))"
    unfolding advantage_def ideal2 real2 by(rule sec2.adv[unfolded advantage_def])

  let ?π’œ = "λη. absorb (π’œ Ξ·) (parallel_wiring βŠ™ parallel_converter 1C (converter_of_resource (sim2 Ξ· |= 1C ⊳ ideal2 Ξ·)))"
  have ideal1: 
    "connect (π’œ Ξ·) ((sim1 Ξ· |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ·) =
     connect (?π’œ Ξ·) (sim1 Ξ· |= 1C ⊳ ideal1 Ξ·)" for Ξ·
  proof -
    have *: "ℐ_uniform ((outs_ℐ (ℐ_real1 Ξ·) <+> outs_ℐ (ℐ_real2 Ξ·)) <+>  outs_ℐ (ℐ_common1 Ξ·) <+> 
      outs_ℐ (ℐ_common2 Ξ·)) UNIV,(ℐ_inner1 Ξ· βŠ•β„ ℐ_common1 Ξ·) βŠ•β„ (ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒C
    ((sim1 Ξ· |= sim2 Ξ·) |= 1C) βŠ™ parallel_wiring ∼ ((sim1 Ξ· |= sim2 Ξ·) |= 1C |= 1C) βŠ™ parallel_wiring"
      by(rule eq_ℐ_comp_cong, rule eq_ℐ_converter_mono)
        (auto simp add: le_ℐ_def comp_parallel_wiring' attach_compose attach_parallel2 attach_converter_of_resource_conv_parallel_resource2
          intro: WT_intro parallel_converter2_id_id[symmetric] eq_ℐ_converter_reflI parallel_converter2_eq_ℐ_cong eq_ℐ_converter_mono)

    have **:"((outs_ℐ (ℐ_real1 Ξ·) <+> outs_ℐ (ℐ_real2 Ξ·)) <+> outs_ℐ (ℐ_common1 Ξ·) <+> outs_ℐ (ℐ_common2 Ξ·)) ⊒R
    (sim1 Ξ· |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ· ∼
    parallel_wiring βŠ™ (1C |∝ converter_of_resource (sim2 Ξ· |= 1C ⊳ ideal2 Ξ·)) ⊳  sim1 Ξ· |= 1C ⊳ ideal1 Ξ·"
      unfolding attach_compose[symmetric]
      by(rule eq_resource_on_trans, rule eq_ℐ_attach_on[where conv'="((sim1 Ξ· |= sim2 Ξ·) |= 1C |= 1C) βŠ™ parallel_wiring"])
        ((rule WT_intro)+ | intro * | auto simp add: le_ℐ_def comp_parallel_wiring' attach_compose 
          attach_parallel2 attach_converter_of_resource_conv_parallel_resource2 intro: WT_intro *)+

    show ?thesis
      unfolding distinguish_attach[symmetric] using WT
      by(rule connect_eq_resource_cong) (simp add: **, (rule WT_intro)+)
  qed

  have real1:
    "connect (π’œ Ξ·) ((1C |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ ideal2 Ξ·) =
     connect (?π’œ Ξ·) (real1 Ξ·)" for Ξ·
  proof -
    have **: "ℐ_uniform (outs_ℐ ((ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)))
     UNIV,(ℐ_real1 Ξ· βŠ•β„ ℐ_common1 Ξ·) βŠ•β„ (ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒C
      ((1C |= sim2 Ξ·) |= 1C) βŠ™ parallel_wiring ∼ ((1C |= sim2 Ξ·) |= 1C |= 1C) βŠ™ parallel_wiring" 
      by(rule eq_ℐ_comp_cong, rule eq_ℐ_converter_mono)
        (auto simp add: le_ℐ_def intro: WT_intro parallel_converter2_eq_ℐ_cong WT_converter_parallel_converter2
          parallel_converter2_id_id[symmetric] eq_ℐ_converter_reflI WT_parallel_wiring)

    have *: "outs_ℐ ((ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)) ⊒R
    parallel_wiring βŠ™ ((1C |= 1C) |= sim2 Ξ· |= 1C) ⊳ real1 Ξ· βˆ₯ ideal2 Ξ· ∼
    parallel_wiring βŠ™ (1C |∝ converter_of_resource (sim2 Ξ· |= 1C ⊳ ideal2 Ξ·)) ⊳ real1 Ξ·"
      by(rule eq_resource_on_trans, rule eq_ℐ_attach_on[where conv'="parallel_wiring βŠ™ (1C |= sim2 Ξ· |= 1C)"]
          , (rule WT_intro)+, rule eq_ℐ_comp_cong, rule eq_ℐ_converter_mono)
        (auto simp add: le_ℐ_def attach_compose attach_converter_of_resource_conv_parallel_resource2 attach_parallel2 
          intro: WT_intro parallel_converter2_eq_ℐ_cong parallel_converter2_id_id eq_ℐ_converter_reflI)

    show ?thesis
      unfolding distinguish_attach[symmetric] using WT
      by(rule connect_eq_resource_cong, fold attach_compose)
        (rule eq_resource_on_trans[where res'="((1C |= sim2 Ξ·) |= 1C |= 1C) βŠ™ parallel_wiring ⊳ real1 Ξ· βˆ₯ ideal2 Ξ·"]
          , (rule eq_ℐ_attach_on, (intro * ** | subst comp_parallel_wiring | rule eq_ℐ_attach_on | (rule WT_intro eq_ℐ_attach_on)+ )+))
  qed

  have "ℐ_real1 Ξ· βŠ•β„ ℐ_common1 Ξ· ⊒g ?π’œ Ξ· √" for Ξ· by(rule WT_intro)+
  moreover have "interaction_any_bounded_by (?π’œ Ξ·) (bound1 Ξ·)" for Ξ·
    by interaction_bound_converter simp
  moreover have "plossless_gpv (ℐ_real1 Ξ· βŠ•β„ ℐ_common1 Ξ·) (?π’œ Ξ·)" if "lossless1" for Ξ· 
    by(rule plossless_intro WT_intro | simp add: that)+
  ultimately
  have negl1: "negligible (λη. advantage (π’œ Ξ·) 
     ((sim1 Ξ· |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ·)
     ((1C |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ ideal2 Ξ·))"
    unfolding advantage_def ideal1 real1 by(rule sec1.adv[unfolded advantage_def])

  from negligible_plus[OF negl1 negl2]
  show "negligible (λη. advantage (π’œ Ξ·) ((sim1 Ξ· |= sim2 Ξ·) |= 1C ⊳ parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ·)
         (parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·))"
    by(rule negligible_mono) (auto simp add: advantage_def intro!: eventuallyI landau_o.big_mono )
next
  interpret sec1: constructive_security real1 ideal1 sim1 ℐ_real1 ℐ_inner1 ℐ_common1 bound1 lossless1 w1 by fact
  interpret sec2: constructive_security real2 ideal2 sim2 ℐ_real2 ℐ_inner2 ℐ_common2 bound2 lossless2 w2 by fact
  from sec1.correct obtain cnv1
    where correct1: "β‹€π’Ÿ. ⟦ β‹€Ξ·. ℐ_inner1 Ξ· βŠ•β„ ℐ_common1 Ξ· ⊒g π’Ÿ Ξ· √;
      β‹€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound1 Ξ·);
      β‹€Ξ·. lossless1 ⟹ plossless_gpv (ℐ_inner1 Ξ· βŠ•β„ ℐ_common1 Ξ·) (π’Ÿ Ξ·) ⟧
     ⟹ (βˆ€Ξ·. wiring (ℐ_inner1 Ξ·) (ℐ_real1 Ξ·) (cnv1 Ξ·) (w1 Ξ·)) ∧
         negligible (λη. advantage (π’Ÿ Ξ·) (ideal1 Ξ·) (cnv1 Ξ· |= 1C ⊳ real1 Ξ·))"
    by blast
  from sec2.correct obtain cnv2
    where correct2: "β‹€π’Ÿ. ⟦ β‹€Ξ·. ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ· ⊒g π’Ÿ Ξ· √;
      β‹€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound2 Ξ·);
      β‹€Ξ·. lossless2 ⟹ plossless_gpv (ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ·) (π’Ÿ Ξ·) ⟧
     ⟹ (βˆ€Ξ·. wiring (ℐ_inner2 Ξ·) (ℐ_real2 Ξ·) (cnv2 Ξ·) (w2 Ξ·)) ∧
         negligible (λη. advantage (π’Ÿ Ξ·) (ideal2 Ξ·) (cnv2 Ξ· |= 1C ⊳ real2 Ξ·))"
    by blast
  show "βˆƒcnv. βˆ€π’Ÿ. (βˆ€Ξ·. (ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒g π’Ÿ Ξ· √) ⟢
       (βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (min (bound1 Ξ·) (bound2 Ξ·))) ⟢
       (βˆ€Ξ·. lossless1 ∨ lossless2 ⟢ plossless_gpv ((ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)) (π’Ÿ Ξ·)) ⟢
       (βˆ€Ξ·. wiring (ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) (ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) (cnv Ξ·) (w1 Ξ· |w w2 Ξ·)) ∧
       negligible (λη. advantage (π’Ÿ Ξ·) (parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ·) (cnv Ξ· |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·))"
  proof(intro exI strip conjI)
    fix π’Ÿ :: "security β‡’ (('e + 'k) + 'b + 'h, ('f + 'l) + 'd + 'j) distinguisher"
    assume WT_D [rule_format, WT_intro]: "βˆ€Ξ·. (ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·) ⊒g π’Ÿ Ξ· √"
      and bound [rule_format, interaction_bound]: "βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (min (bound1 Ξ·) (bound2 Ξ·))"
      and lossless [rule_format, plossless_intro]: "βˆ€Ξ·. lossless1 ∨ lossless2 ⟢ plossless_gpv ((ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)) (π’Ÿ Ξ·)"

    let ?cnv = "λη. cnv1 η |= cnv2 η"

    let ?π’Ÿ1 = "λη. absorb (π’Ÿ Ξ·) (parallel_wiring βŠ™ parallel_converter 1C (converter_of_resource (ideal2 Ξ·)))"
    have WT1: "ℐ_inner1 Ξ· βŠ•β„ ℐ_common1 Ξ· ⊒g ?π’Ÿ1 Ξ· √" for Ξ· by(rule WT_intro)+
    have bound1: "interaction_any_bounded_by (?π’Ÿ1 Ξ·) (bound1 Ξ·)" for Ξ· by interaction_bound simp
    have "plossless_gpv (ℐ_inner1 Ξ· βŠ•β„ ℐ_common1 Ξ·) (?π’Ÿ1 Ξ·)" if lossless1 for Ξ·
      by(rule plossless_intro WT_intro | simp add: that)+
    from correct1[OF WT1 bound1 this]
    have w1: "wiring (ℐ_inner1 Ξ·) (ℐ_real1 Ξ·) (cnv1 Ξ·) (w1 Ξ·)" 
      and adv1: "negligible (λη. advantage (?π’Ÿ1 Ξ·) (ideal1 Ξ·) (cnv1 Ξ· |= 1C ⊳ real1 Ξ·))" for Ξ·
      by auto

    from w1 obtain f g where fg: "β‹€Ξ·. w1 Ξ· = (f Ξ·, g Ξ·)"
      and [WT_intro]: "β‹€Ξ·. ℐ_inner1 Ξ·, ℐ_real1 Ξ· ⊒C cnv1 Ξ· √" 
      and eq1: "β‹€Ξ·. ℐ_inner1 Ξ·, ℐ_real1 Ξ· ⊒C cnv1 Ξ· ∼ map_converter id id (f Ξ·) (g Ξ·) 1C"
      apply atomize_elim
      apply(fold all_conj_distrib)
      apply(subst choice_iff[symmetric])+
      apply(fastforce elim!: wiring.cases)
      done
    have ℐ1: "ℐ_inner1 Ξ· ≀ map_ℐ (f Ξ·) (g Ξ·) (ℐ_real1 Ξ·)" for Ξ·
      using eq_ℐ_converterD_WT1[OF eq1] by(rule WT_map_converter_idD)(rule WT_intro)
    with WT_converter_id order_refl have [WT_intro]: "ℐ_inner1 Ξ·, map_ℐ (f Ξ·) (g Ξ·) (ℐ_real1 Ξ·) ⊒C 1C √" for Ξ·
      by(rule WT_converter_mono)
    have lossless1 [plossless_intro]: "plossless_converter (ℐ_inner1 Ξ·) (ℐ_real1 Ξ·) (map_converter id id (f Ξ·) (g Ξ·) 1C)" for Ξ·
      by(rule plossless_map_converter)(rule plossless_intro order_refl ℐ1 WT_intro plossless_converter_mono | simp)+

    let ?π’Ÿ2 = "λη. absorb (π’Ÿ Ξ·) (parallel_wiring βŠ™ parallel_converter (converter_of_resource (map_converter id id (f Ξ·) (g Ξ·) 1C |= 1C ⊳ real1 Ξ·)) 1C)"
    have WT2: "ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ· ⊒g ?π’Ÿ2 Ξ· √" for Ξ· by(rule WT_intro | simp)+
    have bound2: "interaction_any_bounded_by (?π’Ÿ2 Ξ·) (bound2 Ξ·)" for Ξ· by interaction_bound simp
    have "plossless_gpv (ℐ_inner2 Ξ· βŠ•β„ ℐ_common2 Ξ·) (?π’Ÿ2 Ξ·)" if lossless2 for Ξ·
      by(rule plossless_intro WT_intro | simp add: that)+
    from correct2[OF WT2 bound2 this]
    have w2: "wiring (ℐ_inner2 Ξ·) (ℐ_real2 Ξ·) (cnv2 Ξ·) (w2 Ξ·)" 
      and adv2: "negligible (λη. advantage (?π’Ÿ2 Ξ·) (ideal2 Ξ·) (cnv2 Ξ· |= 1C ⊳ real2 Ξ·))" for Ξ·
      by auto

    from w2 have [WT_intro]: "ℐ_inner2 Ξ·, ℐ_real2 Ξ· ⊒C cnv2 Ξ· √" for Ξ· by cases

    have *: "connect (π’Ÿ Ξ·) (?cnv Ξ· |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·) =
      connect (?π’Ÿ2 Ξ·) (cnv2 Ξ· |= 1C ⊳ real2 Ξ·)" for Ξ·
    proof -
      have "outs_ℐ ((ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) βŠ•β„ (ℐ_common1 Ξ· βŠ•β„ ℐ_common2 Ξ·)) ⊒R
         ?cnv Ξ· |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ· ∼ 
         (map_converter id id (f Ξ·) (g Ξ·) 1C |= cnv2 Ξ·) |= (1C |= 1C) ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·"
        by(rule eq_ℐ_attach_on' WT_intro parallel_converter2_eq_ℐ_cong eq1 eq_ℐ_converter_reflI parallel_converter2_id_id[symmetric])+ simp
      also have "(map_converter id id (f Ξ·) (g Ξ·) 1C |= cnv2 Ξ·) |= (1C |= 1C) ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ· =
        parallel_wiring ⊳ (map_converter id id (f Ξ·) (g Ξ·) 1C |= 1C ⊳ real1 Ξ·) βˆ₯ (cnv2 Ξ· |= 1C ⊳ real2 Ξ·)"
        by(simp add: comp_parallel_wiring' attach_compose attach_parallel2)
      finally show ?thesis
        by(auto intro!: connect_eq_resource_cong[OF WT_D] intro: WT_intro simp add: distinguish_attach[symmetric] attach_compose attach_converter_of_resource_conv_parallel_resource)
    qed

    have **: "connect (?π’Ÿ2 Ξ·) (ideal2 Ξ·) = connect (?π’Ÿ1 Ξ·) (cnv1 Ξ· |= 1C ⊳ real1 Ξ·)" for Ξ·
    proof -
      have "connect (?π’Ÿ2 Ξ·) (ideal2 Ξ·) = 
        connect (π’Ÿ Ξ·) (parallel_wiring ⊳ ((map_converter id id (f Ξ·) (g Ξ·) 1C |= 1C) |= 1C) ⊳ (real1 Ξ· βˆ₯ ideal2 Ξ·))"
        by(simp add: distinguish_attach[symmetric] attach_converter_of_resource_conv_parallel_resource attach_compose attach_parallel2)
      also have "… = connect (π’Ÿ Ξ·) (parallel_wiring ⊳ ((cnv1 Ξ· |= 1C) |= 1C) ⊳ (real1 Ξ· βˆ₯ ideal2 Ξ·))"
        unfolding attach_compose[symmetric] using WT_D
        by(rule connect_eq_resource_cong[symmetric])
          (rule eq_ℐ_attach_on' WT_intro eq_ℐ_comp_cong eq_ℐ_converter_reflI parallel_converter2_eq_ℐ_cong eq1 | simp)+
      also have "… = connect (?π’Ÿ1 Ξ·) (cnv1 Ξ· |= 1C ⊳ real1 Ξ·)"
        by(simp add: distinguish_attach[symmetric] attach_converter_of_resource_conv_parallel_resource2 attach_compose attach_parallel2)
      finally show ?thesis .
    qed

    have ***: "connect (?π’Ÿ1 Ξ·) (ideal1 Ξ·) = connect (π’Ÿ Ξ·) (parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ·)" for Ξ·
      by(auto intro!: connect_eq_resource_cong[OF WT_D] simp add: attach_converter_of_resource_conv_parallel_resource2 distinguish_attach[symmetric] attach_compose intro: WT_intro)

    show "wiring (ℐ_inner1 Ξ· βŠ•β„ ℐ_inner2 Ξ·) (ℐ_real1 Ξ· βŠ•β„ ℐ_real2 Ξ·) (?cnv Ξ·) (w1 Ξ· |w w2 Ξ·)" for Ξ·
      using w1 w2 by(rule wiring_parallel_converter2)
    from negligible_plus[OF adv1 adv2]
    show "negligible (λη. advantage (π’Ÿ Ξ·) (parallel_wiring ⊳ ideal1 Ξ· βˆ₯ ideal2 Ξ·) (?cnv Ξ· |= 1C ⊳ parallel_wiring ⊳ real1 Ξ· βˆ₯ real2 Ξ·))"
      by(rule negligible_le)(simp add: advantage_def * ** ***)
  qed
qed

theorem (in constructive_security) parallel_realisation1:
  assumes WT_res: "β‹€Ξ·. ℐ_res Ξ· βŠ•β„ ℐ_common' Ξ· ⊒res res Ξ· √"
    and lossless_res: "β‹€Ξ·. lossless ⟹ lossless_resource (ℐ_res Ξ· βŠ•β„ ℐ_common' Ξ·) (res Ξ·)"
  shows "constructive_security (λη. parallel_wiring ⊳ res Ξ· βˆ₯ real_resource Ξ·)
    (λη. parallel_wiring ⊳ (res Ξ· βˆ₯ ideal_resource Ξ·)) (λη. parallel_converter2 id_converter (sim Ξ·)) 
    (λη. ℐ_res Ξ· βŠ•β„ ℐ_real Ξ·) (λη. ℐ_res Ξ· βŠ•β„ ℐ_ideal Ξ·) (λη. ℐ_common' Ξ· βŠ•β„ ℐ_common Ξ·) bound lossless (λη. (id, id) |w w Ξ·)"
  by(rule parallel_constructive_security[OF constructive_security_trivial[where lossless=False and bound="λ_. ∞", OF WT_res], simplified, OF _ lossless_res])
    unfold_locales

theorem (in constructive_security) parallel_realisation2:
  assumes WT_res: "β‹€Ξ·. ℐ_res Ξ· βŠ•β„ ℐ_common' Ξ· ⊒res res Ξ· √"
    and lossless_res: "β‹€Ξ·. lossless ⟹ lossless_resource (ℐ_res Ξ· βŠ•β„ ℐ_common' Ξ·) (res Ξ·)"
  shows "constructive_security (λη. parallel_wiring ⊳ real_resource Ξ· βˆ₯ res Ξ·)
    (λη. parallel_wiring ⊳ (ideal_resource Ξ· βˆ₯ res Ξ·)) (λη. parallel_converter2 (sim Ξ·) id_converter) 
    (λη. ℐ_real Ξ· βŠ•β„ ℐ_res Ξ·) (λη. ℐ_ideal Ξ· βŠ•β„ ℐ_res Ξ·) (λη. ℐ_common Ξ· βŠ•β„ ℐ_common' Ξ·) bound lossless (λη. w Ξ· |w (id, id))"
  by(rule parallel_constructive_security[OF _ constructive_security_trivial[where lossless=False and bound="λ_. ∞", OF WT_res], simplified, OF _ lossless_res])
    unfold_locales

theorem (in constructive_security) parallel_resource1:
  assumes WT_res [WT_intro]: "β‹€Ξ·. ℐ_res Ξ· ⊒res res Ξ· √"
    and lossless_res [plossless_intro]: "β‹€Ξ·. lossless ⟹ lossless_resource (ℐ_res Ξ·) (res Ξ·)"
  shows "constructive_security (λη. parallel_resource1_wiring ⊳ res Ξ· βˆ₯ real_resource Ξ·)
    (λη. parallel_resource1_wiring ⊳ res Ξ· βˆ₯ ideal_resource Ξ·) sim 
    ℐ_real ℐ_ideal (λη. ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·) bound lossless w"
proof
  fix π’œ :: "security β‡’ ('a + 'g + 'e, 'b + 'h + 'f) distinguisher"
  assume WT [WT_intro]: "ℐ_real Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·) ⊒g π’œ Ξ· √" for Ξ·
  assume bound [interaction_bound]: "interaction_any_bounded_by (π’œ Ξ·) (bound Ξ·)" for Ξ·
  assume lossless [plossless_intro]: "lossless ⟹ plossless_gpv (ℐ_real Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·)) (π’œ Ξ·)" for Ξ·

  let ?π’œ = "λη. absorb (π’œ Ξ·) (swap_lassocr βŠ™ parallel_converter (converter_of_resource (res Ξ·)) 1C)"
  have ideal:
    "connect (π’œ Ξ·) (sim Ξ· |= 1C ⊳ parallel_resource1_wiring ⊳ res Ξ· βˆ₯ ideal_resource Ξ·) =
     connect (?π’œ Ξ·) (sim Ξ· |= 1C ⊳ ideal_resource Ξ·)" for Ξ·
  proof -
    have[intro]: "ℐ_uniform (outs_ℐ (ℐ_real Ξ·) <+> outs_ℐ (ℐ_res Ξ·) <+> outs_ℐ (ℐ_common Ξ·))
     UNIV,ℐ_ideal Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·) ⊒C  sim Ξ· |= 1C ∼ sim Ξ· |= 1C |= 1C " 
      by(rule eq_ℐ_converter_mono) (auto simp add: le_ℐ_def intro!: 
          WT_intro parallel_converter2_id_id[symmetric] parallel_converter2_eq_ℐ_cong eq_ℐ_converter_reflI)

    have *: "outs_ℐ (ℐ_real Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·)) ⊒R  (sim Ξ· |= 1C) βŠ™ parallel_resource1_wiring ⊳ res Ξ· βˆ₯ ideal_resource Ξ· ∼
      swap_lassocr βŠ™ (converter_of_resource (res Ξ·) |∝ 1C) ⊳ sim Ξ· |= 1C ⊳ ideal_resource Ξ·" 
      by (rule eq_resource_on_trans[where res'="(sim Ξ· |= 1C |= 1C) βŠ™ parallel_resource1_wiring ⊳ res Ξ· βˆ₯ ideal_resource Ξ·"], 
          rule eq_ℐ_attach_on, (rule  WT_intro)+, rule eq_ℐ_comp_cong)
        (auto simp add: parallel_resource1_wiring_def comp_swap_lassocr attach_compose attach_parallel2 
          attach_converter_of_resource_conv_parallel_resource intro!: WT_intro eq_ℐ_converter_reflI)  

    show ?thesis
      unfolding distinguish_attach[symmetric] using WT
      by(rule connect_eq_resource_cong, subst attach_compose[symmetric])
        (intro *, (rule WT_intro)+)
  qed
  have real:
    "connect (π’œ Ξ·) (parallel_resource1_wiring ⊳ res Ξ· βˆ₯ real_resource Ξ·) =
     connect (?π’œ Ξ·) (real_resource Ξ·)" for Ξ·
    unfolding distinguish_attach[symmetric]
    by(simp add: attach_compose attach_converter_of_resource_conv_parallel_resource parallel_resource1_wiring_def)
  have "ℐ_real Ξ· βŠ•β„ ℐ_common Ξ· ⊒g ?π’œ Ξ· √" for Ξ· by(rule WT_intro)+
  moreover have "interaction_any_bounded_by (?π’œ Ξ·) (bound Ξ·)" for Ξ·
    by interaction_bound_converter simp
  moreover have "plossless_gpv (ℐ_real Ξ· βŠ•β„ ℐ_common Ξ·) (?π’œ Ξ·)" if lossless for Ξ· 
    by(rule plossless_intro WT_intro | simp add: that)+
  ultimately show "negligible (λη. advantage (π’œ Ξ·) (sim Ξ· |= 1C ⊳
                        parallel_resource1_wiring ⊳ res Ξ· βˆ₯ ideal_resource Ξ·)
                       (parallel_resource1_wiring ⊳ res Ξ· βˆ₯ real_resource Ξ·))"
    unfolding advantage_def ideal real by(rule adv[unfolded advantage_def])
next
  from correct obtain cnv 
    where correct': "β‹€π’Ÿ. ⟦ β‹€Ξ·. ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒g π’Ÿ Ξ· √;
          β‹€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound Ξ·);
          β‹€Ξ·. lossless ⟹ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·) (π’Ÿ Ξ·) ⟧
          ⟹ (βˆ€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)) ∧
              negligible (λη. advantage (π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·))"
    by blast
  show "βˆƒcnv. βˆ€π’Ÿ. (βˆ€Ξ·. ℐ_ideal Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·) ⊒g π’Ÿ Ξ· √) ⟢
        (βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound Ξ·)) ⟢
        (βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·)) (π’Ÿ Ξ·)) ⟢
        (βˆ€Ξ·. wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)) ∧
        negligible (λη. advantage (π’Ÿ Ξ·) (parallel_resource1_wiring ⊳ res Ξ· βˆ₯ ideal_resource Ξ·)
          (cnv Ξ· |= 1C ⊳ parallel_resource1_wiring ⊳ res Ξ· βˆ₯ real_resource Ξ·))"
  proof(intro exI conjI strip)
    fix π’Ÿ :: "security β‡’ ('c + 'g + 'e, 'd + 'h + 'f) distinguisher"
    assume WT_D [rule_format, WT_intro]: "βˆ€Ξ·. ℐ_ideal Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·) ⊒g π’Ÿ Ξ· √"
      and bound [rule_format, interaction_bound]: "βˆ€Ξ·. interaction_any_bounded_by (π’Ÿ Ξ·) (bound Ξ·)"
      and lossless [rule_format, plossless_intro]: "βˆ€Ξ·. lossless ⟢ plossless_gpv (ℐ_ideal Ξ· βŠ•β„ (ℐ_res Ξ· βŠ•β„ ℐ_common Ξ·)) (π’Ÿ Ξ·)"

    let ?π’Ÿ = "λη. absorb (π’Ÿ Ξ·) (swap_lassocr βŠ™ parallel_converter (converter_of_resource (res Ξ·)) 1C)"
    have WT': "ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ· ⊒g ?π’Ÿ Ξ· √" for Ξ· by(rule WT_intro)+
    have bound': "interaction_any_bounded_by (?π’Ÿ Ξ·) (bound Ξ·)" for Ξ· by interaction_bound simp
    have lossless': "plossless_gpv (ℐ_ideal Ξ· βŠ•β„ ℐ_common Ξ·) (?π’Ÿ Ξ·)" if lossless for Ξ·
      by(rule plossless_intro WT_intro that)+
    from correct'[OF WT' bound' lossless']
    have w: "wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)" 
      and adv: "negligible (λη. advantage (?π’Ÿ Ξ·) (ideal_resource Ξ·) (cnv Ξ· |= 1C ⊳ real_resource Ξ·))"
      for Ξ· by auto
    show  "wiring (ℐ_ideal Ξ·) (ℐ_real Ξ·) (cnv Ξ·) (w Ξ·)" for Ξ· by(rule w)
    from w have [WT_intro]: "ℐ_ideal Ξ·, ℐ_real Ξ· ⊒C cnv Ξ· √" for Ξ· by cases
    have "connect (π’Ÿ Ξ·) (swap_lassocr ⊳ res Ξ· βˆ₯ (cnv Ξ· |= 1C ⊳ real_resource Ξ·)) =
      connect (π’Ÿ Ξ·) (cnv Ξ· |= 1C ⊳ swap_lassocr ⊳ res Ξ· βˆ₯ real_resource Ξ·)" for Ξ·
    proof -
      have "connect (π’Ÿ Ξ·) (cnv Ξ· |= 1C ⊳ swap_lassocr ⊳ res Ξ· βˆ₯ real_resource Ξ·) =
        connect (π’Ÿ Ξ·) (cnv Ξ· |= 1C |= 1C ⊳ swap_lassocr ⊳ res Ξ· βˆ₯ real_resource Ξ·)"
        by(rule connect_eq_resource_cong[OF WT_D])                                                                
          (rule eq_ℐ_attach_on' WT_intro parallel_converter2_eq_ℐ_cong eq_ℐ_converter_reflI parallel_converter2_id_id[symmetric] | simp)+
      also have "… = connect (π’Ÿ Ξ·) (swap_lassocr ⊳ res Ξ· βˆ₯ (cnv Ξ· |= 1C ⊳ real_resource Ξ·))"
        by(simp add: comp_swap_lassocr' attach_compose attach_parallel2)
      finally show ?thesis by simp
    qed
    with adv show "negligible (λη. advantage (π’Ÿ Ξ·) (parallel_resource1_wiring ⊳ res Ξ· βˆ₯ ideal_resource Ξ·)
          (cnv Ξ· |= 1C ⊳ parallel_resource1_wiring ⊳ res Ξ· βˆ₯ real_resource Ξ·))"
      by(simp add: advantage_def distinguish_attach[symmetric] attach_compose attach_converter_of_resource_conv_parallel_resource parallel_resource1_wiring_def)
  qed
qed(rule WT_intro)+

end