(*The blocks explicitly exported via call arguments, plus the already shared blocks*)
Definition exportedSrc mu vals b := orb (getBlocks vals b) (sharedSrc mu b).
Definition exportedTgt mu vals b := orb (getBlocks vals b) (sharedTgt mu b).

(* Specifications: *)
Lemma exported_inject: forall mu (WD: SM_wd mu) vals1 vals2
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b
(SRC: exportedSrc mu vals1 b = true ),
exists jb d, as_inj mu b = Some (jb, d)
/\ exportedTgt mu vals2 jb = true.
Lemma val_inject_sub_on j k: forall v1 v2
(V:  val_inject j v1 v2)
(HK: forall b, getBlocks (v1::nil) b = true -> j b = k b),
val_inject k v1 v2.
Lemma val_inject_sub_on' j k: forall v1 v2
(V:  val_inject j v1 v2)
(HK: forall b b2 d, getBlocks (v1::nil) b = true ->
j b = Some(b2,d) -> k b = Some(b2,d)),
val_inject k v1 v2.
Lemma val_list_inject_sub_on j k: forall vals1 vals2
(V:  Val.inject_list j vals1 vals2)
(HK: forall b, getBlocks vals1 b = true -> j b = k b),
Val.inject_list k vals1 vals2.
Lemma val_list_inject_sub_on' j k: forall vals1 vals2
(V:  Val.inject_list j vals1 vals2)
(HK: forall b b2 d, getBlocks vals1 b = true ->
j b = Some(b2,d) -> k b = Some(b2,d)),
Val.inject_list k vals1 vals2.
Lemma REACH_shared_of: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (shared_of mu) m1 m2)
(ValInjMu : Forall2 (val_inject (shared_of mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
B (HB: forall b b2 d, shared_of mu b = Some(b2,d) -> B b2 = true),
exists b2 d, shared_of mu b1 = Some (b2, d) /\
REACH m2 (fun b => orb (getBlocks vals2 b) (B b)) b2 = true.
Lemma REACH_as_inj: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
B (HB: forall b b2 d, shared_of mu b = Some(b2,d) -> B b2 = true),
exists b2 d, as_inj mu b1 = Some (b2, d) /\
REACH m2 (fun b => orb (getBlocks vals2 b) (B b)) b2 = true.
Lemma REACH_local: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = true),
exists b2 d, local_of mu b1 = Some (b2, d).
Lemma REACH_extern: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = false),
exists b2 d, extern_of mu b1 = Some (b2, d).
(*The following six or so results are key lemmas about REACH - they say that blocks exported in SRC are injected, to blocks exported by TGT, preserving the locBlocks-structure, ie distinction betwene public and foreign*)
Lemma REACH_as_inj_REACH: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true),
exists b2 d, as_inj mu b1 = Some (b2, d) /\
REACH m2 (exportedTgt mu vals2) b2 = true.
Lemma REACH_local_REACH: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = true),
exists b2 d, local_of mu b1 = Some (b2, d) /\
REACH m2 (exportedTgt mu vals2) b2 = true.
Lemma REACH_local_REACH': forall mu m1 vals1  b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(WD: SM_wd mu) m2 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2)
(locBSrc : locBlocksSrc mu b1 = true) b2 d
(LOC: local_of mu b1 = Some (b2, d)),
REACH m2 (exportedTgt mu vals2) b2 = true.
Lemma REACH_extern_REACH: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = false),
exists b2 d, extern_of mu b1 = Some (b2, d) /\
REACH m2 (exportedTgt mu vals2) b2 = true.
Lemma pubBlocksSrc_REACH: forall m1 mu (WD: SM_wd mu) vals b, pubBlocksSrc mu b = true ->
REACH m1 (exportedSrc mu vals) b = true.
Lemma getBlocks_REACH_exportedSrc m mu vals b: forall
(GB: getBlocks vals b = true),
REACH m (exportedSrc mu vals) b = true.
Lemma exported_inject: forall mu (WD: SM_wd mu) vals1 vals2
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b
(SRC: exportedSrc mu vals1 b = true ),
exists jb d, as_inj mu b = Some (jb, d)
/\ exportedTgt mu vals2 jb = true.
Lemma REACH_shared_of: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (shared_of mu) m1 m2)
(ValInjMu : Forall2 (val_inject (shared_of mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
B (HB: forall b b2 d, shared_of mu b = Some(b2,d) -> B b2 = true),
exists b2 d, shared_of mu b1 = Some (b2, d) /\
REACH m2 (fun b => orb (getBlocks vals2 b) (B b)) b2 = true.
Lemma REACH_as_inj: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
B (HB: forall b b2 d, shared_of mu b = Some(b2,d) -> B b2 = true),
exists b2 d, as_inj mu b1 = Some (b2, d) /\
REACH m2 (fun b => orb (getBlocks vals2 b) (B b)) b2 = true.
Lemma REACH_local: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = true),
exists b2 d, local_of mu b1 = Some (b2, d).
Lemma REACH_extern: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = false),
exists b2 d, extern_of mu b1 = Some (b2, d).
(*The following six or so results are key lemmas about REACH - they say that blocks exported in SRC are injected, to blocks exported by TGT, preserving the locBlocks-structure, ie distinction betwene public and foreign*)
Lemma REACH_as_inj_REACH: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true),
exists b2 d, as_inj mu b1 = Some (b2, d) /\
REACH m2 (exportedTgt mu vals2) b2 = true.
Lemma REACH_local_REACH: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = true),
exists b2 d, local_of mu b1 = Some (b2, d) /\
REACH m2 (exportedTgt mu vals2) b2 = true.
Lemma REACH_local_REACH': forall mu m1 vals1  b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(WD: SM_wd mu) m2 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2)
(locBSrc : locBlocksSrc mu b1 = true) b2 d
(LOC: local_of mu b1 = Some (b2, d)),
REACH m2 (exportedTgt mu vals2) b2 = true.
Lemma REACH_extern_REACH: forall mu (WD: SM_wd mu) m1 m2 vals1 vals2
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1
(R : REACH m1 (exportedSrc mu vals1) b1 = true)
(locBSrc : locBlocksSrc mu b1 = false),
exists b2 d, extern_of mu b1 = Some (b2, d) /\
REACH m2 (exportedTgt mu vals2) b2 = true.