Definition on_path b o p :=
    In b (concat (lookup_path_oram o p)).

(* Specifications: *)
Lemma block_dec (b : block) bs : In b bs \/ ~ In b bs.
Lemma on_path_dec b o : forall p, on_path b o p \/ ~ on_path b o p.
Lemma pos_map_stable_across_wb : forall n p s start, state_position_map s = state_position_map (write_back_r start p n s).
Lemma calc_path_pos_map_same : forall id s s', state_position_map s = state_position_map s' -> calc_path id s = calc_path id s'.
Lemma in_clear_path b o : forall p p', In b (concat (lookup_path_oram o p)) -> ~ In b (concat (lookup_path_oram o p')) -> In b (concat (lookup_path_oram (clear_path o p') p)).
Lemma get_pre_wb_st_Read_state_state : forall (id id' : block_id) (v : nat) (s : state) (p_new : path), blk_in_state id v s -> blk_in_state id v ((get_pre_wb_st id' Read s (calc_path id' s) p_new)).
Lemma get_pre_wb_st_Write_state_state : forall (id id' : block_id) (v v': nat) (s : state) (p_new : path), id <> id' -> blk_in_state id v s -> blk_in_state id v ((get_pre_wb_st id' (Write v') s (calc_path id' s) p_new)).
Lemma In_path_in_tree_block : forall o p b, In b (concat (lookup_path_oram o p)) -> In b (get_all_blks_tree o).
Lemma NoDup_tree_id_same_v: forall id v v' l, NoDup (List.map block_blockid l) -> In (Block id v) l -> In (Block id v') l -> v = v'.
Lemma In_tree_in_path : forall s id v, well_formed s -> In (Block id v) (get_all_blks_tree (state_oram s)) -> blk_in_path id v s.
Lemma blk_in_p_nil_Some id v o1 o2 data : blk_in_p id v (node (Some data) o1 o2) [] -> In (Block id v) data.
Lemma blk_in_p_nil_None id v o1 o2 : ~ blk_in_p id v (node None o1 o2) [].
Lemma blk_in_p_cons_true id v o1 o2 p data : blk_in_p id v o1 p -> blk_in_p id v (node data o1 o2) (true :: p).
Lemma blk_in_p_cons_false id v o1 o2 p data : blk_in_p id v o2 p -> blk_in_p id v (node data o1 o2) (false :: p).
Lemma blk_in_p_true_Some id v o1 o2 p data : blk_in_p id v (node (Some data) o1 o2) (true :: p) -> In (Block id v) data \/ blk_in_p id v o1 p.
Lemma blk_in_p_true_None id v o1 o2 p : blk_in_p id v (node None o1 o2) (true :: p) -> blk_in_p id v o1 p.
Lemma blk_in_p_false_Some id v o1 o2 p data : blk_in_p id v (node (Some data) o1 o2) (false :: p) -> In (Block id v) data \/ blk_in_p id v o2 p.
Lemma blk_in_p_false_None id v o1 o2 p : blk_in_p id v (node None o1 o2) (false :: p) -> blk_in_p id v o2 p.
Lemma blk_in_p_clear_path: forall o p p_new id v, blk_in_p id v (clear_path o p) p_new -> blk_in_p id v o p_new.
Lemma stash_path_combined_rel_Rd_undef : forall (id id' : block_id) (s : state) (p_new : path), well_formed s -> undef id s -> undef id ((get_pre_wb_st id' Read s (calc_path id' s) p_new)).
Lemma stash_path_combined_rel_Wr_undef : forall (id id' : block_id) (v : nat) (s : state) (p_new : path), id <> id' -> well_formed s -> undef id' s -> undef id' ((get_pre_wb_st id (Write v) s (calc_path id s) p_new)).
Lemma get_pre_wb_st_Write_stsh : forall (id : block_id) (v : nat) (s : state) (p_new : path), blk_in_stash id v ((get_pre_wb_st id (Write v) s (calc_path id s) p_new)).
Lemma calc_path_write_bk_r_stable : forall start id s n p , calc_path id (write_back_r start p n s) = calc_path id s.
Lemma path_conversion : forall o lvl p p' b, isEqvPath p p' lvl = true -> at_lvl_in_path o lvl p b -> at_lvl_in_path o lvl p' b.
Lemma locate_comp_block_selection : forall o p p' lvl lvl' dlt, (lvl < lvl')%nat -> locate_node_in_tr (up_oram_tr o lvl dlt p') lvl' p = locate_node_in_tr o lvl' p.
Lemma at_lvl_in_path_blocks_selection : forall s p p' lvl lvl' b, (lvl < lvl')%nat -> at_lvl_in_path (state_oram s) lvl' p b -> at_lvl_in_path (state_oram (blocks_selection p' lvl s)) lvl' p b.
Lemma kv_in_delta_in_tree : forall (o : oram) (id : block_id) (v : nat) (del : list block) (lvl: nat )(p :path), In (Block id v) del -> coord_in_bound o p lvl -> at_lvl_in_path (up_oram_tr o lvl del p) lvl p (Block id v).
Lemma path_eq_get_cand_bs : forall id v h p stop m, In (Block id v) (get_cand_bs h p stop m) -> isEqvPath p (lookup_dict (makeBoolList false LOP) id m) stop = true.
Lemma stash_block_selection : forall p s id v lvl, well_formed s -> length p = LOP -> Nat.le lvl LOP -> blk_in_stash id v s -> blk_in_stash id v (blocks_selection p lvl s) \/ (at_lvl_in_path (state_oram (blocks_selection p lvl s)) lvl p (Block id v) /\ at_lvl_in_path (state_oram (blocks_selection p lvl s)) lvl (calc_path id s) (Block id v) ).
Lemma up_oram_tr_preserves_pb : forall o lvl dlt p n, is_p_b_tr o n -> is_p_b_tr (up_oram_tr o lvl dlt p) n.
Lemma disjoint_weaken2 : forall dlt l lst, disjoint_list (List.map block_blockid l) (List.map block_blockid lst) -> subset_rel dlt lst -> disjoint_list (List.map block_blockid l) (List.map block_blockid dlt).
Lemma get_write_back_blocks_subset : forall lst p lvl pos_map, subset_rel (get_write_back_blocks p lst 4 lvl pos_map) lst.
Lemma In_path_in_tree : forall o p id, In id (List.map block_blockid (concat (lookup_path_oram o p))) -> In id (List.map block_blockid (get_all_blks_tree o)).
Lemma in_up_oram_tr : forall o id lvl dlt p p', NoDup (List.map block_blockid (get_all_blks_tree o)) -> In id (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p'))) -> In id (List.map block_blockid (concat (lookup_path_oram o p))) -> In id (List.map block_blockid (concat (lookup_path_oram (up_oram_tr o lvl dlt p') p))).
Lemma get_write_back_blocks_pos_map : forall id p stsh lvl pos_map, In id (List.map block_blockid (get_write_back_blocks p stsh 4 lvl pos_map)) -> let p' := lookup_dict (makeBoolList false LOP) id pos_map in isEqvPath p p' lvl = true.
Lemma isEqvPath_lookup_path_oram : forall o n id lvl dlt p p', is_p_b_tr o (S n) -> length p = n -> length p' = n -> (lvl < n)%nat -> In id (List.map block_blockid dlt) -> isEqvPath p p' lvl = true -> In id (List.map block_blockid (concat (lookup_path_oram (up_oram_tr o lvl dlt p) p'))).
Lemma blocks_selection_wf : forall (p : path) (lvl : nat) (s : state), well_formed s -> length p = LOP -> (lvl < LOP)%nat -> well_formed (blocks_selection p lvl s).
Lemma write_back_wf : forall (step start : nat) (s : state) (p : path), length p = LOP -> well_formed s -> Nat.le (start + step) LOP -> well_formed (write_back_r start p step s).
Lemma write_back_in_stash_kv_rel_aux : forall n s p id v start, well_formed s -> length p = LOP -> Nat.le (start + n) LOP -> blk_in_stash id v s -> blk_in_stash id v (write_back_r start p n s) \/ exists k, (start <= k /\ at_lvl_in_path (state_oram (write_back_r start p n s)) k p (Block id v) /\ at_lvl_in_path (state_oram (write_back_r start p n s)) k (calc_path id s) (Block id v))%nat.
Lemma locate_node_in_path : forall o lvl p b, locate_node_in_tr o lvl p = Some b -> In b (lookup_path_oram o p).
Lemma weaken_at_lvl_in_path : forall o lvl p id v, at_lvl_in_path o lvl p (Block id v) -> blk_in_p id v o p.
Lemma write_back_in_stash_state : forall s id v p, well_formed s -> length p = LOP -> blk_in_stash id v s -> blk_in_state id v (write_back_r O p (length p) s).
Lemma get_post_wb_st_stsh_state : forall (id : block_id) (v : nat) (s : state) (p : path), well_formed s -> length p = LOP -> blk_in_stash id v s -> blk_in_state id v (get_post_wb_st s p).
Lemma block_dec (b : block) bs : In b bs \/ ~ In b bs.
Lemma on_path_dec b o : forall p, on_path b o p \/ ~ on_path b o p.
Lemma pos_map_stable_across_wb : forall n p s start, state_position_map s = state_position_map (write_back_r start p n s).
Lemma calc_path_pos_map_same : forall id s s', state_position_map s = state_position_map s' -> calc_path id s = calc_path id s'.
Lemma in_clear_path b o : forall p p', In b (concat (lookup_path_oram o p)) -> ~ In b (concat (lookup_path_oram o p')) -> In b (concat (lookup_path_oram (clear_path o p') p)).
Lemma get_pre_wb_st_Read_state_state : forall (id id' : block_id) (v : nat) (s : state) (p_new : path), blk_in_state id v s -> blk_in_state id v ((get_pre_wb_st id' Read s (calc_path id' s) p_new)).
Lemma get_pre_wb_st_Write_state_state : forall (id id' : block_id) (v v': nat) (s : state) (p_new : path), id <> id' -> blk_in_state id v s -> blk_in_state id v ((get_pre_wb_st id' (Write v') s (calc_path id' s) p_new)).
Lemma In_path_in_tree_block : forall o p b, In b (concat (lookup_path_oram o p)) -> In b (get_all_blks_tree o).
Lemma NoDup_tree_id_same_v: forall id v v' l, NoDup (List.map block_blockid l) -> In (Block id v) l -> In (Block id v') l -> v = v'.
Lemma In_tree_in_path : forall s id v, well_formed s -> In (Block id v) (get_all_blks_tree (state_oram s)) -> blk_in_path id v s.
Lemma blk_in_p_nil_Some id v o1 o2 data : blk_in_p id v (node (Some data) o1 o2) [] -> In (Block id v) data.
Lemma blk_in_p_nil_None id v o1 o2 : ~ blk_in_p id v (node None o1 o2) [].
Lemma blk_in_p_cons_true id v o1 o2 p data : blk_in_p id v o1 p -> blk_in_p id v (node data o1 o2) (true :: p).
Lemma blk_in_p_cons_false id v o1 o2 p data : blk_in_p id v o2 p -> blk_in_p id v (node data o1 o2) (false :: p).
Lemma blk_in_p_true_Some id v o1 o2 p data : blk_in_p id v (node (Some data) o1 o2) (true :: p) -> In (Block id v) data \/ blk_in_p id v o1 p.
Lemma blk_in_p_true_None id v o1 o2 p : blk_in_p id v (node None o1 o2) (true :: p) -> blk_in_p id v o1 p.
Lemma blk_in_p_false_Some id v o1 o2 p data : blk_in_p id v (node (Some data) o1 o2) (false :: p) -> In (Block id v) data \/ blk_in_p id v o2 p.
Lemma blk_in_p_false_None id v o1 o2 p : blk_in_p id v (node None o1 o2) (false :: p) -> blk_in_p id v o2 p.
Lemma blk_in_p_clear_path: forall o p p_new id v, blk_in_p id v (clear_path o p) p_new -> blk_in_p id v o p_new.
Lemma stash_path_combined_rel_Rd_undef : forall (id id' : block_id) (s : state) (p_new : path), well_formed s -> undef id s -> undef id ((get_pre_wb_st id' Read s (calc_path id' s) p_new)).
Lemma stash_path_combined_rel_Wr_undef : forall (id id' : block_id) (v : nat) (s : state) (p_new : path), id <> id' -> well_formed s -> undef id' s -> undef id' ((get_pre_wb_st id (Write v) s (calc_path id s) p_new)).
Lemma get_pre_wb_st_Write_stsh : forall (id : block_id) (v : nat) (s : state) (p_new : path), blk_in_stash id v ((get_pre_wb_st id (Write v) s (calc_path id s) p_new)).
Lemma calc_path_write_bk_r_stable : forall start id s n p , calc_path id (write_back_r start p n s) = calc_path id s.
Lemma path_conversion : forall o lvl p p' b, isEqvPath p p' lvl = true -> at_lvl_in_path o lvl p b -> at_lvl_in_path o lvl p' b.
Lemma locate_comp_block_selection : forall o p p' lvl lvl' dlt, (lvl < lvl')%nat -> locate_node_in_tr (up_oram_tr o lvl dlt p') lvl' p = locate_node_in_tr o lvl' p.
Lemma at_lvl_in_path_blocks_selection : forall s p p' lvl lvl' b, (lvl < lvl')%nat -> at_lvl_in_path (state_oram s) lvl' p b -> at_lvl_in_path (state_oram (blocks_selection p' lvl s)) lvl' p b.
Lemma kv_in_delta_in_tree : forall (o : oram) (id : block_id) (v : nat) (del : list block) (lvl: nat )(p :path), In (Block id v) del -> coord_in_bound o p lvl -> at_lvl_in_path (up_oram_tr o lvl del p) lvl p (Block id v).
Lemma path_eq_get_cand_bs : forall id v h p stop m, In (Block id v) (get_cand_bs h p stop m) -> isEqvPath p (lookup_dict (makeBoolList false LOP) id m) stop = true.
Lemma stash_block_selection : forall p s id v lvl, well_formed s -> length p = LOP -> Nat.le lvl LOP -> blk_in_stash id v s -> blk_in_stash id v (blocks_selection p lvl s) \/ (at_lvl_in_path (state_oram (blocks_selection p lvl s)) lvl p (Block id v) /\ at_lvl_in_path (state_oram (blocks_selection p lvl s)) lvl (calc_path id s) (Block id v) ).
Lemma up_oram_tr_preserves_pb : forall o lvl dlt p n, is_p_b_tr o n -> is_p_b_tr (up_oram_tr o lvl dlt p) n.
Lemma disjoint_weaken2 : forall dlt l lst, disjoint_list (List.map block_blockid l) (List.map block_blockid lst) -> subset_rel dlt lst -> disjoint_list (List.map block_blockid l) (List.map block_blockid dlt).
Lemma get_write_back_blocks_subset : forall lst p lvl pos_map, subset_rel (get_write_back_blocks p lst 4 lvl pos_map) lst.
Lemma In_path_in_tree : forall o p id, In id (List.map block_blockid (concat (lookup_path_oram o p))) -> In id (List.map block_blockid (get_all_blks_tree o)).
Lemma in_up_oram_tr : forall o id lvl dlt p p', NoDup (List.map block_blockid (get_all_blks_tree o)) -> In id (List.map block_blockid (get_all_blks_tree (up_oram_tr o lvl dlt p'))) -> In id (List.map block_blockid (concat (lookup_path_oram o p))) -> In id (List.map block_blockid (concat (lookup_path_oram (up_oram_tr o lvl dlt p') p))).
Lemma get_write_back_blocks_pos_map : forall id p stsh lvl pos_map, In id (List.map block_blockid (get_write_back_blocks p stsh 4 lvl pos_map)) -> let p' := lookup_dict (makeBoolList false LOP) id pos_map in isEqvPath p p' lvl = true.
Lemma isEqvPath_lookup_path_oram : forall o n id lvl dlt p p', is_p_b_tr o (S n) -> length p = n -> length p' = n -> (lvl < n)%nat -> In id (List.map block_blockid dlt) -> isEqvPath p p' lvl = true -> In id (List.map block_blockid (concat (lookup_path_oram (up_oram_tr o lvl dlt p) p'))).
Lemma blocks_selection_wf : forall (p : path) (lvl : nat) (s : state), well_formed s -> length p = LOP -> (lvl < LOP)%nat -> well_formed (blocks_selection p lvl s).
Lemma write_back_wf : forall (step start : nat) (s : state) (p : path), length p = LOP -> well_formed s -> Nat.le (start + step) LOP -> well_formed (write_back_r start p step s).
Lemma write_back_in_stash_kv_rel_aux : forall n s p id v start, well_formed s -> length p = LOP -> Nat.le (start + n) LOP -> blk_in_stash id v s -> blk_in_stash id v (write_back_r start p n s) \/ exists k, (start <= k /\ at_lvl_in_path (state_oram (write_back_r start p n s)) k p (Block id v) /\ at_lvl_in_path (state_oram (write_back_r start p n s)) k (calc_path id s) (Block id v))%nat.
Lemma locate_node_in_path : forall o lvl p b, locate_node_in_tr o lvl p = Some b -> In b (lookup_path_oram o p).
Lemma weaken_at_lvl_in_path : forall o lvl p id v, at_lvl_in_path o lvl p (Block id v) -> blk_in_p id v o p.
Lemma write_back_in_stash_state : forall s id v p, well_formed s -> length p = LOP -> blk_in_stash id v s -> blk_in_state id v (write_back_r O p (length p) s).
Lemma get_post_wb_st_stsh_state : forall (id : block_id) (v : nat) (s : state) (p : path), well_formed s -> length p = LOP -> blk_in_stash id v s -> blk_in_state id v (get_post_wb_st s p).