Require Import Eqdep Lia Framework FSParameters FileDiskLayer. (* LoggedDiskLayer TransactionCacheLayer TransactionalDiskLayer. *)
Require Import FileDiskNoninterference FileDiskRefinement.
Require Import ATC_ORS ATCDLayer ATC_Simulation HSS ATC_TransferProofs.
Require Import ATCD_Simulation ATCD_AOE.
Require Import Not_Init ATCD_ORS ATCD_TIE ATCD_HSS ATCD_Commit_Pre.

Import FileDiskLayer.
Set Nested Proofs Allowed.

Lemma AOE_explicit_to_AOE:
forall O1 O2 (L1: Layer O1) (L2: Layer O2) (Ref: Refinement L1 L2)
R u T (p: prog L2 T) rec l_grs,
(forall l_o s1 s2,
abstract_oracles_exist_wrt_explicit Ref R u p rec l_grs l_o s1 s2) ->
abstract_oracles_exist_wrt Ref R u p rec l_grs.
Proof.
  unfold abstract_oracles_exist_wrt_explicit,
  abstract_oracles_exist_wrt; eauto.
Qed.

Definition compile_to_ATCD {T} (p: prog _ T) :=
  (Simulation.Definitions.compile ATCD_Refinement
(Simulation.Definitions.compile ATC_Refinement
   (Simulation.Definitions.compile FD.refinement p))).

Definition ATCD_log_equivalent (s1 s2: state ATCDLang) :=
  (exists (hdr1 hdr2 : Log.header) (merged_disk1 merged_disk2 : total_mem),
  (exists txns1 : list Log.txn,
     fst (snd (snd s1)) =
     Mem.list_upd_batch empty_mem (map Log.addr_list txns1)
       (map Log.data_blocks txns1) /\
     Log.log_header_rep hdr1 txns1 (snd (snd (snd s1))) /\
     merged_disk1 =
     total_mem_map fst
       (shift (Nat.add data_start)
          (list_upd_batch_set (snd (snd (snd (snd s1))))
             (map Log.addr_list txns1) (map Log.data_blocks txns1))) /\
     (forall a : nat,
      a >= data_start -> snd (snd (snd (snd (snd s1))) a) = [])) /\
  (exists txns2 : list Log.txn,
     fst (snd (snd s2)) =
     Mem.list_upd_batch empty_mem (map Log.addr_list txns2)
       (map Log.data_blocks txns2) /\
     Log.log_header_rep hdr2 txns2 (snd (snd (snd s2))) /\
     merged_disk2 =
     total_mem_map fst
       (shift (Nat.add data_start)
          (list_upd_batch_set (snd (snd (snd (snd s2))))
             (map Log.addr_list txns2) (map Log.data_blocks txns2))) /\
     (forall a : nat,
      a >= data_start -> snd (snd (snd (snd (snd s2))) a) = [])) /\
  Log.count (Log.current_part hdr1) = Log.count (Log.current_part hdr2) /\
  Forall2
    (fun rec1 rec2 : Log.txn_record =>
     Log.addr_count rec1 = Log.addr_count rec2)
    (Log.records (Log.current_part hdr1))
    (Log.records (Log.current_part hdr2)) /\
  Forall2
    (fun rec1 rec2 : Log.txn_record =>
     Log.data_count rec1 = Log.data_count rec2)
    (Log.records (Log.current_part hdr1))
    (Log.records (Log.current_part hdr2))).

(********** Transfer Theorems ***********)
Opaque File.read File.recover.
Theorem ss_ATCD_read:
  forall n inum off u u' lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD  (| Read inum off |))
  (compile_to_ATCD (|Recover|)) lo s1 ->

  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD  (| Read inum off |))
  (compile_to_ATCD (|Recover|)) lo s2 ->

  (forall s1',
    exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| Read inum off |)) (Crashed s1') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

  (forall s2',
    exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| Read inum off |)) (Crashed s2') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

    ATCD_log_equivalent s1 s2 ->

  RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD  (| Read inum off |))
    (compile_to_ATCD  (| Read inum off |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    ((refines_related ATCD_Refinement (refines_related ATC_Refinement (AD_related_states u' None))))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - simpl.
  apply ss_ATC_read.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_read].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    Transparent File.read.
    unfold File.read.
    eapply ATC_HSS_auth_then_exec; eauto.
    intros.
    eapply ATC_HSS_read_inner; eauto.
    unfold  refines_related; eauto.
    intros; eapply read_inner_commit_pre; eauto.
    eapply have_same_structure_read; eauto.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

Opaque File.write File.recover.
Theorem ss_ATCD_write:
  forall n inum off u u' v lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Write inum off v |))
  (compile_to_ATCD (|Recover|)) lo s1 ->

  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Write inum off v |))
  (compile_to_ATCD (|Recover|)) lo s2 ->

  (forall s1',
    exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| Write inum off v |)) (Crashed s1') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

  (forall s2',
    exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| Write inum off v |)) (Crashed s2') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

    ATCD_log_equivalent s1 s2 ->

  RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD (| Write inum off v |))
    (compile_to_ATCD (| Write inum off v |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    (refines_related ATCD_Refinement (refines_related ATC_Refinement (AD_related_states u' None)))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - simpl.
  eapply ss_ATC_write.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_write].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    Transparent File.write.
    unfold File.write.
    eapply ATC_HSS_auth_then_exec; eauto.
    intros.
    eapply ATC_HSS_write_inner; eauto.
    unfold  refines_related; eauto.
    intros; eapply write_inner_commit_pre; eauto.
    eapply have_same_structure_write; eauto.
    Opaque File.write.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

Theorem ss_ATCD_write_input:
  forall n inum off u u' v1 v2 lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Write inum off v1 |))
  (compile_to_ATCD (|Recover|)) lo s1 ->

  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Write inum off v2 |))
  (compile_to_ATCD (|Recover|)) lo s2 ->

  (forall s1',
    exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| Write inum off v1 |)) (Crashed s1') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

  (forall s2',
    exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| Write inum off v2 |)) (Crashed s2') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

    ATCD_log_equivalent s1 s2 ->

  RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD (| Write inum off v1 |))
    (compile_to_ATCD (| Write inum off v2 |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    (refines_related ATCD_Refinement (refines_related ATC_Refinement (AD_related_states u' (Some inum))))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - simpl.
  eapply ss_ATC_write_input.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_write].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    Transparent File.write.
    unfold File.write.
    eapply ATC_HSS_auth_then_exec; eauto.
    intros.
    eapply ATC_HSS_write_inner; eauto.
    unfold  refines_related; eauto.
    intros; eapply write_inner_commit_pre; eauto.
    eapply have_same_structure_write_input; eauto.
    Opaque File.write.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

Opaque File.create File.recover.
Theorem ss_ATCD_create:
  forall n u u' v lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Create v |))
  (compile_to_ATCD (|Recover|)) lo s1 ->

  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Create v |))
  (compile_to_ATCD (|Recover|)) lo s2 ->

  (forall s1',
    exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| Create v |)) (Crashed s1') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

  (forall s2',
    exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| Create v |)) (Crashed s2') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

    ATCD_log_equivalent s1 s2 ->

    RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD (| Create v |))
    (compile_to_ATCD (| Create v |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    (refines_related ATCD_Refinement (refines_related ATC_Refinement (AD_related_states u' None)))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - apply ss_ATC_create.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_create].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    eapply ATC_HSS_create; eauto.
    eapply have_same_structure_create; eauto.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

Opaque File.extend File.recover.
Theorem ss_ATCD_extend:
  forall n u u' inum v lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD(| Extend inum v |))
  (compile_to_ATCD (|Recover|)) lo s1 ->

  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD(| Extend inum v |))
  (compile_to_ATCD (|Recover|))lo s2 ->

  (forall s1',
    exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| Extend inum v |)) (Crashed s1') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

  (forall s2',
    exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| Extend inum v |)) (Crashed s2') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

    ATCD_log_equivalent s1 s2 ->

    RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD(| Extend inum v |))
    (compile_to_ATCD(| Extend inum v |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    (refines_related ATCD_Refinement (refines_related ATC_Refinement (AD_related_states u' None)))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - apply ss_ATC_extend.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_extend].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    Transparent File.extend.
    unfold File.extend.
    eapply ATC_HSS_auth_then_exec; eauto.
    intros.
    eapply ATC_HSS_extend_inner; eauto.
    unfold  refines_related; eauto.
    intros; eapply extend_inner_commit_pre; eauto.
    eapply have_same_structure_extend; eauto.
    Opaque File.extend.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

Theorem ss_ATCD_extend_input:
  forall n u u' inum v1 v2 lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD(| Extend inum v1 |))
  (compile_to_ATCD (|Recover|)) lo s1 ->

  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD(| Extend inum v2 |))
  (compile_to_ATCD (|Recover|))lo s2 ->

  (forall s1',
    exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| Extend inum v1 |)) (Crashed s1') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

  (forall s2',
    exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| Extend inum v2 |)) (Crashed s2') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

    ATCD_log_equivalent s1 s2 ->

    RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD(| Extend inum v1 |))
    (compile_to_ATCD(| Extend inum v2 |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    (refines_related ATCD_Refinement (refines_related ATC_Refinement (AD_related_states u' (Some inum))))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - apply ss_ATC_extend_input.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_extend].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    Transparent File.extend.
    unfold File.extend.
    eapply ATC_HSS_auth_then_exec; eauto.
    intros.
    eapply ATC_HSS_extend_inner; eauto.
    unfold  refines_related; eauto.
    intros; eapply extend_inner_commit_pre; eauto.
    eapply have_same_structure_extend_input; eauto.
    Opaque File.extend.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

Opaque File.change_owner File.recover.
Theorem ss_ATCD_change_owner:
  forall n u u' inum v lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| ChangeOwner inum v |))
  (compile_to_ATCD (|Recover|)) lo s1 ->

  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| ChangeOwner inum v |))
  (compile_to_ATCD (|Recover|)) lo s2 ->

  (forall s1',
    exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| ChangeOwner inum v |)) (Crashed s1') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

  (forall s2',
    exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| ChangeOwner inum v |)) (Crashed s2') ->
    no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

    ATCD_log_equivalent s1 s2 ->

    RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD (| ChangeOwner inum v |))
    (compile_to_ATCD (| ChangeOwner inum v |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    (refines_related ATCD_Refinement
    (refines_related ATC_Refinement (AD_related_states u' (Some inum))))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - apply ss_ATC_change_owner.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_change_owner].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    Transparent File.change_owner.
    unfold File.change_owner.
    eapply ATC_HSS_auth_then_exec; eauto.
    intros.
    eapply ATC_HSS_change_owner_inner; eauto.
    unfold  refines_related; eauto.
    intros; eapply change_owner_inner_commit_pre; eauto.
    eapply have_same_structure_change_owner; eauto.
    Opaque File.change_owner.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

Opaque File.delete File.recover.
Theorem ss_ATCD_delete:
  forall n u u' inum lo s1 s2,
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Delete inum |))
  (compile_to_ATCD (|Recover|)) lo s1 ->
  non_colliding_selector_list u
  (Simulation.Definitions.refines ATCD_Refinement)
  (Simulation.Definitions.refines_reboot ATCD_Refinement) n
  (compile_to_ATCD (| Delete inum |))
  (compile_to_ATCD (|Recover|)) lo s2 ->

  (forall s1',
  exec ATCDLang u (hd [] lo) s1 (compile_to_ATCD  (| Delete inum |)) (Crashed s1') ->
  no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s1'))))) ->

(forall s2',
  exec ATCDLang u (hd [] lo) s2 (compile_to_ATCD  (| Delete inum |)) (Crashed s2') ->
  no_accidental_overlap (hd (fun _ => 0) n) (snd (snd (snd (snd s2'))))) ->

  ATCD_log_equivalent s1 s2 ->

  RDNI_Weak_explicit u lo s1 s2
    (compile_to_ATCD (| Delete inum |))
    (compile_to_ATCD (| Delete inum |))
    (compile_to_ATCD (|Recover|))
    (refines_valid ATCD_Refinement (refines_valid ATC_Refinement AD_valid_state))
    (refines_related ATCD_Refinement
    (refines_related ATC_Refinement (AD_related_states u' None)))
    (eq u') (ATCD_reboot_list n).
Proof.
  intros.
  eapply RDNIW_explicit_transfer.
  - apply ss_ATC_delete.
  - eapply ATCD_simulation.
    shelve.
  - eapply ATCD_simulation.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; apply ATCD_AOE; eauto.
    shelve.
  - intros; eapply ATCD_ORS_transfer; simpl.
    all: shelve.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  - unfold exec_compiled_preserves_validity, AD_valid_state,
  refines_valid, FD_valid_state;
  intros; simpl; eauto.
  Unshelve.
  all: simpl; try solve [try apply not_init_compile; apply not_init_delete].
  {
    unfold refines_related; simpl; intros.
    cleanup.
    Transparent File.delete.
    unfold File.delete.
    eapply ATC_HSS_auth_then_exec; eauto.
    intros.
    eapply ATC_HSS_delete_inner; eauto.
    unfold  refines_related; eauto.
    intros; eapply delete_inner_commit_pre; eauto.
    eapply have_same_structure_delete; eauto.
    Opaque File.delete.
  }
  all: try solve [ intros; cleanup; simpl in *; intuition eauto ].
Qed.

(*
Opaque File.recover.
Lemma ATCD_TS_read_inner:
    forall n inum off u u' txns1 txns2 hdr1 hdr2,
    Termination_Sensitive u
    (Simulation.Definitions.compile
    ATCD_Refinement
   (Simulation.Definitions.compile
    ATC_Refinement
    (@lift_L2 AuthenticationOperation _ TD _
    (File.read_inner off inum))))
   (Simulation.Definitions.compile
    ATCD_Refinement
   (Simulation.Definitions.compile
    ATC_Refinement
    (@lift_L2 AuthenticationOperation _ TD _
    (File.read_inner off inum))))
    (Simulation.Definitions.compile
    ATCD_Refinement
    (Simulation.Definitions.compile
    ATC_Refinement
    File.recover))
   (refines_valid ATCD_Refinement
     (refines_valid ATC_Refinement
    AD_valid_state))
  (fun s1 s2 => refines_related ATCD_Refinement (refines_related ATC_Refinement ( (fun s1 s2  => exists s1a s2a,
  File.files_inner_rep s1a (fst (snd (snd s1))) /\
  File.files_inner_rep s2a (fst (snd (snd s2))) /\
  FD_related_states u' None s1a s2a /\
  fst (snd s1) = Empty /\ fst (snd s2) = Empty))) s1 s2 /\
  equivalent_for_recovery txns1 txns2 Log.Current_Part hdr1 hdr2 s1 s2)
     (ATCD_reboot_list n).
  Proof.
    Transparent File.read_inner.
    intros; unfold File.read_inner.
    eapply ATCD_TS_compositional.
    intros; eapply TS_eqv_impl.
    eapply ATCD_TS_get_block_number.
    simpl; intros; shelve.
    2: intros; shelve.

    intros; unfold refines_related in *; cleanup.
    intros; unfold refines_related in *; cleanup.
    eapply_fresh ATCD_oracle_refines_finished in H; eauto.
    eapply_fresh ATCD_oracle_refines_finished in H0; eauto.
    cleanup.

    eapply_fresh ATCD_exec_lift_finished in H; eauto;
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
    cleanup.
    eapply_fresh ATCD_exec_lift_finished in H0; eauto;
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
    cleanup.
    simpl in *.
    eapply_fresh ATCD_oracle_refines_impl_eq in H11; eauto.
    2: shelve. (* eapply have_same_structure_get_owner; eauto. *)
    2: apply TC_oracle_refines_operation_eq.
    cleanup.

    clear H H0.

    eapply_fresh ATC_oracle_refines_finished in H13; eauto.
    eapply_fresh ATC_oracle_refines_finished in H15; eauto.
    cleanup.
    eapply_fresh ATC_exec_lift_finished in H13; eauto;
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
    cleanup.
    eapply_fresh ATC_exec_lift_finished in H15; eauto;
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
    try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
    cleanup.
    simpl in *.
    eapply ATC_oracle_refines_impl_eq in H; eauto.
    2: shelve.
    2: apply TD_oracle_refines_operation_eq.
    cleanup.

    clear H13 H15.

    eapply lift2_invert_exec in H17;
    eapply lift2_invert_exec in H19; cleanup.
    apply HC_map_ext_eq in H; subst.

    unfold File.files_inner_rep in *; cleanup.
    eapply_fresh Inode.get_block_number_finished_oracle_eq in H21; eauto; subst.
    cleanup; destruct r1, r2; try solve [intuition congruence].
    2: intros; eapply TS_eqv_impl; [apply ATCD_TS_ret | shelve].

    eapply ATCD_TS_compositional.
    2: intros; destruct r1, r2; (eapply TS_eqv_impl; [apply ATCD_TS_ret | shelve]).
    2: shelve.
    simpl; intros; repeat invert_exec; try congruence.
    eapply TS_eqv_impl.
    eapply ATCD_TS_DiskAllocator_read.
    {
      eapply Inode.get_block_number_finished in H21; eauto.
      eapply Inode.get_block_number_finished in H17; eauto.
      cleanup; repeat split_ors; cleanup; intuition eauto.
      eapply SameRetType.all_block_numbers_in_bound in H.
      3: eauto.
      all: eauto.
      eapply Forall_forall in H; eauto.
      eapply in_seln; eauto.

      eapply SameRetType.all_block_numbers_in_bound in H6.
      3: eauto.
      all: eauto.
      eapply Forall_forall in H6; eauto.
      apply in_seln; eauto.
    }
    {
      eapply Inode.get_block_number_finished in H21; eauto.
      eapply Inode.get_block_number_finished in H17; eauto.

      cleanup; repeat split_ors; cleanup; intuition eauto.
      eapply data_block_inbounds; eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.

      eapply data_block_inbounds.
      4: eauto.
      all: eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.
    }
    {
      shelve. (*
      instantiate (2:= refines_related ATCD_Refinement
      (fun s1 s2  =>
      exists s1a s2a,
      (Inode.inode_rep im1 (fst (snd (snd s1))) /\
          (exists file_block_map,
              File.DiskAllocator.block_allocator_rep file_block_map
                (fst (snd (snd s1))) /\
              File.file_map_rep s1a im1 file_block_map)) /\
        (Inode.inode_rep im2 (fst (snd (snd s2))) /\
          (exists file_block_map,
              File.DiskAllocator.block_allocator_rep file_block_map
                (fst (snd (snd s2))) /\
              File.file_map_rep s2a im2 file_block_map)) /\
      FD_related_states u' None s1a s2a /\
      fst (snd s1) = Empty /\
      fst (snd s2) = Empty)).

        simpl; intros.
        unfold refines_related in *.
        cleanup.
        split.
        unfold File.files_inner_rep.
        do 2 eexists; intuition eauto.
        do 2 eexists; intuition eauto.

        simpl in *; unfold HC_refines in H12, H21; cleanup.
        simpl in *; unfold TransactionToTransactionalDisk.Definitions.refines,
        Transaction.transaction_rep  in *; cleanup;
        repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H34;
      eapply txn_length_0_empty in H38; subst.
      setoid_rewrite H34;
      setoid_rewrite H38.
      simpl; intuition eauto.

      rewrite H38, H34 in *; simpl in *.
      eapply Inode.get_block_number_finished in H20; eauto.
      eapply Inode.get_block_number_finished in H18; eauto.
      cleanup; repeat split_ors; cleanup; intuition eauto.
      repeat erewrite TSCommon.used_blocks_are_allocated_2; eauto.
      *)
    }
    shelve.
    shelve.
    shelve.
    shelve.
    all: unfold Simulation.Definitions.refines in *; simpl in *; eauto.

    Unshelve.
    41: instantiate (5 := fun _ _ => _); simpl; eauto.
    all: eauto.
    {
      simpl.
      intros; unfold refines_related in *; cleanup.
      simpl in *.
      unfold File.files_inner_rep in *; cleanup.
      do 2 eexists; intuition eauto.
      do 2 eexists; intuition eauto.

      do 2 eexists; intuition eauto.

      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H14;
      setoid_rewrite H14.
      simpl; eauto.

      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H18;
      setoid_rewrite H18.
      simpl; eauto.
    }
    {
      simpl.
      intros; unfold refines_related in *; cleanup.
      eapply_fresh get_block_number_oracle_refines_exists in H; eauto.
      eapply_fresh get_block_number_oracle_refines_exists in H0; eauto.
      cleanup.

      eapply_fresh ATCD_exec_lift_finished in H; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H0; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATCD_oracle_refines_impl_eq in H12; eauto.
      2: eapply have_same_structure_get_block_number; eauto.
      3: apply TD_oracle_refines_operation_eq.
      cleanup.

      eapply lift2_invert_exec in H14;
      eapply lift2_invert_exec in H16; cleanup.
      apply map_ext_eq in H12; cleanup.
      2: intros; cleanup; intuition congruence.
      unfold File.files_inner_rep in *; cleanup.
      eapply Inode.get_block_number_finished in H20; eauto.
      eapply Inode.get_block_number_finished in H18; eauto.
      cleanup.
      clear H12 H20.
      do 2 eexists; intuition eauto.
      do 2 eexists; intuition eauto.

      eexists; intuition eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.

      eexists; intuition eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.

      setoid_rewrite H26; eauto.
      setoid_rewrite H22; eauto.

      unfold File.files_inner_rep in *; cleanup.
      do 2 eexists; intuition eauto.
    }
    all: try solve [exact (fun _ _ => True)].
    all: simpl; eauto.
    {
      intros.
      match goal with
       | [H: _ ?inum = Some _,
          H0: _ ?inum = Some _ |- _] =>
       eapply_fresh FileInnerSpecs.inode_exists_then_file_exists in H; eauto; cleanup;
       eapply_fresh FileInnerSpecs.inode_exists_then_file_exists in H0; eauto; cleanup
       end.
       unfold FD_related_states,
       same_for_user_except in *; cleanup.
       match goal with
       | [H: ?fm1 ?inum = Some _,
          H0: ?fm2 ?inum = Some _,
          H1: forall (_: addr) (_ _: File),
           ?fm1 _ = Some _ ->
           ?fm2 _ = Some _ ->
           _ = _ /\ _ = _ |- _] =>
           eapply_fresh H1 in H; eauto; cleanup
      end.
       unfold File.file_map_rep in *; cleanup.
       match goal with
       | [H: ?x1 ?inum = Some _,
          H0: ?x2 ?inum = Some _,
          H1: forall (_: Inode.Inum) _ _,
          ?x1 _ = Some _ ->
          _ _ = Some _ -> _,
          H2: forall (_: Inode.Inum) _ _,
          ?x2 _ = Some _ ->
          _ _ = Some _ -> _ |- _] =>
          eapply H1 in H; eauto; cleanup;
          eapply H2 in H0; eauto; cleanup
       end.
       unfold File.file_rep in *; cleanup; eauto.
    }
    Unshelve.
    all: eauto.
  Qed.
    Opaque File.read_inner.

Opaque Inode.get_owner.
Lemma ATCD_TS_read:
    forall n inum off u u' txns1 txns2 hdr1 hdr2 lo s1 s2,
    Termination_Sensitive_explicit u lo s1 s2
    (Simulation.Definitions.compile
    ATCD_Refinement
   (Simulation.Definitions.compile
    ATC_Refinement
    (File.read inum off)))
   (Simulation.Definitions.compile
    ATCD_Refinement
   (Simulation.Definitions.compile
    ATC_Refinement
    (File.read inum off)))
    (Simulation.Definitions.compile
    ATCD_Refinement
    (Simulation.Definitions.compile
    ATC_Refinement
    File.recover))
   (refines_valid ATCD_Refinement
     (refines_valid ATC_Refinement
    AD_valid_state))
  (fun s1 s2 => refines_related ATCD_Refinement (refines_related ATC_Refinement (AD_related_states u' None)) s1 s2 /\
  equivalent_for_recovery txns1 txns2 Log.Current_Part hdr1 hdr2 s1 s2)
     (ATCD_reboot_list n).
  Proof.
    Opaque File.read_inner Transaction.commit.
    intros; simpl.
    eapply ATCD_TS_explicit_compositional.
    {
      intros; eapply TS_explicit_to_TS;
      eapply TS_eqv_impl;
      [apply ATCD_TS_get_owner | shelve].
      (*
      unfold refines_related, AD_related_states;
      simpl. unfold refines_related; simpl.
      unfold refines, File.files_rep; simpl.
      intros; cleanup; intuition eauto.
      do 2 eexists; intuition eauto.
      rewrite H4, H6;
      do 2 eexists; intuition eauto.
      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H12;
      setoid_rewrite H12.
      simpl; eauto.

      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H16;
      setoid_rewrite H16.
      simpl; eauto.
      *)
    }
    {
      intros; unfold refines_related in *; cleanup.
      eapply_fresh ATCD_oracle_refines_finished in H0; eauto.
      eapply_fresh ATCD_oracle_refines_finished in H1; eauto.
      cleanup.

      eapply_fresh ATCD_exec_lift_finished in H0; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H1; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATCD_oracle_refines_impl_eq in H8; eauto.
      2: shelve. (* eapply have_same_structure_get_owner; eauto. *)
      2: apply TC_oracle_refines_operation_eq.
      cleanup.

      eapply_fresh ATC_oracle_refines_finished in H10; eauto.
      eapply_fresh ATC_oracle_refines_finished in H12; eauto.
      cleanup.
      eapply_fresh ATC_exec_lift_finished in H10; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATC_exec_lift_finished in H12; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATC_oracle_refines_impl_eq in H8; eauto.
      2: eapply have_same_structure_get_owner; eauto.
      2: apply TD_oracle_refines_operation_eq.
      cleanup.

      repeat invert_lift2; cleanup.
      apply HC_map_ext_eq in H8; cleanup.

      eapply_fresh get_owner_related_ret_eq in H21; eauto; subst.
      destruct r1.
      2: intros; eapply TS_explicit_to_TS;
      eapply TS_eqv_impl;
      [ apply ATCD_TS_abort_then_ret| shelve].

      eapply ATCD_TS_explicit_compositional.
      intros; eapply TS_explicit_to_TS;
      eapply TS_eqv_impl;
      [apply ATCD_TS_Authentication_auth | shelve].
      2: shelve.
      simpl; intros; repeat invert_exec; try congruence.
      2: intros; eapply TS_explicit_to_TS;
      eapply TS_eqv_impl;
      [ apply ATCD_TS_abort_then_ret| shelve].
      eapply ATCD_TS_explicit_compositional.

      (**** This part varies in proofs ****)
      intros; eapply ATCD_TS_read_inner.
      intros.
      {
        instantiate (1:= refines_related ATCD_Refinement
        (fun s3 s4 : state AD =>
         exists s1a s2a : disk File,
           File.files_inner_rep s1a (fst (snd (snd s3))) /\
           File.files_inner_rep s2a (fst (snd (snd s4))) /\
           FD_related_states u' None s1a s2a /\
           fst (snd s3) = Empty /\ fst (snd s4) = Empty)) in H13; simpl in *; cleanup.
           unfold refines_related, FD_related_states in *; simpl in *; cleanup.

          eapply_fresh read_inner_oracle_refines_exists in H4; eauto.
          eapply_fresh read_inner_oracle_refines_exists in H6; eauto.
          cleanup.
          eapply_fresh ATCD_exec_lift_finished in H4; eauto;
          try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
          try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
          cleanup.
          eapply_fresh ATCD_exec_lift_finished in H6; eauto;
          try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
          try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
          cleanup.
          simpl in *.

          eapply lift2_invert_exec in H22;
          eapply lift2_invert_exec in H24; cleanup.

          eapply ATCD_oracle_refines_impl_eq in H21.
          2: apply H20.
          all: simpl in *; eauto.
          2: apply TD_oracle_refines_operation_eq.
          apply map_ext_eq in H21; cleanup.
          2: intros; cleanup; intuition congruence.
          eapply SameRetType.read_inner_finished_oracle_eq in H27.
          2: apply H29.
          all: eauto.
          cleanup.
          destruct r1, r2; try solve [intuition congruence].
          intros; apply ATCD_TS_commit_then_ret.
          intros; apply ATCD_TS_abort_then_ret.
          eapply have_same_structure_read_inner; eauto.
          do 2 eexists; intuition eauto.
          unfold FD_related_states;
          apply TSCommon.same_for_user_except_symmetry; eauto.
          apply not_init_read_inner.
          apply not_init_read_inner.
      }
      (**************)
      intros; shelve.
    }
    intros; shelve.
    Unshelve.
    all: try exact u'.
    all: eauto.
    all: try solve [exact (fun _ _ => True)].
    all: try solve [simpl; eauto].
    {
      simpl; intros;
      unfold AD_related_states, refines_related in *;
      cleanup; simpl in *.
      unfold refines, File.files_rep in *; simpl in *; cleanup.
      repeat invert_exec; destruct s0, s3; simpl in *; eauto;
        do 2 eexists; intuition eauto;
        do 2 eexists; intuition eauto.
    }
    2:{
      intros; unfold refines_related in *; cleanup.
      eapply_fresh get_owner_oracle_refines_exists in H; eauto.
      eapply_fresh get_owner_oracle_refines_exists in H0; eauto.
      cleanup.

      eapply_fresh ATCD_exec_lift_finished in H; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H0; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATCD_oracle_refines_impl_eq in H4; eauto.
      2: eapply have_same_structure_get_owner; eauto.
      2: apply TD_oracle_refines_operation_eq.
      cleanup.

      eapply lift2_invert_exec in H6;
      eapply lift2_invert_exec in H8; cleanup.
      apply map_ext_eq in H4; cleanup.
      2: intros; cleanup; intuition congruence.
      do 2 eexists; intuition eauto.

      unfold AD_related_states, refines_related in *;
      cleanup; simpl in *.
      unfold refines, File.files_rep, File.files_inner_rep in *; simpl in *; cleanup.

      eapply Inode.get_owner_finished in H12; eauto.
      2: rewrite H17; eauto.
      eapply Inode.get_owner_finished in H10; eauto.
      2: rewrite H13; eauto.
      cleanup.

      clear H10 H12. (* clear ors*)
      do 2 eexists; intuition eauto;
      eexists; intuition eauto;
      eexists; intuition eauto.
      all:eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto;
      intros; FileInnerSpecs.solve_bounds.
    }
    {
      simpl.
      unfold refines_related, FD_related_states in *; simpl in *; cleanup.

      eapply_fresh read_inner_oracle_refines_exists in H4; eauto.
      eapply_fresh read_inner_oracle_refines_exists in H6; eauto.
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H4; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H6; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.

      eapply lift2_invert_exec in H29;
      eapply lift2_invert_exec in H31; cleanup.

      eapply FileInnerSpecs.read_inner_finished in H34; eauto.
      eapply FileInnerSpecs.read_inner_finished in H36; eauto.
      cleanup.

      unfold HC_refines in *; cleanup; simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; logic_clean.

      clear H48 H52.
      repeat split; intros.
      eapply Forall_forall; intros.
      apply Transaction.dedup_last_in in H52.
      apply in_rev in H52.
      eapply Forall_forall in H37; eauto.

      eapply Forall_forall; intros.
      apply Transaction.dedup_last_in in H52.
      apply in_rev in H52.
      eapply Forall_forall in H38; eauto.

      edestruct dedup_by_list_length
        with (AEQ := addr_dec)
             (l1:= (rev (map fst (fst (snd s2'0)))))
             (l2:= (rev (map snd (fst (snd s2'0))))).

      repeat rewrite rev_length, map_length in *.
      pose proof (dedup_last_length addr_dec (rev (map fst (fst (snd s2'0))))).
      rewrite rev_length in *.
      apply addr_list_to_blocks_length_le_preserve in H88.
      eapply PeanoNat.Nat.le_trans.
      2: apply H47.
      apply PeanoNat.Nat.add_le_mono; eauto.

      edestruct dedup_by_list_length
        with (AEQ := addr_dec)
             (l1:= (rev (map fst (fst (snd s1'0)))))
             (l2:= (rev (map snd (fst (snd s1'0))))).

      repeat rewrite rev_length, map_length in *.
      pose proof (dedup_last_length addr_dec (rev (map fst (fst (snd s1'0))))).
      rewrite rev_length in *.
      apply addr_list_to_blocks_length_le_preserve in H88.
      eapply PeanoNat.Nat.le_trans.
      2: apply H51.
      apply PeanoNat.Nat.add_le_mono; eauto.
    }
    Unshelve.
    all: eauto.
  Qed.

Lemma ATCD_TS_DiskAllocator_read:
    forall n a1 a2 u u',
    (a1 < File.DiskAllocatorParams.num_of_blocks <-> a2 < File.DiskAllocatorParams.num_of_blocks) ->
    (File.DiskAllocatorParams.bitmap_addr + S a1 <
    data_length <->
    File.DiskAllocatorParams.bitmap_addr + S a2 <
    data_length) ->
    Termination_Sensitive u
  (Simulation.Definitions.compile
     ATCD_Refinement
     (@lift_L2 AuthenticationOperation _ TD _
     (File.DiskAllocator.read a1)))
  (Simulation.Definitions.compile
     ATCD_Refinement
     (@lift_L2 AuthenticationOperation _ TD _
     (File.DiskAllocator.read a2)))
  (Simulation.Definitions.compile
     ATCD_Refinement
     (Simulation.Definitions.compile
        FD.refinement
        (| Recover |)))
  (refines_valid ATCD_Refinement
     AD_valid_state)
  (fun s1 s2 => refines_related ATCD_Refinement
  (fun s1 s2  => exists s1a s2a,
  File.files_inner_rep s1a (fst (snd (snd s1))) /\
  File.files_inner_rep s2a (fst (snd (snd s2))) /\
  FD_related_states u' None s1a s2a) s1 s2 /\
  (forall a,
     Transaction.get_first (fst (snd s1)) a = None <->
     Transaction.get_first (fst (snd s2)) a = None) /\
  (Transaction.get_first (fst (snd s1)) (File.DiskAllocatorParams.bitmap_addr + S a1) = None <->
   Transaction.get_first (fst (snd s2)) (File.DiskAllocatorParams.bitmap_addr + S a2) = None) /\
   nth_error
            (value_to_bits
               (upd_batch (snd (snd s1)) (rev (map fst (fst (snd s1))))
               (rev (map snd (fst (snd s1)))) File.DiskAllocatorParams.bitmap_addr)) a1 =
               nth_error
            (value_to_bits
               (upd_batch (snd (snd s2)) (rev (map fst (fst (snd s2))))
               (rev (map snd (fst (snd s2)))) File.DiskAllocatorParams.bitmap_addr)) a2)
  (ATCD_reboot_list n).
  Proof.
    unfold File.DiskAllocator.read; intros.
    destruct (Compare_dec.lt_dec a1 File.DiskAllocatorParams.num_of_blocks);
    destruct (Compare_dec.lt_dec a2 File.DiskAllocatorParams.num_of_blocks);
    try lia.
    2: intros; apply ATCD_TS_ret.
    simpl.
    eapply ATCD_TS_compositional.

    intros; eapply TS_eqv_impl.
    eapply ATCD_TS_Transaction_read.
    shelve.
    intros; cleanup; eauto.
    2: intros; shelve.
    intros.
    eapply lift2_invert_exec in H1; cleanup.
    eapply lift2_invert_exec in H2; cleanup.
    unfold refines_related in *; simpl in *; cleanup.
    unfold HC_refines in *; simpl in *; cleanup.
    unfold TransactionToTransactionalDisk.Definitions.refines in *.
    eapply Transaction.read_finished in H8; eauto.
    eapply Transaction.read_finished in H9; eauto.
    cleanup; repeat split_ors; cleanup; try lia.
    unfold Transaction.transaction_rep in *; cleanup.
    setoid_rewrite H6.
    destruct_fresh (nth_error
    (value_to_bits
       (upd_batch (snd (snd s2)) (rev (map fst (fst (snd s2))))
          (rev (map snd (fst (snd s2))))
          File.DiskAllocatorParams.bitmap_addr)) a2); setoid_rewrite D.
    2: intros; apply ATCD_TS_ret.
    {
      destruct b.
      2: intros; apply ATCD_TS_ret.
      eapply ATCD_TS_compositional.
      2: intros; apply ATCD_TS_ret.
      intros; simpl; eapply ATCD_TS_Transaction_read; eauto.
      intros; shelve.
    }
    {
      edestruct (block_allocator_empty a1);
      edestruct (block_allocator_empty a2);
      cleanup; apply ATCD_TS_ret.
    }
    Unshelve.
    all: try solve [ exact (fun _ _ => True)].
    all: simpl; eauto.
    all: intuition.
    unfold File.DiskAllocatorParams.bitmap_addr.
    {
      eapply lift2_invert_exec in H1; cleanup.
      eapply lift2_invert_exec in H2; cleanup.
      unfold refines_related in *; simpl in *; cleanup.
      unfold HC_refines in *; simpl in *; cleanup.
      unfold TransactionToTransactionalDisk.Definitions.refines in *.
      eapply Transaction.read_finished in H5; eauto.
      eapply Transaction.read_finished in H12; eauto.
      cleanup; intuition.
    }
    {
      eapply lift2_invert_exec in H1; cleanup.
      eapply lift2_invert_exec in H2; cleanup.
      unfold refines_related in *; simpl in *; cleanup.
      unfold HC_refines in *; simpl in *; cleanup.
      unfold TransactionToTransactionalDisk.Definitions.refines in *.
      eapply Transaction.read_finished in H5; eauto.
      eapply Transaction.read_finished in H12; eauto.
      cleanup; intuition.
    }
  Qed.

  Lemma ATCD_TS_explicit_inode_map:
  forall n u u' inum off,
  (forall im1 im2,
  Termination_Sensitive u
  (Simulation.Definitions.compile ATCD_Refinement
  (@lift_L2 AuthenticationOperation _ TD _ (File.read_inner off inum)))
  (Simulation.Definitions.compile ATCD_Refinement
  (@lift_L2 AuthenticationOperation _ TD _ (File.read_inner off inum)))
    (Simulation.Definitions.compile ATCD_Refinement File.recover)
    (refines_valid ATCD_Refinement
     AD_valid_state)
     (refines_related ATCD_Refinement
     (fun s1 s2  => exists s1a s2a,
    (Inode.inode_rep im1 (fst (snd (snd s1))) /\
        (exists file_block_map : disk value,
            File.DiskAllocator.block_allocator_rep file_block_map
              (fst (snd (snd s1))) /\
            File.file_map_rep s1a im1 file_block_map)) /\
      (Inode.inode_rep im2 (fst (snd (snd s2))) /\
        (exists file_block_map : disk value,
            File.DiskAllocator.block_allocator_rep file_block_map
              (fst (snd (snd s2))) /\
            File.file_map_rep s2a im2 file_block_map)) /\
    FD_related_states u' None s1a s2a /\
    fst (snd s1) = Empty /\
    fst (snd s2) = Empty))
    (ATCD_reboot_list n)) ->

    Termination_Sensitive u
(Simulation.Definitions.compile ATCD_Refinement
(@lift_L2 AuthenticationOperation _ TD _ (File.read_inner off inum)))
(Simulation.Definitions.compile ATCD_Refinement
(@lift_L2 AuthenticationOperation _ TD _ (File.read_inner off inum)))
  (Simulation.Definitions.compile ATCD_Refinement File.recover)
(refines_valid ATCD_Refinement
     AD_valid_state)
(refines_related ATCD_Refinement
(fun s1 s2  => exists s1a s2a,
File.files_inner_rep s1a (fst (snd (snd s1))) /\
File.files_inner_rep s2a (fst (snd (snd s2))) /\
FD_related_states u' None s1a s2a /\
fst (snd s1) = Empty /\
  fst (snd s2) = Empty))
  (ATCD_reboot_list n) .
Proof.
unfold Termination_Sensitive; intros.
unfold refines_related, File.files_inner_rep in *.
cleanup.
eapply H.
3: eauto.
all: eauto.
do 2 eexists; intuition eauto.
do 2 eexists; intuition eauto.
Qed.

Lemma ATCD_TS_read_inner:
    forall n inum off u u',
    Termination_Sensitive u
  (Simulation.Definitions.compile
     ATCD_Refinement
     (@lift_L2 AuthenticationOperation _ TD _
     (File.read_inner off inum)))
  (Simulation.Definitions.compile
     ATCD_Refinement
     (@lift_L2 AuthenticationOperation _ TD _
     (File.read_inner off inum)))
  (Simulation.Definitions.compile
     ATCD_Refinement
     (Simulation.Definitions.compile
        FD.refinement
        (| Recover |)))
  (refines_valid ATCD_Refinement
     AD_valid_state)
  (refines_related ATCD_Refinement
  (fun s1 s2  => exists s1a s2a,
  File.files_inner_rep s1a (fst (snd (snd s1))) /\
  File.files_inner_rep s2a (fst (snd (snd s2))) /\
  FD_related_states u' None s1a s2a /\
  fst (snd s1) = Empty /\ fst (snd s2) = Empty))
  (ATCD_reboot_list n).
  Proof.
    Transparent File.read_inner.
    intros;
    eapply ATCD_TS_explicit_inode_map.
    intros; unfold File.read_inner.
    eapply ATCD_TS_compositional.
    intros; eapply TS_eqv_impl.
    eapply ATCD_TS_get_block_number.
    simpl; intros; shelve.
    2: intros; shelve.

    intros; unfold refines_related in *; cleanup.
      eapply_fresh get_block_number_oracle_refines_exists in H; eauto.
      eapply_fresh get_block_number_oracle_refines_exists in H0; eauto.
      cleanup.

      eapply_fresh ATCD_exec_lift_finished in H; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H0; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATCD_oracle_refines_impl_eq in H12; eauto.
      2: eapply have_same_structure_get_block_number; eauto.
      3: apply TD_oracle_refines_operation_eq.
      cleanup.

      eapply lift2_invert_exec in H14;
      eapply lift2_invert_exec in H16; cleanup.
      apply map_ext_eq in H12; cleanup.
      2: intros; cleanup; intuition congruence.

      unfold File.files_inner_rep in *; cleanup.
      eapply_fresh Inode.get_block_number_finished_oracle_eq in H20; eauto; subst.
      cleanup; destruct r1, r2; try solve [intuition congruence].
      2: intros; apply ATCD_TS_ret.

      eapply ATCD_TS_compositional.
      2: intros; destruct r1, r2; apply ATCD_TS_ret.
      2: intros; shelve.
      simpl; intros; repeat invert_exec; try congruence.
      eapply TS_eqv_impl.
      eapply ATCD_TS_DiskAllocator_read.
      {
        eapply Inode.get_block_number_finished in H20; eauto.
        eapply Inode.get_block_number_finished in H18; eauto.
        cleanup; repeat split_ors; cleanup; intuition eauto.
        eapply SameRetType.all_block_numbers_in_bound in H29.
        3: eauto.
        all: eauto.
        eapply Forall_forall in H29; eauto.
        apply in_seln; eauto.

        eapply SameRetType.all_block_numbers_in_bound in H10.
        3: eauto.
        all: eauto.
        eapply Forall_forall in H10; eauto.
        apply in_seln; eauto.
      }
      {
        eapply Inode.get_block_number_finished in H20; eauto.
        eapply Inode.get_block_number_finished in H18; eauto.

        cleanup; repeat split_ors; cleanup; intuition eauto.
      eapply data_block_inbounds; eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.

      eapply data_block_inbounds.
      4: eauto.
      all: eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.
      }
      {
        instantiate (2:= refines_related ATCD_Refinement
        (fun s1 s2  =>
        exists s1a s2a,
        (Inode.inode_rep im1 (fst (snd (snd s1))) /\
            (exists file_block_map,
                File.DiskAllocator.block_allocator_rep file_block_map
                  (fst (snd (snd s1))) /\
                File.file_map_rep s1a im1 file_block_map)) /\
          (Inode.inode_rep im2 (fst (snd (snd s2))) /\
            (exists file_block_map,
                File.DiskAllocator.block_allocator_rep file_block_map
                  (fst (snd (snd s2))) /\
                File.file_map_rep s2a im2 file_block_map)) /\
        FD_related_states u' None s1a s2a /\
        fst (snd s1) = Empty /\
        fst (snd s2) = Empty)).

         simpl; intros.
         unfold refines_related in *.
         cleanup.
         split.
         unfold File.files_inner_rep.
         do 2 eexists; intuition eauto.
         do 2 eexists; intuition eauto.

         simpl in *; unfold HC_refines in H12, H21; cleanup.
         simpl in *; unfold TransactionToTransactionalDisk.Definitions.refines,
         Transaction.transaction_rep  in *; cleanup;
         repeat split_ors; cleanup; try congruence.
        eapply txn_length_0_empty in H34;
        eapply txn_length_0_empty in H38; subst.
        setoid_rewrite H34;
        setoid_rewrite H38.
        simpl; intuition eauto.

        rewrite H38, H34 in *; simpl in *.
        eapply Inode.get_block_number_finished in H20; eauto.
        eapply Inode.get_block_number_finished in H18; eauto.
        cleanup; repeat split_ors; cleanup; intuition eauto.
        repeat erewrite TSCommon.used_blocks_are_allocated_2; eauto.
      }
      shelve.
      {
        unfold File.files_inner_rep in *; cleanup.
        do 2 eexists; intuition eauto.
      }

    Unshelve.
    all: eauto.
    {
      simpl.
      intros; unfold refines_related in *; cleanup.
      simpl in *.
      unfold File.files_inner_rep in *; cleanup.
      do 2 eexists; intuition eauto.
      do 2 eexists; intuition eauto.

      do 2 eexists; intuition eauto.

      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H14;
      setoid_rewrite H14.
      simpl; eauto.

      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H18;
      setoid_rewrite H18.
      simpl; eauto.
    }
    {
      simpl.
      intros; unfold refines_related in *; cleanup.
      eapply_fresh get_block_number_oracle_refines_exists in H; eauto.
      eapply_fresh get_block_number_oracle_refines_exists in H0; eauto.
      cleanup.

      eapply_fresh ATCD_exec_lift_finished in H; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H0; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATCD_oracle_refines_impl_eq in H12; eauto.
      2: eapply have_same_structure_get_block_number; eauto.
      3: apply TD_oracle_refines_operation_eq.
      cleanup.

      eapply lift2_invert_exec in H14;
      eapply lift2_invert_exec in H16; cleanup.
      apply map_ext_eq in H12; cleanup.
      2: intros; cleanup; intuition congruence.
      unfold File.files_inner_rep in *; cleanup.
      eapply Inode.get_block_number_finished in H20; eauto.
      eapply Inode.get_block_number_finished in H18; eauto.
      cleanup.
      clear H12 H20.
      do 2 eexists; intuition eauto.
      do 2 eexists; intuition eauto.

      eexists; intuition eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.

      eexists; intuition eauto.
      eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto.
      intros; FileInnerSpecs.solve_bounds.

      setoid_rewrite H26; eauto.
      setoid_rewrite H22; eauto.

      unfold File.files_inner_rep in *; cleanup.
      do 2 eexists; intuition eauto.
    }
    all: try solve [exact (fun _ _ => True)].
    all: simpl; eauto.
    {
      intros.
      match goal with
       | [H: _ ?inum = Some _,
          H0: _ ?inum = Some _ |- _] =>
       eapply_fresh FileInnerSpecs.inode_exists_then_file_exists in H; eauto; cleanup;
       eapply_fresh FileInnerSpecs.inode_exists_then_file_exists in H0; eauto; cleanup
       end.
       unfold FD_related_states,
       same_for_user_except in *; cleanup.
       match goal with
       | [H: ?fm1 ?inum = Some _,
          H0: ?fm2 ?inum = Some _,
          H1: forall (_: addr) (_ _: File),
           ?fm1 _ = Some _ ->
           ?fm2 _ = Some _ ->
           _ = _ /\ _ = _ |- _] =>
           eapply_fresh H1 in H; eauto; cleanup
      end.
       unfold File.file_map_rep in *; cleanup.
       match goal with
       | [H: ?x1 ?inum = Some _,
          H0: ?x2 ?inum = Some _,
          H1: forall (_: Inode.Inum) _ _,
          ?x1 _ = Some _ ->
          _ _ = Some _ -> _,
          H2: forall (_: Inode.Inum) _ _,
          ?x2 _ = Some _ ->
          _ _ = Some _ -> _ |- _] =>
          eapply H1 in H; eauto; cleanup;
          eapply H2 in H0; eauto; cleanup
       end.
       unfold File.file_rep in *; cleanup; eauto.
    }
    Unshelve.
    all: eauto.
  Qed.
    Opaque File.read_inner.

    Lemma ATCD_TS_read:
    forall n inum off u u',
    Termination_Sensitive u
  (Simulation.Definitions.compile
     ATCD_Refinement
     (Simulation.Definitions.compile
        FD.refinement
        (| Read inum off |)))
  (Simulation.Definitions.compile
     ATCD_Refinement
     (Simulation.Definitions.compile
        FD.refinement
        (| Read inum off |)))
  (Simulation.Definitions.compile
     ATCD_Refinement
     (Simulation.Definitions.compile
        FD.refinement
        (| Recover |)))
  (refines_valid ATCD_Refinement
     AD_valid_state)
  (refines_related ATCD_Refinement
     (AD_related_states u' None))
  (ATCD_reboot_list n).
  Proof.
    intros; simpl.
    eapply ATCD_TS_compositional.
    {
      intros; eapply TS_eqv_impl.
      eapply ATCD_TS_get_owner.
      unfold refines_related, AD_related_states;
      simpl. unfold refines_related; simpl.
      unfold refines, File.files_rep; simpl.
      intros; cleanup; intuition eauto.
      do 2 eexists; intuition eauto.
      rewrite H4, H6;
      do 2 eexists; intuition eauto.
      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H12;
      setoid_rewrite H12.
      simpl; eauto.

      unfold HC_refines in *; cleanup.
      simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; simpl in *; cleanup.
      repeat split_ors; cleanup; try congruence.
      eapply txn_length_0_empty in H16;
      setoid_rewrite H16.
      simpl; eauto.
    }
    {
      intros; unfold refines_related in *; cleanup.
      eapply_fresh get_owner_oracle_refines_exists in H; eauto.
      eapply_fresh get_owner_oracle_refines_exists in H0; eauto.
      cleanup.

      eapply_fresh ATCD_exec_lift_finished in H; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H0; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATCD_oracle_refines_impl_eq in H4; eauto.
      2: eapply have_same_structure_get_owner; eauto.
      2: apply TD_oracle_refines_operation_eq.
      cleanup.

      eapply lift2_invert_exec in H6;
      eapply lift2_invert_exec in H8; cleanup.
      apply map_ext_eq in H4; cleanup.
      2: intros; cleanup; intuition congruence.

      eapply_fresh get_owner_related_ret_eq in H10; eauto; subst.
      destruct r2.
      2: intros; apply ATCD_TS_abort_then_ret.

      eapply ATCD_TS_compositional.
      intros; apply ATCD_TS_auth.
      2: shelve.
      simpl; intros; repeat invert_exec; try congruence.
      2: intros; apply ATCD_TS_abort_then_ret.
      eapply ATCD_TS_compositional.
      intros; eapply ATCD_TS_read_inner.
      intros.
      {
        instantiate (1:= refines_related ATCD_Refinement
        (fun s3 s4 : state AD =>
         exists s1a s2a : disk File,
           File.files_inner_rep s1a (fst (snd (snd s3))) /\
           File.files_inner_rep s2a (fst (snd (snd s4))) /\
           FD_related_states u' None s1a s2a /\
           fst (snd s3) = Empty /\ fst (snd s4) = Empty)) in H13; simpl in *; cleanup.
        unfold refines_related, FD_related_states in *; simpl in *; cleanup.

      eapply_fresh read_inner_oracle_refines_exists in H4; eauto.
      eapply_fresh read_inner_oracle_refines_exists in H6; eauto.
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H4; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H6; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.

      eapply lift2_invert_exec in H22;
      eapply lift2_invert_exec in H24; cleanup.

      eapply ATCD_oracle_refines_impl_eq in H21.
      2: apply H20.
      all: simpl in *; eauto.
      2: apply TD_oracle_refines_operation_eq.
      apply map_ext_eq in H21; cleanup.
      2: intros; cleanup; intuition congruence.
      eapply SameRetType.read_inner_finished_oracle_eq in H27.
      2: apply H29.
      all: eauto.
      cleanup.
      destruct r1, r2; try solve [intuition congruence].
      intros; apply ATCD_TS_commit_then_ret.
      intros; apply ATCD_TS_abort_then_ret.
      eapply have_same_structure_read_inner; eauto.
      do 2 eexists; intuition eauto.
      unfold FD_related_states;
      apply TSCommon.same_for_user_except_symmetry; eauto.
      apply not_init_read_inner.
      apply not_init_read_inner.
      }
      intros; shelve.
    }
    intros; shelve.
    Unshelve.
    all: try exact u'.
    all: eauto.
    all: try solve [exact (fun _ _ => True)].
    all: try solve [simpl; eauto].
    {
      simpl; intros;
      unfold AD_related_states, refines_related in *;
      cleanup; simpl in *.
      unfold refines, File.files_rep in *; simpl in *; cleanup.
      repeat invert_exec; destruct s0, s3; simpl in *; eauto;
        do 2 eexists; intuition eauto;
        do 2 eexists; intuition eauto.
    }
    2:{
      intros; unfold refines_related in *; cleanup.
      eapply_fresh get_owner_oracle_refines_exists in H; eauto.
      eapply_fresh get_owner_oracle_refines_exists in H0; eauto.
      cleanup.

      eapply_fresh ATCD_exec_lift_finished in H; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H0; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.
      eapply ATCD_oracle_refines_impl_eq in H4; eauto.
      2: eapply have_same_structure_get_owner; eauto.
      2: apply TD_oracle_refines_operation_eq.
      cleanup.

      eapply lift2_invert_exec in H6;
      eapply lift2_invert_exec in H8; cleanup.
      apply map_ext_eq in H4; cleanup.
      2: intros; cleanup; intuition congruence.
      do 2 eexists; intuition eauto.

      unfold AD_related_states, refines_related in *;
      cleanup; simpl in *.
      unfold refines, File.files_rep, File.files_inner_rep in *; simpl in *; cleanup.

      eapply Inode.get_owner_finished in H12; eauto.
      2: rewrite H17; eauto.
      eapply Inode.get_owner_finished in H10; eauto.
      2: rewrite H13; eauto.
      cleanup.

      clear H10 H12. (* clear ors*)
      do 2 eexists; intuition eauto;
      eexists; intuition eauto;
      eexists; intuition eauto.
      all:eapply File.DiskAllocator.block_allocator_rep_inbounds_eq; eauto;
      intros; FileInnerSpecs.solve_bounds.
    }
    {
      simpl.
      unfold refines_related, FD_related_states in *; simpl in *; cleanup.

      eapply_fresh read_inner_oracle_refines_exists in H4; eauto.
      eapply_fresh read_inner_oracle_refines_exists in H6; eauto.
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H4; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      eapply_fresh ATCD_exec_lift_finished in H6; eauto;
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_finished];
      try solve [apply TransactionToTransactionalDisk.Refinement.TC_to_TD_core_simulation_crashed].
      cleanup.
      simpl in *.

      eapply lift2_invert_exec in H29;
      eapply lift2_invert_exec in H31; cleanup.

      eapply FileInnerSpecs.read_inner_finished in H34; eauto.
      eapply FileInnerSpecs.read_inner_finished in H36; eauto.
      cleanup.

      unfold HC_refines in *; cleanup; simpl in *.
      unfold TransactionToTransactionalDisk.Definitions.refines,
      Transaction.transaction_rep in *; logic_clean.

      clear H48 H52.
      repeat split; intros.
      eapply Forall_forall; intros.
      apply Transaction.dedup_last_in in H52.
      apply in_rev in H52.
      eapply Forall_forall in H37; eauto.

      eapply Forall_forall; intros.
      apply Transaction.dedup_last_in in H52.
      apply in_rev in H52.
      eapply Forall_forall in H38; eauto.

      edestruct dedup_by_list_length
        with (AEQ := addr_dec)
             (l1:= (rev (map fst (fst (snd s2'0)))))
             (l2:= (rev (map snd (fst (snd s2'0))))).

      repeat rewrite rev_length, map_length in *.
      pose proof (dedup_last_length addr_dec (rev (map fst (fst (snd s2'0))))).
      rewrite rev_length in *.
      apply addr_list_to_blocks_length_le_preserve in H88.
      eapply PeanoNat.Nat.le_trans.
      2: apply H47.
      apply PeanoNat.Nat.add_le_mono; eauto.

      edestruct dedup_by_list_length
        with (AEQ := addr_dec)
             (l1:= (rev (map fst (fst (snd s1'0)))))
             (l2:= (rev (map snd (fst (snd s1'0))))).

      repeat rewrite rev_length, map_length in *.
      pose proof (dedup_last_length addr_dec (rev (map fst (fst (snd s1'0))))).
      rewrite rev_length in *.
      apply addr_list_to_blocks_length_le_preserve in H88.
      eapply PeanoNat.Nat.le_trans.
      2: apply H51.
      apply PeanoNat.Nat.add_le_mono; eauto.
    }
    Unshelve.
    all: eauto.
  Qed.
*)


(* seplog (c) AIST 2005-2013. R. Affeldt, N. Marti, et al. GNU GPLv3. *)
(* seplog (c) AIST 2014-2018. R. Affeldt et al. GNU GPLv3. *)
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Require Import Init_ext ssrZ ZArith_ext uniq_tac machine_int multi_int.
Require Import encode_decode integral_type.
Import MachineInt.
Require Import mips_bipl mips_seplog mips_tactics mips_syntax mips_mint.
Import mips_bipl.expr_m.
Require Import simu.
Import simu.simu_m.
Require Import copy_u_u_prg copy_u_u_triple copy_u_u_termination.

Local Open Scope machine_int_scope.
Local Open Scope heap_scope.
Local Open Scope assoc_scope.
Local Open Scope uniq_scope.
Local Open Scope asm_expr_scope.
Local Open Scope asm_cmd_scope.
Local Open Scope zarith_ext_scope.

Lemma copy_u_u_safe_termination a0 a1 a2 rk rx x ru u d :
  uniq(x, u) -> uniq(rk, rx, ru, a0, a1, a2, r0) ->
  safe_termination
  (state_mint (x |=> unsign rk rx \U+ (u |=> unsign rk ru \U+ d)))
  (copy_u_u rk rx ru a0 a1 a2).
Proof.
move=> Hvars Hregs.
rewrite /safe_termination.
move=> s st h s_st_h.
set code := copy_u_u _ _ _ _ _ _.
move: (proj1 s_st_h x (unsign rk rx)).
rewrite assoc.get_union_sing_eq.
case/(_ Logic.eq_refl) => rx_fit x_rk Hx.
move: (proj1 s_st_h u (unsign rk ru)).
rewrite assoc.get_union_sing_neq; last by Uniq_neq.
rewrite assoc.get_union_sing_eq.
case/(_ Logic.eq_refl) => ru_fit u_rk Hu.
case: (copy_u_u_termination st h _ _ _ _ _ _ Hregs) => si Hsi.
move: (copy_u_u_triple _ _ _ _ _ _ Hregs
  (Z2ints 32 '|u2Z ([rk ]_ st)| ([u ]_ s)%pseudo_expr)
  (Z2ints 32 '|u2Z ([rk ]_ st)| ([x ]_ s)%pseudo_expr)
  '|u2Z ([rk ]_ st)|).
rewrite 2!size_Z2ints.
move/(_ erefl erefl _ rx_fit) => hoare_triple.
apply constructive_indefinite_description'.
move: (triple_exec_precond _ _ _ hoare_triple _ _ _ Hsi (heap.dom (heap_mint (unsign rk ru) st h \U heap_mint (unsign rk rx) st h))).
apply.
split => //.
split.
  rewrite Z_of_nat_Zabs_nat //; exact/min_u2Z.
suff : h |P|
        heap.dom
           (heap_mint (unsign rk ru) st h \U heap_mint (unsign rk rx) st h) =
heap_mint (unsign rk ru) st h \U heap_mint (unsign rk rx) st h.
  move=> ->.
  apply assert_m.con_cons => //.
  apply (proj2 s_st_h u x) => //.
  by Uniq_neq.
  rewrite assoc.get_union_sing_neq; last by Uniq_neq.
  by rewrite assoc.get_union_sing_eq.
  by rewrite assoc.get_union_sing_eq.
rewrite -heap.incluE.
apply heap_prop_m.inclu_union; by apply heap_inclu_heap_mint_unsign.
Qed.


From iris.program_logic Require Export weakestpre.
From iris.base_logic Require Import invariants lib.saved_prop.
From iris.heap_lang Require Export lang.
From iris.heap_lang Require Import proofmode.
From iris.algebra Require Import auth gset.
From iris_examples.barrier Require Export barrier.
Set Default Proof Using "Type".

(** The CMRAs/functors we need. *)
Class barrierG Σ := BarrierG {
  barrier_inG :> inG Σ (authR (gset_disjUR gname));
  barrier_savedPropG :> savedPropG Σ;
}.
Definition barrierΣ : gFunctors :=
  #[ GFunctor (authRF (gset_disjUR gname)); savedPropΣ ].

Instance subG_barrierΣ {Σ} : subG barrierΣ Σ → barrierG Σ.
Proof. solve_inG. Qed.

(** Now we come to the Iris part of the proof. *)
Section proof.
Context `{!heapG Σ, !barrierG Σ} (N : namespace).

Definition barrier_inv (l : loc) (γ : gname) (P : iProp Σ) : iProp Σ :=
  (∃ (b : bool) (γsps : gset gname),
    l ↦ #b ∗
    own γ (● (GSet γsps)) ∗
    ((if b then True else P) -∗
      ([∗ set] γsp ∈ γsps, ∃ R, saved_prop_own γsp R ∗ ▷ R)))%I.

Definition recv (l : loc) (R : iProp Σ) : iProp Σ :=
  (∃ γ P R' γsp,
    inv N (barrier_inv l γ P) ∗
    ▷ (R' -∗ R) ∗
    own γ (◯ GSet {[ γsp ]}) ∗
    saved_prop_own γsp R')%I.

Definition send (l : loc) (P : iProp Σ) : iProp Σ :=
  (∃ γ, inv N (barrier_inv l γ P))%I.

(** Setoids *)
Instance barrier_inv_ne l γ : NonExpansive (barrier_inv l γ).
Proof. solve_proper. Qed.
Global Instance send_ne l : NonExpansive (send l).
Proof. solve_proper. Qed.
Global Instance recv_ne l : NonExpansive (recv l).
Proof. solve_proper. Qed.

(** Actual proofs *)
Lemma newbarrier_spec (P : iProp Σ) :
  {{{ True }}} newbarrier #() {{{ l, RET #l; recv l P ∗ send l P }}}.
Proof.
  iIntros (Φ) "_ HΦ". iApply wp_fupd. wp_lam. wp_alloc l as "Hl".
  iApply ("HΦ" with "[> -]").
  iMod (saved_prop_alloc P) as (γsp) "#Hsp".
  iMod (own_alloc (● GSet {[ γsp ]} ⋅ ◯ GSet {[ γsp ]})) as (γ) "[H● H◯]".
  { by apply auth_both_valid. }
  iMod (inv_alloc N _ (barrier_inv l γ P) with "[Hl H●]") as "#Hinv".
  { iExists false, {[ γsp ]}. iIntros "{$Hl $H●} !> HP".
    rewrite big_sepS_singleton; eauto. }
  iModIntro; iSplitL "H◯".
  - iExists γ, P, P, γsp. iFrame; auto.
  - by iExists γ.
Qed.

Lemma signal_spec l P :
  {{{ send l P ∗ P }}} signal #l {{{ RET #(); True }}}.
Proof.
  iIntros (Φ) "[Hs HP] HΦ". iDestruct "Hs" as (γ) "#Hinv". wp_lam.
  iInv N as ([] γsps) "(>Hl & H● & HRs)".
  { wp_store. iModIntro. iSplitR "HΦ"; last by iApply "HΦ".
    iExists true, γsps. iFrame. }
  wp_store. iDestruct ("HRs" with "HP") as "HRs".
  iModIntro. iSplitR "HΦ"; last by iApply "HΦ".
  iExists true, γsps. iFrame; eauto.
Qed.

Lemma wait_spec l P:
  {{{ recv l P }}} wait #l {{{ RET #(); P }}}.
Proof.
  rename P into R.
  iIntros (Φ) "HR HΦ". iDestruct "HR" as (γ P R' γsp) "(#Hinv & HR & H◯ & #Hsp)".
  iLöb as "IH". wp_rec. wp_bind (! _)%E.
  iInv N as ([] γsps) "(>Hl & >H● & HRs)"; last first.
  { wp_load. iModIntro. iSplitL "Hl H● HRs".
    { iExists false, γsps. iFrame. }
    by wp_apply ("IH" with "[$] [$]"). }
  iSpecialize ("HRs" with "[//]"). wp_load.
  iDestruct (own_valid_2 with "H● H◯")
    as %[Hvalid%gset_disj_included%elem_of_subseteq_singleton _]%auth_both_valid.
  iDestruct (big_sepS_delete with "HRs") as "[HR'' HRs]"; first done.
  iDestruct "HR''" as (R'') "[#Hsp' HR'']".
  iDestruct (saved_prop_agree with "Hsp Hsp'") as "#Heq".
  iMod (own_update_2 with "H● H◯") as "H●".
  { apply (auth_update_dealloc _ _ (GSet (γsps ∖ {[ γsp ]}))).
    apply gset_disj_dealloc_local_update. }
  iIntros "!>". iSplitL "Hl H● HRs".
  { iDestruct (bi.later_intro with "HRs") as "HRs".
    iModIntro. iExists true, (γsps ∖ {[ γsp ]}). iFrame; eauto. }
  wp_if. iApply "HΦ". iApply "HR". by iRewrite "Heq".
Qed.

Lemma recv_split E l P1 P2 :
  ↑N ⊆ E → recv l (P1 ∗ P2) ={E}=∗ recv l P1 ∗ recv l P2.
Proof.
  rename P1 into R1; rename P2 into R2.
  iIntros (?). iDestruct 1 as (γ P R' γsp) "(#Hinv & HR & H◯ & #Hsp)".
  iInv N as (b γsps) "(>Hl & >H● & HRs)".
  iDestruct (own_valid_2 with "H● H◯")
    as %[Hvalid%gset_disj_included%elem_of_subseteq_singleton _]%auth_both_valid.
  iMod (own_update_2 with "H● H◯") as "H●".
  { apply (auth_update_dealloc _ _ (GSet (γsps ∖ {[ γsp ]}))).
    apply gset_disj_dealloc_local_update. }
  set (γsps' := γsps ∖ {[γsp]}).
  iMod (saved_prop_alloc_cofinite γsps' R1) as (γsp1 Hγsp1) "#Hsp1".
  iMod (saved_prop_alloc_cofinite (γsps' ∪ {[ γsp1 ]}) R2)
    as (γsp2 [? ?%not_elem_of_singleton]%not_elem_of_union) "#Hsp2".
  iMod (own_update _ _ (● _ ⋅ (◯ GSet {[ γsp1 ]} ⋅ ◯ (GSet {[ γsp2 ]})))
    with "H●") as "(H● & H◯1 & H◯2)".
  { rewrite -auth_frag_op gset_disj_union; last set_solver.
    apply auth_update_alloc, (gset_disj_alloc_empty_local_update _ {[ γsp1; γsp2 ]}).
    set_solver. }
  iModIntro. iSplitL "HR Hl HRs H●".
  { iModIntro. iExists b, ({[γsp1; γsp2]} ∪ γsps').
    iIntros "{$Hl $H●} HP". iSpecialize ("HRs" with "HP").
    iDestruct (big_sepS_delete with "HRs") as "[HR'' HRs]"; first done.
    iDestruct "HR''" as (R'') "[#Hsp' HR'']".
    iDestruct (saved_prop_agree with "Hsp Hsp'") as "#Heq".
    iAssert (▷ R')%I with "[HR'']" as "HR'"; [iNext; by iRewrite "Heq"|].
    iDestruct ("HR" with "HR'") as "[HR1 HR2]".
    iApply big_sepS_union; [set_solver|iFrame "HRs"].
    iApply big_sepS_union; [set_solver|].
    iSplitL "HR1"; rewrite big_sepS_singleton; eauto. }
  iModIntro; iSplitL "H◯1".
  - iExists γ, P, R1, γsp1. iFrame; auto.
  - iExists γ, P, R2, γsp2. iFrame; auto.
Qed.

Lemma recv_weaken l P1 P2 : (P1 -∗ P2) -∗ recv l P1 -∗ recv l P2.
Proof.
  iIntros "HP". iDestruct 1 as (γ P R' i) "(#Hinv & HR & H◯)".
  iExists γ, P, R', i. iIntros "{$Hinv $H◯} !> HQ". iApply "HP". by iApply "HR".
Qed.

Lemma recv_mono l P1 P2 : (P1 ⊢ P2) → recv l P1 ⊢ recv l P2.
Proof. iIntros (HP) "H". iApply (recv_weaken with "[] H"). iApply HP. Qed.
End proof.

Typeclasses Opaque send recv.


Require Import VST.floyd.proofauto.
Require Import VST.progs.minexample.
Instance CompSpecs : compspecs. make_compspecs prog. Defined.
Definition Vprog : varspecs. mk_varspecs prog. Defined.

Definition minexample_spec : ident * funspec :=
 DECLARE _minexample
 WITH a: val, b: val, c: val, d: val, sh : share
 PRE []
   PROP  ()
   LOCAL ()
   SEP   (data_at sh tint Vzero a;
          data_at sh tint Vzero a -* data_at sh tint Vzero b)
  POST [ tint ]
    PROP()
    LOCAL (temp ret_temp Vzero)
    SEP ().

Definition Gprog : funspecs :=
        ltac:(with_library prog [minexample_spec]).

Lemma body_minexample : semax_body Vprog Gprog f_minexample minexample_spec.
Proof.
  start_function.
  (* pattern-accepting behavior: *)
  Fail
    (gather_SEP
       (data_at sh tint Vzero a)
       (data_at sh tint Vzero a -* data_at sh tint Vzero b)).
  (* equivalent numerical behavior: *)
  gather_SEP 0 1.
Abort.