(* The complement of make_shares. *)
Fixpoint make_shares_inv shs (lasts : list Z) i {struct lasts} : list share :=
match lasts with
| [] => []
| b :: rest => if eq_dec b i then hd Share.bot shs :: make_shares_inv (tl shs) rest i
else make_shares_inv (tl shs) rest i
end.

(* Specifications: *)
Lemma make_shares_minus : forall i lasts sh0 shs sh' sh1 (Hsh' : sepalg_list.list_join sh0 shs sh')
(Hsh1 : sepalg_list.list_join sh0 (make_shares shs lasts i) sh1)
(Hlen : Zlength shs = Zlength lasts),
sepalg_list.list_join sh1 (make_shares_inv shs lasts i) sh'.
Lemma make_shares_add : forall i i' lasts j shs (Hj : 0 <= j < Zlength lasts)
(Hi : Znth j lasts = i) (Hi' : i' <> i) (Hlen : Zlength shs >= Zlength lasts),
exists shs1 shs2, make_shares shs lasts i = shs1 ++ shs2 /\
make_shares shs (upd_Znth j lasts i') i = shs1 ++ Znth j shs :: shs2.
Lemma make_shares_In : forall i lasts x shs (Hx : 0 <= x < Zlength lasts) (Hi : Znth x lasts <> i)
(Hlen : Zlength shs >= Zlength lasts),
In (Znth x shs)  (make_shares shs lasts i).
Lemma make_shares_inv_In : forall i lasts x shs (Hx : 0 <= x < Zlength lasts) (Hi : Znth x lasts = i)
(Hlen : Zlength shs >= Zlength lasts),
In (Znth x shs) (make_shares_inv shs lasts i).
Lemma make_shares_sub : forall i lasts shs sh0 sh1 sh2 (Hlen : Zlength shs >= Zlength lasts)
(Hsh1 : sepalg_list.list_join sh0 shs sh1) (Hsh2 : sepalg_list.list_join sh0 (make_shares shs lasts i) sh2),
sepalg.join_sub sh2 sh1.
Lemma make_shares_join : forall i lasts shs sh0 j sh1 sh2
(Hlen : Zlength shs >= Zlength lasts)
(Hsh1 : sepalg_list.list_join sh0 shs sh1)
(Hsh2 : sepalg_list.list_join sh0 (make_shares shs lasts i) sh2)
(Hin : 0 <= j < Zlength shs)
(Hj : Znth j lasts = i),
exists sh', sepalg.join sh2 (Znth j shs) sh'.
Lemma make_shares_join' : forall i lasts shs sh0 j sh1 sh2
(Hlen : Zlength shs >= Zlength lasts)
(Hsh1 : sepalg_list.list_join sh0 shs sh1)
(Hsh2 : sepalg_list.list_join sh0 (make_shares shs lasts i) sh2)
(Hin : 0 <= j < Zlength shs) (Hout : Zlength lasts <= j),
exists sh', sepalg.join sh2 (Znth j shs) sh'.
Lemma data_at_buffer_cohere : forall sh1 sh2 v1 v2 p, readable_share sh1 ->
data_at sh1 tbuffer v1 p * data_at sh2 tbuffer v2 p |--
data_at sh1 tbuffer v1 p * data_at sh2 tbuffer v1 p.
Lemma hd_Znth': forall {A} (d: A) al, hd d al = @Znth A d 0 al.
(* The relationship between the last_taken array and the shares held by the writer is preserved by the action of the loop body. *)
Lemma upd_write_shares : forall bufs b b0 lasts shs sh0 (Hb : 0 <= b < B) (Hb0 : 0 <= b0 < B)
(Hlasts : Forall (fun x : Z => 0 <= x < B) lasts) (Hshs : Zlength shs = N)
(Hread : Forall readable_share shs) (Hsh0 : sepalg_list.list_join sh0 shs Ews)
(Hdiff : b <> b0) (Hout : ~ In b lasts) (Hout0 : ~ In b0 lasts) (Hlasts : Zlength lasts = N)
bsh' v' (Hv' : -1 <= v' < B) h' (Hh' : 0 <= Zlength h' < N)
(Hbsh' : sepalg_list.list_join sh0 (sublist (Zlength h' + 1) N shs) bsh')
bsh (Hbsh : sepalg.join bsh' (Znth (Zlength h') shs) bsh),
(if eq_dec v' (-1) then
EX v0 : Z, data_at (Znth (Zlength h') shs) tbuffer (vint v0) (Znth (Znth (Zlength h') lasts) bufs)
else !! (v' = b0) && (EX v'0 : Z, data_at (Znth (Zlength h') shs) tbuffer (vint v'0) (Znth b0 bufs))) *
((EX v0 : Z, data_at bsh' tbuffer (vint v0) (Znth b bufs)) *
fold_right sepcon emp (upd_Znth b (map (fun a => EX sh : share, !! (if eq_dec a b0 then
sepalg_list.list_join sh0 (make_shares shs (sublist 0 (Zlength h')
(map (fun i : Z => if eq_dec (Znth i h') Empty then b0 else Znth i lasts) (upto (Z.to_nat N)))) a) sh
else if eq_dec a b then sepalg_list.list_join sh0 (sublist (Zlength h') N shs) sh
else sepalg_list.list_join sh0 (make_shares shs
(map (fun i : Z => if eq_dec (Znth i h') Empty then b0 else Znth i lasts) (upto (Z.to_nat N))) a) sh) &&
(EX v0 : Z, data_at sh tbuffer (vint v0) (Znth a bufs))) (upto (Z.to_nat B))) emp))
|-- fold_right sepcon emp (map (fun a => EX sh : share, !! (if eq_dec a b0 then
sepalg_list.list_join sh0 (make_shares shs (sublist 0 (Zlength h' + 1)
(map (fun i : Z => if eq_dec (Znth i (h' ++ [vint v'])) Empty then b0 else Znth i lasts) (upto (Z.to_nat N)))) a) sh
else if eq_dec a b then sepalg_list.list_join sh0 (sublist (Zlength h' + 1) N shs) sh
else sepalg_list.list_join sh0 (make_shares shs
(map (fun i : Z => if eq_dec (Znth i (h' ++ [vint v'])) Empty then b0 else Znth i lasts) (upto (Z.to_nat N))) a) sh) &&
(EX v0 : Z, data_at sh tbuffer (vint v0) (Znth a bufs))) (upto (Z.to_nat B))).
Lemma body_finish_write : semax_body Vprog Gprog f_finish_write finish_write_spec.