Definition inj_on_list {A B} (l : list A) (f : A -> B) :=
  forall x y, In x l -> In y l -> f x = f y -> x = y.Definition subset_rel {X} (sub lst : list X) : Prop :=
  forall x,
    In x sub ->
    In x lst.

(* Specifications: *)
Lemma NoDup_disjointness_1: forall {A} (l1 l2 : list A), NoDup l1 -> NoDup l2 -> disjoint_list l1 l2 -> NoDup (l1 ++ l2).
Lemma NoDup_disjointness: forall {A B} (l1 : list A) (l2 : list A) (f : A -> B) , NoDup (List.map f l1) -> NoDup (List.map f l2) -> disjoint_list (List.map f l1) (List.map f l2) -> NoDup (List.map f (l1 ++ l2)).
Lemma NoDup_app_disj : forall {A} (l1 l2 : list A), NoDup (l1 ++ l2) -> disjoint_list l1 l2.
Lemma NoDup_app_remove_mid : forall (A : Type) (l2 l1 l3 : list A) , NoDup (l1 ++ l2 ++ l3) -> NoDup (l1 ++ l3).
Lemma NoDup_takeL {A} : forall n (l : list A), NoDup l -> NoDup (takeL n l).
Lemma NoDup_map_inj {A B} : forall (f : A -> B) l, NoDup (List.map f l) -> inj_on_list l f.
Lemma remove_aux_removed {A} `{EqDec A} : forall (lst : list A) (a : A), NoDup lst -> ~ In a (remove_aux eqb lst a).
Lemma NoDup_remove_aux_general {A} `{EqDec A} : forall lst b, NoDup lst -> NoDup (remove_aux eqb lst b).
Lemma remove_list_sub_removed {A} `{EqDec A} : forall dlt lst b, NoDup lst -> In b (remove_list_sub eqb dlt lst) -> ~ In b dlt.
Lemma NoDup_remove_aux : forall lst x, NoDup (List.map block_blockid lst) -> NoDup (List.map block_blockid (remove_aux eqb lst x)).
Lemma up_oram_tr_tree_or_delta o : forall id lvl dlt p, In id (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p))) -> In id (List.map block_blockid (get_all_blks_tree o)) \/ In id (List.map block_blockid dlt).
Lemma NoDup_up_oram_tree : forall o dlt lvl p, NoDup (List.map block_blockid dlt) -> NoDup (List.map block_blockid (get_all_blks_tree o)) -> disjoint_list (List.map block_blockid (get_all_blks_tree o)) (List.map block_blockid dlt) -> NoDup (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p))).
Lemma NoDup_remove_list_sub : forall (dlt lst : list block), NoDup (List.map block_blockid lst) -> NoDup (List.map block_blockid (remove_list_sub eqb dlt lst)).
Lemma subset_rel_get_cand_bs : forall `{C :Config} lst p lvl pos_map, subset_rel (get_cand_bs lst p lvl pos_map) lst.
Lemma NoDup_get_write_back_blocks : forall `{C : Config} lst p lvl pos_map, NoDup (List.map block_blockid lst) -> NoDup (List.map block_blockid (get_write_back_blocks p lst 4 lvl pos_map)).
Lemma disjoint_dlt : forall o lvl dlt lst p, NoDup (List.map block_blockid lst) -> subset_rel dlt lst -> disjoint_list (List.map block_blockid (get_all_blks_tree o)) (List.map block_blockid lst) -> disjoint_list (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p))) (List.map block_blockid (remove_list_sub eqb dlt lst)).
Lemma NoDup_disjointness_1: forall {A} (l1 l2 : list A), NoDup l1 -> NoDup l2 -> disjoint_list l1 l2 -> NoDup (l1 ++ l2).
Lemma NoDup_disjointness: forall {A B} (l1 : list A) (l2 : list A) (f : A -> B) , NoDup (List.map f l1) -> NoDup (List.map f l2) -> disjoint_list (List.map f l1) (List.map f l2) -> NoDup (List.map f (l1 ++ l2)).
Lemma NoDup_app_disj : forall {A} (l1 l2 : list A), NoDup (l1 ++ l2) -> disjoint_list l1 l2.
Lemma NoDup_app_remove_mid : forall (A : Type) (l2 l1 l3 : list A) , NoDup (l1 ++ l2 ++ l3) -> NoDup (l1 ++ l3).
Lemma NoDup_takeL {A} : forall n (l : list A), NoDup l -> NoDup (takeL n l).
Lemma NoDup_map_inj {A B} : forall (f : A -> B) l, NoDup (List.map f l) -> inj_on_list l f.
Lemma remove_aux_removed {A} `{EqDec A} : forall (lst : list A) (a : A), NoDup lst -> ~ In a (remove_aux eqb lst a).
Lemma NoDup_remove_aux_general {A} `{EqDec A} : forall lst b, NoDup lst -> NoDup (remove_aux eqb lst b).
Lemma remove_list_sub_removed {A} `{EqDec A} : forall dlt lst b, NoDup lst -> In b (remove_list_sub eqb dlt lst) -> ~ In b dlt.
Lemma NoDup_remove_aux : forall lst x, NoDup (List.map block_blockid lst) -> NoDup (List.map block_blockid (remove_aux eqb lst x)).
Lemma up_oram_tr_tree_or_delta o : forall id lvl dlt p, In id (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p))) -> In id (List.map block_blockid (get_all_blks_tree o)) \/ In id (List.map block_blockid dlt).
Lemma NoDup_up_oram_tree : forall o dlt lvl p, NoDup (List.map block_blockid dlt) -> NoDup (List.map block_blockid (get_all_blks_tree o)) -> disjoint_list (List.map block_blockid (get_all_blks_tree o)) (List.map block_blockid dlt) -> NoDup (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p))).
Lemma NoDup_remove_list_sub : forall (dlt lst : list block), NoDup (List.map block_blockid lst) -> NoDup (List.map block_blockid (remove_list_sub eqb dlt lst)).
Lemma subset_rel_get_cand_bs : forall `{C :Config} lst p lvl pos_map, subset_rel (get_cand_bs lst p lvl pos_map) lst.
Lemma NoDup_get_write_back_blocks : forall `{C : Config} lst p lvl pos_map, NoDup (List.map block_blockid lst) -> NoDup (List.map block_blockid (get_write_back_blocks p lst 4 lvl pos_map)).
Lemma disjoint_dlt : forall o lvl dlt lst p, NoDup (List.map block_blockid lst) -> subset_rel dlt lst -> disjoint_list (List.map block_blockid (get_all_blks_tree o)) (List.map block_blockid lst) -> disjoint_list (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p))) (List.map block_blockid (remove_list_sub eqb dlt lst)).