Skip to content

Commit f62b6f3

Browse files
committed
Checkpoint merkle Tree.Put progress
1 parent e327487 commit f62b6f3

File tree

2 files changed

+280
-191
lines changed

2 files changed

+280
-191
lines changed

src/program_proof/pav/merkle.v

Lines changed: 280 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,203 @@
11
From Perennial.program_proof Require Import grove_prelude.
22
From Goose.github_com.mit_pdos.pav Require Import merkle.
33

4-
From Perennial.program_proof.pav Require Import classes misc cryptoffi cryptoutil merkle_internal.
4+
From Perennial.program_proof.pav Require Import classes misc cryptoffi cryptoutil.
55
From Perennial.program_proof Require Import std_proof.
66

7+
Section internal.
8+
Context `{!heapGS Σ}.
9+
10+
Inductive tree : Type :=
11+
(* Cut only exists for proof checking trees. *)
12+
| Cut : list w8 → tree
13+
| Empty : tree
14+
| Leaf : list w8 → tree
15+
| Interior : list tree → tree.
16+
17+
Fixpoint has_entry (tr : tree) (id : list w8) (node : tree) : Prop :=
18+
match tr with
19+
| Cut _ => False
20+
| Empty => id = [] ∧ tr = node
21+
| Leaf val => id = [] ∧ tr = node
22+
| Interior children =>
23+
match id with
24+
| [] => False
25+
| pos :: rest =>
26+
∃ child, children !! Z.to_nat (word.unsigned pos) = Some child ∧ has_entry child rest node
27+
end
28+
end.
29+
30+
(* The core invariant that defines the recursive hashing structure of merkle trees. *)
31+
Fixpoint is_node_hash (tr : tree) (hash : list w8) : iProp Σ :=
32+
match tr with
33+
| Cut hash' => ⌜hash = hash' ∧ length hash' = 32%nat⌝
34+
| Empty => is_hash [W8 0] hash
35+
| Leaf val => is_hash (val ++ [W8 1]) hash
36+
| Interior children =>
37+
∃ (child_hashes : list (list w8)),
38+
let map_fn := (λ c h, is_node_hash c h) in
39+
([∗ list] child_fn;hash' ∈ (map_fn <$> children);child_hashes,
40+
child_fn hash') ∗
41+
is_hash (concat child_hashes ++ [W8 2]) hash
42+
end%I.
43+
44+
#[global]
45+
Instance is_node_hash_timeless tr hash : Timeless (is_node_hash tr hash).
46+
Proof. Admitted.
47+
48+
#[global]
49+
Instance is_node_hash_persistent tr hash : Persistent (is_node_hash tr hash).
50+
Proof. Admitted.
51+
52+
Lemma node_hash_len tr hash :
53+
is_node_hash tr hash -∗ ⌜length hash = 32%nat⌝.
54+
Proof.
55+
iIntros "Htree".
56+
destruct tr.
57+
{ iDestruct "Htree" as "[%Heq %Hlen]". naive_solver. }
58+
1-2: iDestruct (is_hash_len with "Htree") as "%Hlen"; naive_solver.
59+
{
60+
iDestruct "Htree" as (ch) "[_ Htree]".
61+
by iDestruct (is_hash_len with "Htree") as "%Hlen".
62+
}
63+
Qed.
64+
65+
Lemma concat_len_eq {A : Type} sz (l1 l2 : list (list A)) :
66+
concat l1 = concat l2 →
67+
(Forall (λ l, length l = sz) l1) →
68+
(Forall (λ l, length l = sz) l2) →
69+
0 < sz →
70+
l1 = l2.
71+
Proof.
72+
intros Heq_concat Hlen_l1 Hlen_l2 Hsz.
73+
apply (f_equal length) in Heq_concat as Heq_concat_len.
74+
do 2 rewrite concat_length in Heq_concat_len.
75+
generalize dependent l2.
76+
induction l1 as [|a1]; destruct l2 as [|a2]; simpl;
77+
intros Heq_concat Hlen_l2 Heq_concat_len;
78+
decompose_Forall; eauto with lia.
79+
apply (f_equal (take (length a1))) in Heq_concat as Htake_concat.
80+
apply (f_equal (drop (length a1))) in Heq_concat as Hdrop_concat.
81+
rewrite <-H in Htake_concat at 2.
82+
rewrite <-H in Hdrop_concat at 2.
83+
do 2 rewrite take_app_length in Htake_concat.
84+
do 2 rewrite drop_app_length in Hdrop_concat.
85+
rewrite Htake_concat.
86+
apply (app_inv_head_iff [a2]).
87+
apply IHl1; eauto with lia.
88+
Qed.
89+
90+
(* TODO: is this necessary? can we just apply node_hash_len when necessary? *)
91+
Lemma sep_node_hash_len ct ch :
92+
([∗ list] t;h ∈ ct;ch, is_node_hash t h) -∗
93+
⌜Forall (λ l, length l = 32%nat) ch⌝.
94+
Proof.
95+
iIntros "Htree".
96+
iDestruct (big_sepL2_impl _ (λ _ _ h, ⌜length h = 32%nat⌝%I) with "Htree []") as "Hlen_sepL2".
97+
{
98+
iIntros "!>" (???) "_ _ Hhash".
99+
by iDestruct (node_hash_len with "Hhash") as "Hlen".
100+
}
101+
iDestruct (big_sepL2_const_sepL_r with "Hlen_sepL2") as "[_ %Hlen_sepL1]".
102+
iPureIntro.
103+
by apply Forall_lookup.
104+
Qed.
105+
106+
Lemma disj_empty_leaf digest v :
107+
is_node_hash Empty digest -∗
108+
is_node_hash (Leaf v) digest -∗
109+
False.
110+
Proof.
111+
iIntros "Hempty Hleaf".
112+
iDestruct (is_hash_inj with "Hempty Hleaf") as "%Heq".
113+
iPureIntro.
114+
destruct v as [|a]; [naive_solver|].
115+
(* TODO: why doesn't list_simplifier or solve_length take care of this? *)
116+
apply (f_equal length) in Heq.
117+
rewrite length_app in Heq.
118+
simpl in *.
119+
lia.
120+
Qed.
121+
122+
(* Ownership of a logical merkle tree. *)
123+
Definition own_node_except' (recur : option (list w8) -d> loc -d> tree -d> iPropO Σ) : option (list w8) -d> loc -d> tree -d> iPropO Σ :=
124+
(λ path ptr_tr tr,
125+
match tr with
126+
(* We should never have cuts in in-memory trees. *)
127+
| Cut _ => False
128+
| Empty => True
129+
| Leaf val =>
130+
∃ sl_val hash sl_hash,
131+
"Hval" ∷ own_slice_small sl_val byteT (DfracOwn 1) val ∗
132+
"Hptr_val" ∷ ptr_tr ↦[node :: "val"] (slice_val sl_val) ∗
133+
"Hhash" ∷ own_slice_small sl_hash byteT (DfracOwn 1) hash ∗
134+
"Hsl_hash" ∷ ptr_tr ↦[node :: "hash"] (slice_val sl_hash) ∗
135+
"#His_hash" ∷ match path with
136+
| None => is_node_hash tr hash
137+
| _ => True
138+
end
139+
| Interior children =>
140+
∃ hash sl_hash sl_children ptr_children sl_val,
141+
"Hhash" ∷ own_slice_small sl_hash byteT (DfracOwn 1) hash ∗
142+
"Hsl_children" ∷ own_slice_small sl_children ptrT (DfracOwn 1) ptr_children ∗
143+
"Hptr_val" ∷ ptr_tr ↦[node :: "val"] (slice_val sl_val) ∗ (* XXX: keeping this to ensure ptr_tr is not null *)
144+
"Hptr_children" ∷ ptr_tr ↦[node :: "Children"] (slice_val sl_children) ∗
145+
"Hchildren" ∷
146+
([∗ list] idx ↦ child;ptr_child ∈ children;ptr_children,
147+
match path with
148+
| Some (a :: path) => if decide (uint.nat a = idx) then ▷ recur (Some path) ptr_child child
149+
else ▷ recur None ptr_child child
150+
| None => ▷ recur None ptr_child child
151+
| Some [] => ▷ recur None ptr_child child
152+
end
153+
) ∗
154+
"#His_hash" ∷ match path with
155+
| None => is_node_hash tr hash
156+
| _ => True
157+
end
158+
end)%I.
159+
160+
Local Instance own_node_except'_contractive : Contractive own_node_except'.
161+
Proof. Admitted.
162+
163+
Definition own_node_except : option (list w8) → loc → tree → iProp Σ := fixpoint own_node_except'.
164+
165+
Lemma own_node_except_unfold path ptr obj :
166+
own_node_except path ptr obj ⊣⊢ (own_node_except' own_node_except) path ptr obj.
167+
Proof.
168+
apply (fixpoint_unfold own_node_except').
169+
Qed.
170+
171+
Definition tree_to_map (tr : tree) : gmap (list w8) (list w8) :=
172+
let fix traverse (tr : tree) (acc : gmap (list w8) (list w8)) (id : list w8) :=
173+
match tr with
174+
| Cut _ => acc
175+
| Empty => acc
176+
| Leaf val => <[id:=val]>acc
177+
| Interior children =>
178+
(* Grab all entries from the children, storing the ongoing id. *)
179+
(foldr
180+
(λ child (pIdxAcc:(Z * gmap (list w8) (list w8))),
181+
let acc' := traverse child pIdxAcc.2 (id ++ [W8 pIdxAcc.1])
182+
in (pIdxAcc.1 + 1, acc'))
183+
(0, acc) children
184+
).2
185+
end
186+
in traverse tr ∅ [].
187+
188+
Lemma own_node_except_mono path2 path1 root tr :
189+
match path1, path2 with
190+
| Some a, Some b => prefix a b
191+
| None, _ => True
192+
| _, _ => False
193+
end
194+
own_node_except path1 root tr -∗
195+
own_node_except path2 root tr.
196+
Proof.
197+
Admitted.
198+
199+
End internal.
200+
7201
Section external.
8202
Context `{!heapGS Σ}.
9203

@@ -153,7 +347,7 @@ Section local_defs.
153347
Context `{!heapGS Σ}.
154348
Definition own (ptr : loc) (obj : t) : iProp Σ :=
155349
∃ sl_Val sl_Dig sl_Proof,
156-
"HVal" ∷ ptr ↦[GetReply :: "Val"] (slice_val sl_Val) ∗
350+
"HVal" ∷ ptr ↦[GetReply :: "val"] (slice_val sl_Val) ∗
157351
"Hptr_Val" ∷ own_slice_small sl_Val byteT (DfracOwn 1) obj.(Val) ∗
158352
"HDig" ∷ ptr ↦[GetReply :: "Digest"] (slice_val sl_Dig) ∗
159353
"Hptr_Dig" ∷ own_slice_small sl_Dig byteT (DfracOwn 1) obj.(Digest) ∗
@@ -201,7 +395,90 @@ Lemma wp_Tree_Put ptr_tr entries sl_id id sl_val val d0 d1 :
201395
else
202396
"Htree" ∷ own_merkle ptr_tr entries
203397
}}}.
204-
Proof. Admitted.
398+
Proof.
399+
iIntros (?) "H HΦ". iNamed "H".
400+
wp_rec.
401+
wp_pures.
402+
iDestruct (own_slice_small_sz with "Hid") as %Hsz_id.
403+
wp_apply wp_slice_len.
404+
wp_pures.
405+
wp_if_destruct.
406+
{ (* return an error. *)
407+
wp_pures.
408+
replace (slice.nil) with (slice_val Slice.nil) by done.
409+
iApply "HΦ".
410+
iModIntro. iFrame. iPureIntro.
411+
word.
412+
}
413+
wp_rec.
414+
wp_pures.
415+
iNamed "Htree".
416+
wp_loadField.
417+
wp_pures.
418+
419+
(* weaken to loop invariant. *)
420+
iDestruct (own_node_except_mono (Some id) with "[$]") as "Hnode".
421+
{ done. }
422+
423+
wp_bind (if: _ then _ else _)%E.
424+
wp_apply (wp_wand _ _ _ (λ _,
425+
∃ (root : loc) tr,
426+
"Hroot" ∷ ptr_tr ↦[Tree::"root"] #root ∗
427+
"Hnode" ∷ own_node_except (Some id) root tr ∗
428+
"%Htree" ∷ ⌜ tree_to_map tr = entries ⌝
429+
)%I
430+
with "[Hnode Hroot]").
431+
{
432+
wp_if_destruct.
433+
2:{ iModIntro. iFrame "∗%". }
434+
wp_rec.
435+
wp_apply wp_NewSlice.
436+
iIntros (?) "Hsl".
437+
wp_pures. wp_apply wp_allocStruct.
438+
{ val_ty. }
439+
440+
(* establish that tr = Empty *)
441+
iDestruct (own_node_except_unfold with "Hnode") as "Hnode".
442+
rewrite /own_node_except'.
443+
destruct tr.
444+
{ done. }
445+
2:{ iNamed "Hnode".
446+
by iDestruct (struct_field_pointsto_not_null with "Hptr_val") as %Hn.
447+
}
448+
2:{ iNamed "Hnode".
449+
by iDestruct (struct_field_pointsto_not_null with "Hptr_val") as %Hn.
450+
}
451+
iClear "Hnode".
452+
iIntros (?) "Hnode".
453+
iDestruct (struct_fields_split with "Hnode") as "Hnode".
454+
iNamed "Hnode".
455+
wp_storeField.
456+
iFrame.
457+
iExists Empty.
458+
iSplitL; last done.
459+
by iApply own_node_except_unfold.
460+
}
461+
iIntros (?) "HifInv".
462+
wp_pures. clear v.
463+
wp_apply wp_ref_of_zero.
464+
{ done. }
465+
iIntros (nodePath_ptr) "HnodePath_ptr".
466+
wp_pures.
467+
iNamed "HifInv".
468+
wp_loadField.
469+
wp_load.
470+
rewrite zero_slice_val.
471+
wp_apply (wp_SliceAppend (V:=loc) with "[]").
472+
{ iApply own_slice_zero. }
473+
iIntros (?) "HnodePath".
474+
simpl.
475+
wp_store.
476+
wp_apply wp_ref_to.
477+
{ val_ty. }
478+
iIntros (pathIdx_ptr) "HpathIdx".
479+
wp_pures.
480+
wp_apply (wp_forUpto' with "[$HpathIdx]").
481+
Admitted.
205482

206483
Lemma wp_Tree_Get ptr_tr entries sl_id id d0 :
207484
{{{

0 commit comments

Comments
 (0)