Repository: GaloisInc/saw-script
Pull request #1827: Fix examples after en tree
Author: login: scuellar
Created: 2023-03-01T22:29:18Z | Merged: 2025-04-21T19:03:08Z

This PR updates some of the examples and the tutorial to the new Heapster semantics with EnTrees.

We should wait for `heapster-ide-info` to be merged so we can merge directly into `master`.


Diff:
diff --git a/heapster-saw/doc/tutorial/tutorial.md b/heapster-saw/doc/tutorial/tutorial.md
index dd1113996c..27649b2ce6 100644
--- a/heapster-saw/doc/tutorial/tutorial.md
+++ b/heapster-saw/doc/tutorial/tutorial.md
@@ -685,54 +685,60 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automation *)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics.
 
+(* Import our function definitions*)
 Require Import Examples.tutorial_c_gen.
 Import tutorial_c.
 ```
 
-It first imports all the SAW functionality we need and enables pretty
-printing. Then it imports our new definitions (e.g. `add`).
+It first imports all the SAW functionality we need and some useful
+tactics. Then it imports our new definitions (e.g. `add`).
 
 Our first proof will claim that the function `add` produces no
 errors. More specifically, it says that for all inputs (that's what
-`refinesFun` quantifies) `add` always refines to `noErrorsSpec`. That
-is, it returns a pure value.
+`spec_refines_eq` quantifies) `add` always refines to `safety_spec`. That
+is, it returns a pure value without errors.
 
 ```
-Lemma no_errors_add
-  : refinesFun add (fun _ _ => noErrorsSpec).
+
+Lemma no_errors_add (x y: bitvector 64) :
+  spec_refines_eq (add x y) (safety_spec (x,y)).
 Proof.
 ```
 
-We will use our automation to quickly prove the lemma, but we must
-first unfold those definitions the the automation is unfamiliar with.
+We will use our automation to quickly prove the lemma,
 
 ```
-unfold add, add__tuple_fun, noErrorsSpec.
+solve_trivial_spec 0 0. Qed.
 ```
 
-Then our function `prove_refinement` will deal with the proof.
+You can also attempt the same proof with `add_mistyped`, which
+obviously will fail, since `add_mistyped` has an error. First, you
+will note that `add_mistyped` only takes one argument (since only one
+was defined in its signature)
 
 ```
-  prove_refinement.
-Qed.
+Lemma no_errors_add_mistyped (x: bitvector 64) :
+  spec_refines_eq (add_mistyped x) (safety_spec (x)).
+Proof. solve_trivial_spec 0 0.
+
+	clarify_goal_tutorial.
 ```
 
-You can also attempt the same proof with `add_mistyped`, which
-obviously will fail, since `add_mistyped` has an error.
+After rewriting the terms for clarity, you can see the
+remaining goal says that an `ErrorS` is a refinement of
+`RetS`. In other words, it's trying to prove that a trivially
+pure function has an error. That's obviously false.
 
 ```
-Lemma no_errors_add_mistyped
-  : refinesFun add_mistyped (fun _ => noErrorsSpec).
-Proof.
-  unfold add_mistyped, add_mistyped__tuple_fun, noErrorsSpec.
-  prove_refinement. 
-  (* Fails to solve the goal. *)
 Abort.
 ```
 
@@ -793,12 +799,9 @@ You will have to generate the `.vo` again to write proofs about
 produces no errors.
 
 ```
-Lemma no_errors_incr_ptr
-  : refinesFun incr_ptr (fun _ => noErrorsSpec).
-Proof.
-  unfold incr_ptr, incr_ptr__tuple_fun.
-  prove_refinement.
-Qed.
+Lemma no_errors_incr_ptr (x: bitvector 64) :
+  spec_refines_eq (incr_ptr x) (safety_spec x).
+Proof.  solve_trivial_spec 0 0. Qed.
 ```
 
 ### Structs
@@ -963,48 +966,39 @@ adds dynamic checks on the extracted code which we will see in the Coq
 code. 
 
 Let's go to `arrays_gen.v` (which has already been generated for you)
-and look for the definition of `zero_array__tuple_fun`. You will
-notice that it calls `errorM` twice but, in this case that's not a
+and look for the definition of `zero_array__bodies`. You will
+notice that it calls `errorS` twice, but in this case, that's not a
 sign of a typing error! Heapster includes these errors to catch
 out-of-bounds array accesses and unrepresentable indices (i.e. index
 that can't be written as a machine integer). The code below is a
-simplification of the `zero_array__tuple_fun` with some notation for
+simplification of the `zero_array__bodies` with some notation for
 readability (see below for how to enable such pritty printing).
 
 ```
-zero_array__tuple_fun = 
-    (* ... Some ommited code ... *) 
-    LetRec f:=
-     (fun (e1 e2 : int64) (p1 : Vector int64 e1)
-        (_ _ _ : unit : Type) =>
-        (* ... Some ommited code ... *) 
-        let var__4 := (0)[1] in
-        let var__6 := e2 < e1 in
-		(*... Some ommited code ...*)
-	  if
-       not
-         ((if var__6 then 1 else var__4) ==
-          var__4)
-      then
-       if
-        ((17293822569102704640)[64] <= e2) &&
-        (e2 <= (1152921504606846975)[64])
-       then
-        If e2 <P e1
-        Then f e1 (e2 + (1)[64])
-               (p1 [e2 <- (0)[64]]) tt tt tt
-        Else errorM "ghost_bv <u top_bv"
-       else
-        errorM "Failed Assert at arrays.c:61:5"
-      else returnM p1, tt)
-      InBody (f e0 (0)[64] p0 tt tt tt), tt))
+(fun (e0 : int64) (p0 : Vector int64 e0) =>
+   CallS VoidEv emptyFunStack zero_array__frame
+     (mkFrameCall zero_array__frame 1 e0 (0)[64] p0 tt tt tt),
+  (fun (e0 e1 : int64) (p0 : Vector int64 e0) (_ _ _ : unit) =>
+   if negb ((if e1 < e0 then (-1)[1] else (0)[1]) == (0)[1])
+   then
+    if ((17293822569102704640)[64] <= e1) && (e1 <= (1152921504606846975)[64])
+    then
+     If e1 <P e0
+     Then CallS VoidEv emptyFunStack zero_array__frame
+            (mkFrameCall zero_array__frame 1 e0 (e1 + (1)[64]) 
+               (p0 [e1 <- (0)[64]]) tt tt tt)
+     Else ErrorS (Vector int64 e0) "ghost_bv <u top_bv"
+    else ErrorS (Vector int64 e0) "Failed Assert at arrays.c:61:5"
+   else RetS p0, tt))
 ```
  
-The arguments `e1`, `e2` and `p1` correspond to the length `len`, the
+Notice there are two functions, the outermost one represents
+`zero_array` and the one inside represents the loop. in the latter,
+the arguments `e0`, `e1` and `p1` correspond to the length `len`, the
 offset `i`, and the array `arr`. Notice most of that the function
 performs several tests before executing any computation. The first two
 tests, which are within `if then else` blocks, check that the offset
-is less than the array length `e2 < e1`, and that the index `i` is
+is less than the array length `e1 < e0`, and that the index `i` is
 within the bounds of machine integers. The former is part of the loop
 condition, the second is added by Heapster to ensure the ghost
 variable represents a machine integer.
@@ -1012,15 +1006,16 @@ variable represents a machine integer.
 The last check, which is within uppercase `If Then Else` (which
 handles option types) is not part of the original function but
 inserted by Heapster. It checks that the array access is within bounds
-`e2 <P e1`. The operator `<P` returns an optional proof of the array
+`e1 <P e0`. The operator `<P` returns an optional proof of the array
 access being safe. If the check fails, the function reports a runtime
-error `errorM "ghost_bv <u top_bv"`.
+error `ErrorS _ "ghost_bv <u top_bv"`.
 
 If all the checks pass, then the function simply calls
 itself recursively, with the next index and array with a new entry zeroed out.
 
 ```
-f e1 (e2 + (1)[64]) (p1 [e2 <- (0)[64]]) tt tt tt
+(mkFrameCall zero_array__frame 1 e0 (e1 + (1)[64]) 
+               (p0 [e1 <- (0)[64]]) tt tt tt)
 ```
 
 The extra `tt` are artifacts that get inserted by Heapster, but you
@@ -1040,9 +1035,10 @@ We shall now prove that this function in fact should never return an
 error if the inputs are correct. Go to `array_proofs.v` and look at the proof 
 
 ```
-Lemma no_errors_zero_array
-  : refinesFun zero_array (fun x _ => assumingM (zero_array_precond x) noErrorsSpec).
-Proof
+Lemma no_errors_zero_array x y:
+  spec_refines_eq (zero_array x y)
+    (total_spec (fun '(len, vec, dec) =>  zero_array_precond len) (fun _ _ => True) (x,y, bvAdd _ x (intToBv _ 1))).
+Proof.
 ```
 
 It claims that, assuming the precondition `zero_array_precond` is
@@ -1057,12 +1053,8 @@ Definition zero_array_precond x
 
 
 We will not go into detail about the proof, but notice that the
-important steps are handled by custom automation. Namely we use the
-commands `prove_refinement_match_letRecM_l` and `prove_refinement` to
-handle refinements with and without recursion (respectively). The rest
-of the proof, consists of discharging simple inequalities and a couple
-of trivial entailments, where the left hand side is an error (and thus
-entails anything).
+important steps are handled by custom automation. 
+
 
 ### Recursive data structures
 
diff --git a/heapster-saw/examples/_CoqProject b/heapster-saw/examples/_CoqProject
index d763d13bd2..17ff80627c 100644
--- a/heapster-saw/examples/_CoqProject
+++ b/heapster-saw/examples/_CoqProject
@@ -37,3 +37,4 @@ sha512_gen.v
 #sha512_proofs.v
 io_gen.v
 #io_proofs.v
+#common.v
diff --git a/heapster-saw/examples/arrays_proofs.v b/heapster-saw/examples/arrays_proofs.v
index e1504a8a9e..1c69ae0032 100644
--- a/heapster-saw/examples/arrays_proofs.v
+++ b/heapster-saw/examples/arrays_proofs.v
@@ -1,4 +1,3 @@
-From Coq          Require Import Program.Basics.
 From Coq          Require Import Lists.List.
 From Coq          Require Import String.
 From Coq          Require Import Vectors.Vector.
@@ -7,15 +6,107 @@ From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
 From CryptolToCoq Require Import SAWCoreBitvectors.
 
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
-
-Import SAWCorePrelude.
-
+From EnTree  Require Import Automation.
+Require Import Lia.
+From CryptolToCoq Require Import SAWCoreBitvectorsZifyU64.
+      
+Require Import Examples.common.
 Require Import Examples.arrays_gen.
 Import arrays.
 
+Import SAWCorePrelude.
+
 Import VectorNotations.
 
+Set Nested Proofs Allowed.
+Lemma UIP_bv :
+  forall {n} (x y : bitvector n) (p1 p2 : x = y), p1 = p2.
+Proof.
+  intros.
+  apply UIP_dec.
+  clear. intros.
+  refine (eq_dec _ boolEq _ n x y).
+  clear. intros.
+  split; intros H.
+  - destruct x; destruct y; auto.
+  - subst x. destruct y; reflexivity.
+Qed.
+Require Import Coq.Program.Tactics.
+
+Declare Scope bv_64.
+Local Open Scope bv_64.
+Bind Scope bv_64 with bitvector.
+
+Infix "+":= (bvAdd 64) (at level 50,  left associativity): bv_64.
+Infix "-":= (bvSub 64) (at level 50,  left associativity): bv_64.
+Infix "<":= (isBvslt 64) (at level 70): bv_64.
+Infix "<=":= (isBvsle 64) (at level 70): bv_64.
+
+(*This is a prototype of a tactic to solve all signed inequalities for
+Boolean vectors, as long as there is no overflow. Ideally, if the
+tactic fails, it will show you the bounds you need to prove that thre
+is no overflow. You probably missed them in your invariants.
+
+The idea is pretty simple: convert everything to to `Int` and, becasue
+there is no overflow, we can remove the module quantifiers and crush
+it with standard lia.
+
+TO DO:
+
+- Support all arith relations eq[ ], lt[ ], gt[ ], le[✓], ge[ ]
+
+- Don't directly apply rewrites to all subgoals for efficiency
+
+- Recognize when there is a terminal "node" to apply `lia`. Right now
+  we attempt lia at every step, whcih is wasteful.
+
+ *)
+
+Lemma eq_bvToInt:
+  forall n a b,
+    (BinInt.Z.lt (bvToInt n a) (bvToInt n b)) ->
+    isBvslt n a b.
+Proof.
+Admitted.
+Lemma lt_bvToInt:
+  forall n a b,
+    (BinInt.Z.lt (bvToInt n a) (bvToInt n b)) ->
+    isBvslt n a b.
+Proof.
+Admitted.
+Lemma le_bvToInt:
+  forall n a b,
+    (BinInt.Z.le (bvToInt n a) (bvToInt n b)) ->
+    isBvsle n a b.
+Proof.
+Admitted.
+
+
+Ltac bvToInt_ineq:=
+  first [apply eq_bvToInt |
+          apply lt_bvToInt |
+          apply le_bvToInt].
+
+Ltac remove_mods:=
+  (*TODO: Add other operations*)
+  try rewrite bvAdd_Zadd_mod_64;
+  try rewrite bvSub_Zsub_mod_64;
+  try rewrite bvMul_Zmul_mod_64;
+  repeat rewrite bvToInt_intToBv_64;
+  repeat rewrite BinInt.Z.mod_small.
+
+Ltac solve_bv_no_overflow:=
+  try lia;
+  match goal with
+  | |- isBvsle _ ?LHA ?RHS =>
+      apply le_bvToInt
+  | |- isBvslt _ ?LHA ?RHS =>
+       apply lt_bvToInt
+  end; remove_mods;
+  try solve_bv_no_overflow.
+
+
+
 Definition bvMem_lo := intToBv 64 0xf000000000000000.
 Definition bvMem_hi := intToBv 64 0x0fffffffffffffff.
 
@@ -26,35 +117,117 @@ Definition zero_array_precond x
 Definition zero_array_invariant x x' i
   := isBvsle 64 (intToBv 64 0) i /\ isBvsle 64 i x /\ x = x'.
 
-Lemma no_errors_zero_array
-  : refinesFun zero_array (fun x _ => assumingM (zero_array_precond x) noErrorsSpec).
+Record HeVector T :=
+  someVector {
+     hvLen1 : nat 
+    ; hvLen2 : _
+    ; theVector : BVVec hvLen1 hvLen2 T
+    }.
+Arguments someVector {T hvLen1 hvLen2} theVector.
+
+
+(* Simpler version of `inversion_sigma` where the inversion is only applied if the hyp has the same *)
+Ltac simple_inv_sigma:=
+  match goal with
+  | H: (_; ?x) = (_; ?y) |- _ => eapply inj_pair2 in H; try subst x
+  end.
+Ltac inv_with_sigma H:= inversion H; repeat simple_inv_sigma.
+Tactic Notation "inv_someVector" "in" "*" := 
+  match goal with H: someVector _ = someVector _ |- _ => inv_with_sigma H end.
+
+
+Lemma HeVectorToSigma:
+  forall len len' vec vec',
+  (exists (Plen : len = len'),
+    eq_rect len (fun x => BVVec 64 x (bitvector 64)) vec len' Plen = vec') ->
+  someVector vec = someVector vec'.
+Proof. intros * [Plen Heq]. subst len'.
+       rewrite <- eq_rect_eq in Heq; subst; auto.
+Qed.
+
+Hint Extern 101 (IntroArg ?n (someVector ?a = someVector ?b) _) =>
+       let e1 := argName n in IntroArg_intro e1;
+(eapply HeVectorToSigma in e1);
+revert e1; apply (IntroArg_fold n _ _) : refines prepostcond.
+
+Polymorphic Lemma IntroArg_someVector T n m a1 a2 b1 b2 (eq : a1 = a2) goal :
+  IntroArg n (eq_rect _ (fun x => BVVec m x T) b1 _ eq = b2) (fun _ => goal) ->
+  IntroArg n (@someVector T m a1 b1 = @someVector T m a2 b2) (fun _ => goal).
 Proof.
-  unfold zero_array, zero_array__tuple_fun, zero_array_precond.
-  prove_refinement_match_letRecM_l.
-  - exact (fun a' i _ _ _ _ => assumingM (zero_array_invariant a a' i) noErrorsSpec).
-  unfold zero_array_invariant, noErrorsSpec.
-  fold bvMem_lo; fold bvMem_hi.
-  time "no_errors_zero_array" prove_refinement.
-  (* A number of the remaining cases are covered exactly by hypotheses we already have in
-     scope (e.g. proving the loop invariant holds initially). Note that `prove_refinement`
-     doesn't do this automatically because it may matter which hypothesis is used, if
-     there are multiple. For this poof though, it doesn't. *)
-  all: try assumption.
-  (* Proving that the loop invariant holds inductively: *)
-  - discriminate e_maybe.
-  - transitivity a2.
-    + assumption.
-    + apply isBvsle_suc_r; eauto.
-      rewrite e_assuming2, e_assuming0.
-      reflexivity.
-  - apply isBvslt_to_isBvsle_suc.
-    apply isBvult_to_isBvslt_pos; assumption.
-  (* Proving that these branches are impossible, by virtue of our loop invariant: *)
-  - rewrite <- e_assuming1 in e_if0.
-    discriminate e_if0.
-  - rewrite e_assuming2, e_assuming0 in e_if0.
-    apply isBvslt_antirefl in e_if0; contradiction e_if0.
-  (* The remaining cases are all taken care of by either prove_refinement or assumption! *)
+  destruct eq.
+  intros HH a.
+  inv_with_sigma a.
+  eapply HH; reflexivity.
+Qed.
+
+Hint Extern 101 (IntroArg ?n ?A ?g) =>
+  simple apply IntroArg_someVector; idtac "Done it"
+  : refines prepostcond.
+
+Lemma no_errors_zero_array x y:
+  spec_refines_eq (zero_array x y)
+    (total_spec (fun '(len, vec, dec) =>  zero_array_precond len) (fun _ _ => True) (x,y, bvAdd _ x (intToBv _ 1))).
+Proof.
+  intros; unfold_function.
+  prove_refinement.
+  - wellfounded_decreasing_nat.
+    exact (bvToNat _ x1).
+  - prepost_case 0 0.
+    + exact (someVector a = someVector a0 /\
+            x = x1 /\
+            bvAdd _ x (intToBv _ 1) = x2).
+    + exact (someVector r = someVector r0).
+    + prepost_case 1 0.
+      * exact (someVector a = someVector a0 /\
+                 x = x2 /\
+                 x3 = bvSub _ x0 x1 /\
+                 zero_array_invariant x0 x x1).
+      * exact ( (someVector r = someVector r0)).
+      * prepost_exclude_remaining.
+  - prove_refinement_continue;
+      (* Need to add `inv_someVector` to the automation to reduce better*)
+      try inv_someVector in *.
+    (* with NoRewrite NoSolve *)
+    + reflexivity.
+    + assert (HH: isBvule _ x0 (bvsmax _)).
+      { clear - e_assume.
+        destruct e_assume.
+        eapply isBvule_to_isBvsle_pos; auto.
+        vm_compute; auto.
+        rewrite H0. vm_compute. reflexivity.
+      }
+      clear - HH. lia.
+    + reflexivity.
+    + repeat split. 
+      eapply e_assume.
+    + reflexivity.
+    + destruct_conjs; subst.
+      clear HPrePost HWf. lia.
+    + destruct_conjs; subst. auto.
+    + unfold zero_array_precond in *; destruct_conjs; subst; hnf; split.
+      * solve_bv_no_overflow. 
+      * split; auto.
+        solve_bv_no_overflow.
+    + reflexivity.
+    + unfold zero_array_precond, zero_array_invariant in *.
+      destruct_conjs; subst.
+      subst.
+      hnf.
+      rewrite and_bool_eq_false in *.
+      exfalso.
+      destruct e_if0 as [e_if0 | e_if0].
+      * eapply isBvslt_def_opp in e_if0.
+        rewrite <- i1 in e_if0.
+        vm_compute in e_if0; congruence.
+      * eapply isBvslt_def_opp in e_if0.
+        rewrite -> i2 in e_if0.
+        rewrite -> i0 in e_if0.
+        vm_compute in e_if0. congruence.
+    + reflexivity.
+      
+      Unshelve.
+      all: auto.
+      
 Qed.
 
 
diff --git a/heapster-saw/examples/c_data_proofs.v b/heapster-saw/examples/c_data_proofs.v
index 505387e908..cdb6fe0a6f 100644
--- a/heapster-saw/examples/c_data_proofs.v
+++ b/heapster-saw/examples/c_data_proofs.v
@@ -6,27 +6,27 @@ From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
 From CryptolToCoq Require Import SAWCoreBitvectors.
 
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
+From EnTree  Require Import Automation.
 
+Require Import Examples.common.
 Require Import Examples.c_data_gen.
 Import c_data.
 
 Import SAWCorePrelude.
 
-Lemma no_errors_incr_u64_ptr_byte :
-  refinesFun incr_u64_ptr_byte (fun _ => noErrorsSpec).
-  unfold incr_u64_ptr_byte, incr_u64_ptr_byte__tuple_fun, noErrorsSpec.
-  time "no_errors_incr_u64_ptr_byte" prove_refinement.
-Qed.
+
+Set Bullet Behavior "Strict Subproofs".
+
+Global Hint Unfold malloc: automation.
+
+Lemma no_errors_incr_u64_ptr_byte x:
+  spec_refines_eq (incr_u64_ptr_byte x) (safety_spec (x)).
+Proof. solve_trivial_spec 0 0. Qed.
 
 Lemma no_errors_alloc_padded_struct :
-  refinesFun alloc_padded_struct noErrorsSpec.
-  unfold alloc_padded_struct, alloc_padded_struct__tuple_fun, noErrorsSpec, malloc.
-  time "no_errors_alloc_padded_struct" prove_refinement.
-Qed.
-
-Lemma no_errors_padded_struct_incr_all :
-  refinesFun padded_struct_incr_all (fun _ => noErrorsSpec).
-  unfold padded_struct_incr_all, padded_struct_incr_all__tuple_fun, noErrorsSpec.
-  time "no_errors_padded_struct_incr_all" prove_refinement.
-Qed.
+  spec_refines_eq alloc_padded_struct (safety_spec tt).
+Proof. solve_trivial_spec 0 0; solve_trivial_sidecondition. Qed.
+         
+Lemma no_errors_padded_struct_incr_all x0:
+  spec_refines_eq (padded_struct_incr_all x0) (safety_spec (x0)).
+Proof. solve_trivial_spec 0 0; solve_trivial_sidecondition. Qed.
diff --git a/heapster-saw/examples/common.v b/heapster-saw/examples/common.v
new file mode 100644
index 0000000000..98786d08eb
--- /dev/null
+++ b/heapster-saw/examples/common.v
@@ -0,0 +1,154 @@
+(*
+* Common definitions and tactics that make the examples easier to
+* state and prove. Some or all of these could go into an automation file
+* so we can start building functionality.  *)
+
+From Coq          Require Import Lists.List.
+From Coq          Require Import String.
+From Coq          Require Import Vectors.Vector.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
+
+From CryptolToCoq Require Import SAWCorePrelude.
+From CryptolToCoq Require Import SpecMExtra.
+From EnTree  Require Import Automation.
+
+Require Import Coq.Program.Tactics. (* Great tacticals, move to automation. Perhaps `Require Export`? *)
+
+
+Global Set Bullet Behavior "Strict Subproofs".
+
+
+(** *Basic Coq tactics These are natural extensions of the Coq
+  standard library. I generally try to use names that are compatible
+  with those used in opther projects to help new users.
+
+  We should consider moveing them at the top level
+ *)
+
+Ltac break_match:=
+          match goal with
+            |- context [match ?a with _ => _ end] => destruct a
+          end.
+Ltac break_match_hyp:=
+  match goal with
+    [ H:context [match ?a with _ => _ end] |- _] => destruct a
+  end.
+
+Ltac forget_as term name:=
+  let Hforget := fresh in
+  remember term as name eqn:Hforget; clear Hforget.
+
+
+(** *Basic Spec definitions *)
+
+(* Spec when all events and returns are expected to be the same *)
+Definition spec_refines_eq {E Γ R}:
+  Rel (SpecM E Γ R) (SpecM E Γ R):=
+  @spec_refines E E Γ Γ eqPreRel eqPostRel R R eq.
+
+(* The spec fro things that have no errors. *)
+Definition safety_spec {E Γ R A} {QT: QuantType R}: forall a: A, SpecM E Γ R:=
+  total_spec (fun _ => True) (fun _ _ => True).
+
+
+(** * Tactics for solving trivial spec refinement *)
+
+(* unfolds the corresponding to the `fun__bodies` of a spec. *)
+Ltac unfold_bodies:=
+  match goal with |- context[MultiFixS _ _ _ ?X__bodies] => unfold X__bodies end.
+
+(* | Unfolds a function applied to an arbitrary number of
+arguments. Might fail if the function is a transparent definition of
+an applied relation. *)
+Ltac unfold_head T :=
+  match T with
+  | ?T _ => unfold_head T
+  | ?T => unfold T; unfold_bodies
+  end.
+
+(* | Unfolds a function definition `func` and its body `func__bodies` *)
+Create HintDb automation.
+Ltac unfold_function:=
+  try unfold spec_refines_eq, safety_spec;
+   match goal with
+   | |- spec_refines _ _ _ ?fun_applied _ => let T := fun_applied in
+                                             unfold_head T
+   end; autounfold with automation.
+
+(* The follwoing functions are for automatically matching arguments,
+   in a spec trivial spec *)
+Ltac PreCase_conjunction x y:=
+  eapply Logic.and;[exact (x=y)| ].
+
+Ltac cont_join x tl cont:=
+  match tl with
+  | (?front, ?final) =>
+      PreCase_conjunction x final; (cont front)
+  | _ => exact (x = tl)
+  end.
+
+Ltac SubGoal ls1 ls2 cont:=
+  match ls1 with
+  | (?x0 ; ?tl1 ) =>  SubGoal tl1 ls2 ltac:(fun tl2 => cont_join x0 tl2 cont)
+  | _ => cont ls2
+  end.
+
+(* Ltac for trivial PreCase *) 
+Ltac PreCase_Trivial:=
+  match goal with
+    |- PreCase _ _ ?ls1 (?ls2; tt) =>
+      SubGoal ls1 ls2 ltac:(fun ls => exact True) (* last part is only triggered if the lists are empty*)
+  end.
+
+(* Ltac for trivial PostCase *) 
+Ltac list_zip ls1 ls2:=
+  match ls1 with
+  | (?x, ?ls1') => match ls2 with
+                  | (?y, ?ls2') =>
+                      apply Logic.and;
+                      [list_zip ls1' ls2' | exact (x = y)]
+                  | _ => fail "Mismatched lists"
+                  end
+  | _ => exact (ls1 = ls2)
+  end.
+
+Ltac PostCase_Trivial:=
+  match goal with
+    |- PostCase _ _ _ _ ?ls1 ?ls2  => list_zip ls1 ls2
+  end.
+
+
+Ltac solve_prepost_case n m:=
+  prepost_case n m;
+    [PreCase_Trivial
+    | PostCase_Trivial
+    | prepost_exclude_remaining].
+
+(* | This tactic solves many trivial spec refinements, specially good
+     when proving there is no error, which is generally trivial. *)
+Ltac solve_trivial_spec n m:=
+  intros; unfold_function; prove_refinement;
+    [wellfounded_none |  solve_prepost_case n m| prove_refinement_continue].
+
+Ltac solve_trivial_sidecondition :=
+         repeat break_match; repeat break_match_hyp; destruct_conjs; subst; tauto.
+
+(** *Tactics for clarity*)
+
+(* | This tactic allows you to forget errors, the precondition,
+postcondition and relations to clearly see what we are proving.*)
+Ltac clarify_goal_tutorial:=
+  match goal with
+      |- context [ErrorS _ ?st] =>
+        let error_msg:=fresh "error_msg" in
+      forget_as st error_msg
+  end;
+  match goal with
+  |  |- Automation.spec_refines ?pre ?post ?RR _ _ =>
+        let PRE:=fresh "PRE" in
+        let POST:=fresh "POST" in
+        let Relation:=fresh "Relation" in
+       forget_as pre PRE; forget_as post POST; forget_as RR Relation
+  end.
diff --git a/heapster-saw/examples/tutorial_c_proofs.v b/heapster-saw/examples/tutorial_c_proofs.v
index ebb55b0e8d..099e4cfda4 100644
--- a/heapster-saw/examples/tutorial_c_proofs.v
+++ b/heapster-saw/examples/tutorial_c_proofs.v
@@ -1,40 +1,45 @@
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
+(* The following 2 lines enables pretty printing*)
+From CryptolToCoq Require Import CompMExtra.
 Import CompMExtraNotation. Open Scope fun_syntax.
 
+(* The following 2 lines allows better automatio*)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics.
+
 Require Import Examples.tutorial_c_gen.
 Import tutorial_c.
 
+Lemma no_errors_add (x y: bitvector 64) :
+  spec_refines_eq (add x y) (safety_spec (x,y)).
+Proof. solve_trivial_spec 0 0. Qed.
+   
+Lemma no_errors_add_mistyped (x: bitvector 64) :
+  spec_refines_eq (add_mistyped x) (safety_spec (x)).
+Proof. solve_trivial_spec 0 0.
 
-Lemma no_errors_add
-  : refinesFun add (fun _ _ => noErrorsSpec).
-Proof.
-  unfold add, add__tuple_fun.
-  prove_refinement.
-Qed.
-  
-Lemma no_errors_add_mistyped
-  : refinesFun add_mistyped (fun _ => noErrorsSpec).
-Proof.
-  unfold add_mistyped, add_mistyped__tuple_fun, noErrorsSpec.
-  prove_refinement. 
-  (* Fails to solve the goal. *)
+(* After rewriting the terms for clarity, you can see the
+   remaining goal says that an `ErrorS` is a refinement of
+   `RetS`. In other words, it's trying to prove that a trivially
+   pure function has an error. That's obviously false. *)
+      clarify_goal_tutorial.
 Abort.
 
-
-Lemma no_errors_incr_ptr
-  : refinesFun incr_ptr (fun _ => noErrorsSpec).
-Proof.
-  unfold incr_ptr, incr_ptr__tuple_fun, noErrorsSpec.
-  prove_refinement.
-Qed.
+Lemma no_errors_incr_ptr (x: bitvector 64) :
+  spec_refines_eq (incr_ptr x) (safety_spec x).
+Proof.  solve_trivial_spec 0 0. Qed.
   
-Lemma no_errors_norm_vector
-  : refinesFun norm_vector (fun _ _ _ => noErrorsSpec).
-Proof.
-  unfold norm_vector, norm_vector__tuple_fun, noErrorsSpec.
-  prove_refinement.
+Lemma no_errors_norm_vector (x y z: bitvector 64) :
+  spec_refines_eq (norm_vector x y z) (safety_spec (x, y, z)).
+Proof. solve_trivial_spec 0 0.
+
+       (* The remaining goal, is to show that if initial arguments are
+       equal (for both specs) then at the end of the execution, they
+       are also equal.*)
+       destruct_conjs; subst; reflexivity.
 Qed.
diff --git a/heapster-saw/examples/xor_swap_proofs.v b/heapster-saw/examples/xor_swap_proofs.v
index c78cd2dc5d..1736f00e92 100644
--- a/heapster-saw/examples/xor_swap_proofs.v
+++ b/heapster-saw/examples/xor_swap_proofs.v
@@ -1,4 +1,3 @@
-
 From Coq          Require Import Lists.List.
 From Coq          Require Import String.
 From Coq          Require Import Vectors.Vector.
@@ -7,40 +6,52 @@ From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
 From CryptolToCoq Require Import SAWCoreBitvectors.
 
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
+From EnTree  Require Import Automation.
 
+Require Import Examples.common.
 Require Import Examples.xor_swap_gen.
 Import xor_swap.
 
+Set Bullet Behavior "Strict Subproofs".
 
-Definition xor_swap_spec x1 x2 :
-  CompM (bitvector 64 * bitvector 64) :=
-  returnM (x2, x1).
+Definition xor_swap_spec (x1 x2: bitvector 64) := (x2, x1).
 Arguments xor_swap_spec /.
 
-Lemma no_errors_xor_swap : refinesFun xor_swap (fun _ _ => noErrorsSpec).
-Proof.
-  unfold xor_swap, xor_swap__tuple_fun, noErrorsSpec.
-  time "no_errors_xor_swap" prove_refinement.
-Qed.
 
+(* First prove safety (i.e. no errors) *)
+Lemma xor_swap_not_error (x y: bitvector 64) :
+    spec_refines_eq (xor_swap x y) (safety_spec (x,y)).
+Proof. solve_trivial_spec 0 0. Qed.
+      
+Local Hint Extern 10 (spec_refines eqPreRel eqPostRel eq (xor_swap _ _) _) =>
+        simple apply xor_swap_not_error: refine_proofs.
 
-Lemma bvXor_twice_r n x y :
-  SAWCorePrelude.bvXor n (SAWCorePrelude.bvXor n x y) y = x.
-Proof.
-  rewrite <- bvXor_assoc. rewrite bvXor_same. rewrite bvXor_zero. reflexivity.
-Qed.
 
-Lemma bvXor_twice_l n x y :
-  SAWCorePrelude.bvXor n (SAWCorePrelude.bvXor n y x) y = x.
+(* | Nice notation for better reading in this file*)
+Local Infix "^^" := (SAWCorePrelude.bvXor 64) (at level 30).
+Lemma bvXor_twice_l:
+  forall x1 x2 : bitvector 64, x2 ^^ (x2 ^^ x1) = x1.
 Proof.
-  rewrite bvXor_comm. rewrite bvXor_assoc.
-  rewrite bvXor_same. rewrite bvXor_comm. rewrite bvXor_zero. reflexivity.
+  intros; rewrite bvXor_assoc, bvXor_same, bvXor_comm, bvXor_zero.
+  reflexivity.
 Qed.
 
-Lemma xor_swap_correct : refinesFun xor_swap xor_swap_spec.
+Lemma bvXor_twice_r:
+  forall x1 x2 : bitvector 64, (x1 ^^ x2) ^^ x2 = x1.
 Proof.
-  prove_refinement.
-  subst. rewrite bvXor_twice_r. rewrite bvXor_twice_l.
+  intros; rewrite <- bvXor_assoc, bvXor_same, bvXor_zero.
   reflexivity.
+Qed.    
+
+(* | Now we can prove correctness *)
+Lemma xor_swap_spec_ref (x y: bitvector 64) :
+  spec_refines_eq (xor_swap x y)
+    (total_spec (fun _ =>  True) (fun xy r => r = xor_swap_spec (fst xy) (snd xy))
+       (x,y)).
+Proof. solve_trivial_spec 0 0.
+    - apply bvXor_twice_r.
+    - apply bvXor_twice_l.
 Qed.
+      
+Local Hint Extern 10 (spec_refines eqPreRel eqPostRel eq (xor_swap _ _) _) =>
+       simple apply xor_swap_spec_ref: refine_proofs.


Reviews:
user: login: RyanGlScott
body: I've given this a look, mostly focusing on the tutorial. I have not looked deeply at the details of the proofs themselves, so if there is a particular proof that you would like me to give closer scrutiny, let me know.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2023-03-02T15:51:37Z
user: login: scuellar
body: @RyanGlScott , thank you for the review. I think I have addressed all of your points, except the question regarding the TODO. Let me know what you think.
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2023-03-07T16:49:08Z
user: login: RyanGlScott
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2023-03-07T17:00:33Z
user: login: RyanGlScott
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2023-03-07T17:01:42Z
user: login: sauclovian-g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T23:42:51Z

Review comments:
diff_hunk: @@ -685,56 +685,56 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automatio*)
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: ```suggestion
(* The following 2 lines allows better automation *)
```
created_at: 2023-03-02T15:33:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -685,56 +685,56 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automatio*)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics. (* Great tacticals, move to automation. Perhaps `Require Export`? *)
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: I'm not sure how to read this comment. Does this belong in a tutorial?
created_at: 2023-03-02T15:34:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -685,56 +685,56 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automatio*)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics. (* Great tacticals, move to automation. Perhaps `Require Export`? *)
 
+(* Import our function definitions*)
 Require Import Examples.tutorial_c_gen.
 Import tutorial_c.
 ```
 
-It first imports all the SAW functionality we need and enables pretty
-printing. Then it imports our new definitions (e.g. `add`).
+It first imports all the SAW functionality we need and some useful
+tactics. Then it imports our new definitions (e.g. `add`).
 
 Our first proof will claim that the function `add` produces no
 errors. More specifically, it says that for all inputs (that's what
-`refinesFun` quantifies) `add` always refines to `noErrorsSpec`. That
-is, it returns a pure value.
+`spec_refines_eq` quantifies) `add` always refines to `safety_spec`. That
+is, it returns a pure value without errors.
 
 ```
-Lemma no_errors_add
-  : refinesFun add (fun _ _ => noErrorsSpec).
-Proof.
-```
-
-We will use our automation to quickly prove the lemma, but we must
-first unfold those definitions the the automation is unfamiliar with.
 
-```
-unfold add, add__tuple_fun, noErrorsSpec.
+Lemma no_errors_add (x y: bitvector 64) :
+  spec_refines_eq (add x y) (safety_spec (x,y)).
+Proof.
 ```
 
-Then our function `prove_refinement` will deal with the proof.
+We will use our automation to quickly prove the lemma,
 
 ```
-  prove_refinement.
-Qed.
+solve_trivial_spec 0 0. Qed.
 ```
 
 You can also attempt the same proof with `add_mistyped`, which
-obviously will fail, since `add_mistyped` has an error.
-
-```
-Lemma no_errors_add_mistyped
-  : refinesFun add_mistyped (fun _ => noErrorsSpec).
-Proof.
-  unfold add_mistyped, add_mistyped__tuple_fun, noErrorsSpec.
-  prove_refinement. 
-  (* Fails to solve the goal. *)
+obviously will fail, since `add_mistyped` has an error. First, you
+will note that `add_mistyped` only takes one argument (since only one
+was defined in it's signature)
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: ```suggestion
was defined in its signature)
```
created_at: 2023-03-02T15:35:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -685,56 +685,56 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automatio*)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics. (* Great tacticals, move to automation. Perhaps `Require Export`? *)
 
+(* Import our function definitions*)
 Require Import Examples.tutorial_c_gen.
 Import tutorial_c.
 ```
 
-It first imports all the SAW functionality we need and enables pretty
-printing. Then it imports our new definitions (e.g. `add`).
+It first imports all the SAW functionality we need and some useful
+tactics. Then it imports our new definitions (e.g. `add`).
 
 Our first proof will claim that the function `add` produces no
 errors. More specifically, it says that for all inputs (that's what
-`refinesFun` quantifies) `add` always refines to `noErrorsSpec`. That
-is, it returns a pure value.
+`spec_refines_eq` quantifies) `add` always refines to `safety_spec`. That
+is, it returns a pure value without errors.
 
 ```
-Lemma no_errors_add
-  : refinesFun add (fun _ _ => noErrorsSpec).
-Proof.
-```
-
-We will use our automation to quickly prove the lemma, but we must
-first unfold those definitions the the automation is unfamiliar with.
 
-```
-unfold add, add__tuple_fun, noErrorsSpec.
+Lemma no_errors_add (x y: bitvector 64) :
+  spec_refines_eq (add x y) (safety_spec (x,y)).
+Proof.
 ```
 
-Then our function `prove_refinement` will deal with the proof.
+We will use our automation to quickly prove the lemma,
 
 ```
-  prove_refinement.
-Qed.
+solve_trivial_spec 0 0. Qed.
 ```
 
 You can also attempt the same proof with `add_mistyped`, which
-obviously will fail, since `add_mistyped` has an error.
-
-```
-Lemma no_errors_add_mistyped
-  : refinesFun add_mistyped (fun _ => noErrorsSpec).
-Proof.
-  unfold add_mistyped, add_mistyped__tuple_fun, noErrorsSpec.
-  prove_refinement. 
-  (* Fails to solve the goal. *)
+obviously will fail, since `add_mistyped` has an error. First, you
+will note that `add_mistyped` only takes one argument (since only one
+was defined in it's signature)
+
+Lemma no_errors_add_mistyped (x: bitvector 64) :
+  spec_refines_eq (add_mistyped x) (safety_spec (x)).
+Proof. solve_trivial_spec 0 0.
+
+(* After rewriting the terms for clarity, you can see the
+   remaining goal says that an `ErrorS` is a refinement of
+   `RetS`. In other words, it's trying to prove that a trivially
+   pure function has an error. That's obviously false. *)
+      clarify_goal_tutorial.
 Abort.
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: Should this be surrounded with code blocks ` ``` ... ``` `?
created_at: 2023-03-02T15:38:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -792,15 +792,12 @@ You will have to generate the `.vo` again to write proofs about
 `incr_ptr`. After you do so, we can easily prove that `incr_ptr`
 produces no errors.
 
-```
-Lemma no_errors_incr_ptr
-  : refinesFun incr_ptr (fun _ => noErrorsSpec).
-Proof.
-  unfold incr_ptr, incr_ptr__tuple_fun.
-  prove_refinement.
-Qed.
 ```
 
+Lemma no_errors_incr_ptr (x: bitvector 64) :
+  spec_refines_eq (incr_ptr x) (safety_spec x).
+Proof.  solve_trivial_spec 0 0. Qed.```
+
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: I think this code block is missing a closing ` ``` `.
created_at: 2023-03-02T15:40:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -963,64 +960,54 @@ adds dynamic checks on the extracted code which we will see in the Coq
 code. 
 
 Let's go to `arrays_gen.v` (which has already been generated for you)
-and look for the definition of `zero_array__tuple_fun`. You will
-notice that it calls `errorM` twice but, in this case that's not a
+and look for the definition of `zero_array__bodies`. You will
+notice that it calls `errorS` twice but, in this case that's not a
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: Grammar nit pick:

```suggestion
notice that it calls `errorS` twice, but in this case, that's not a
```
created_at: 2023-03-02T15:40:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -963,64 +960,54 @@ adds dynamic checks on the extracted code which we will see in the Coq
 code. 
 
 Let's go to `arrays_gen.v` (which has already been generated for you)
-and look for the definition of `zero_array__tuple_fun`. You will
-notice that it calls `errorM` twice but, in this case that's not a
+and look for the definition of `zero_array__bodies`. You will
+notice that it calls `errorS` twice but, in this case that's not a
 sign of a typing error! Heapster includes these errors to catch
 out-of-bounds array accesses and unrepresentable indices (i.e. index
 that can't be written as a machine integer). The code below is a
-simplification of the `zero_array__tuple_fun` with some notation for
+simplification of the `zero_array__bodies` with some notation for
 readability (see below for how to enable such pritty printing).
 
 ```
-zero_array__tuple_fun = 
-    (* ... Some ommited code ... *) 
-    LetRec f:=
-     (fun (e1 e2 : int64) (p1 : Vector int64 e1)
-        (_ _ _ : unit : Type) =>
-        (* ... Some ommited code ... *) 
-        let var__4 := (0)[1] in
-        let var__6 := e2 < e1 in
-		(*... Some ommited code ...*)
-	  if
-       not
-         ((if var__6 then 1 else var__4) ==
-          var__4)
-      then
-       if
-        ((17293822569102704640)[64] <= e2) &&
-        (e2 <= (1152921504606846975)[64])
-       then
-        If e2 <P e1
-        Then f e1 (e2 + (1)[64])
-               (p1 [e2 <- (0)[64]]) tt tt tt
-        Else errorM "ghost_bv <u top_bv"
-       else
-        errorM "Failed Assert at arrays.c:61:5"
-      else returnM p1, tt)
-      InBody (f e0 (0)[64] p0 tt tt tt), tt))
+(fun (e0 : int64) (p0 : Vector int64 e0) =>
+   CallS VoidEv emptyFunStack zero_array__frame
+     (mkFrameCall zero_array__frame 1 e0 (0)[64] p0 tt tt tt),
+  (fun (e0 e1 : int64) (p0 : Vector int64 e0) (_ _ _ : unit) =>
+   if negb ((if e1 < e0 then (-1)[1] else (0)[1]) == (0)[1])
+   then
+    if ((17293822569102704640)[64] <= e1) && (e1 <= (1152921504606846975)[64])
+    then
+     If e1 <P e0
+     Then CallS VoidEv emptyFunStack zero_array__frame
+            (mkFrameCall zero_array__frame 1 e0 (e1 + (1)[64]) 
+               (p0 [e1 <- (0)[64]]) tt tt tt)
+     Else ErrorS (Vector int64 e0) "ghost_bv <u top_bv"
+    else ErrorS (Vector int64 e0) "Failed Assert at arrays.c:61:5"
+   else RetS p0, tt))
 ```
  
-The arguments `e1`, `e2` and `p1` correspond to the length `len`, the
+The arguments `e0`, `e1` and `p1` correspond to the length `len`, the
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: We should be careful here, because there are two distinct `e0` arguments in the code above, one in each `fun`. I think you are referring to the second `fun` in that code, so it would be good to clarify this, along with some exposition about why there are two `fun`s in the first place. (It doesn't have to be super detailed for tutorial purposes, but readers will want _some_ kind of explanation of what is going on here.)
created_at: 2023-03-02T15:42:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -963,64 +960,54 @@ adds dynamic checks on the extracted code which we will see in the Coq
 code. 
 
 Let's go to `arrays_gen.v` (which has already been generated for you)
-and look for the definition of `zero_array__tuple_fun`. You will
-notice that it calls `errorM` twice but, in this case that's not a
+and look for the definition of `zero_array__bodies`. You will
+notice that it calls `errorS` twice but, in this case that's not a
 sign of a typing error! Heapster includes these errors to catch
 out-of-bounds array accesses and unrepresentable indices (i.e. index
 that can't be written as a machine integer). The code below is a
-simplification of the `zero_array__tuple_fun` with some notation for
+simplification of the `zero_array__bodies` with some notation for
 readability (see below for how to enable such pritty printing).
 
 ```
-zero_array__tuple_fun = 
-    (* ... Some ommited code ... *) 
-    LetRec f:=
-     (fun (e1 e2 : int64) (p1 : Vector int64 e1)
-        (_ _ _ : unit : Type) =>
-        (* ... Some ommited code ... *) 
-        let var__4 := (0)[1] in
-        let var__6 := e2 < e1 in
-		(*... Some ommited code ...*)
-	  if
-       not
-         ((if var__6 then 1 else var__4) ==
-          var__4)
-      then
-       if
-        ((17293822569102704640)[64] <= e2) &&
-        (e2 <= (1152921504606846975)[64])
-       then
-        If e2 <P e1
-        Then f e1 (e2 + (1)[64])
-               (p1 [e2 <- (0)[64]]) tt tt tt
-        Else errorM "ghost_bv <u top_bv"
-       else
-        errorM "Failed Assert at arrays.c:61:5"
-      else returnM p1, tt)
-      InBody (f e0 (0)[64] p0 tt tt tt), tt))
+(fun (e0 : int64) (p0 : Vector int64 e0) =>
+   CallS VoidEv emptyFunStack zero_array__frame
+     (mkFrameCall zero_array__frame 1 e0 (0)[64] p0 tt tt tt),
+  (fun (e0 e1 : int64) (p0 : Vector int64 e0) (_ _ _ : unit) =>
+   if negb ((if e1 < e0 then (-1)[1] else (0)[1]) == (0)[1])
+   then
+    if ((17293822569102704640)[64] <= e1) && (e1 <= (1152921504606846975)[64])
+    then
+     If e1 <P e0
+     Then CallS VoidEv emptyFunStack zero_array__frame
+            (mkFrameCall zero_array__frame 1 e0 (e1 + (1)[64]) 
+               (p0 [e1 <- (0)[64]]) tt tt tt)
+     Else ErrorS (Vector int64 e0) "ghost_bv <u top_bv"
+    else ErrorS (Vector int64 e0) "Failed Assert at arrays.c:61:5"
+   else RetS p0, tt))
 ```
  
-The arguments `e1`, `e2` and `p1` correspond to the length `len`, the
+The arguments `e0`, `e1` and `p1` correspond to the length `len`, the
 offset `i`, and the array `arr`. Notice most of that the function
 performs several tests before executing any computation. The first two
 tests, which are within `if then else` blocks, check that the offset
-is less than the array length `e2 < e1`, and that the index `i` is
+is less than the array length `e1 < e0`, and that the index `i` is
 within the bounds of machine integers. The former is part of the loop
 condition, the second is added by Heapster to ensure the ghost
 variable represents a machine integer.
 
 The last check, which is within uppercase `If Then Else` (which
 handles option types) is not part of the original function but
 inserted by Heapster. It checks that the array access is within bounds
-`e2 <P e1`. The operator `<P` returns an optional proof of the array
+`e1 <P e0`. The operator `<P` returns an optional proof of the array
 access being safe. If the check fails, the function reports a runtime
-error `errorM "ghost_bv <u top_bv"`.
+error `errorS _ "ghost_bv <u top_bv"`.
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: I think this should be:

```suggestion
error `ErrorS _ "ghost_bv <u top_bv"`.
```
created_at: 2023-03-02T15:45:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1057,12 +1045,10 @@ Definition zero_array_precond x
 
 
 We will not go into detail about the proof, but notice that the
-important steps are handled by custom automation. Namely we use the
-commands `prove_refinement_match_letRecM_l` and `prove_refinement` to
-handle refinements with and without recursion (respectively). The rest
-of the proof, consists of discharging simple inequalities and a couple
-of trivial entailments, where the left hand side is an error (and thus
-entails anything).
+important steps are handled by custom automation. 
+
+TODO: This proof is involved. Perhaps add some more details?
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: Yes, I definitely think so! Are you planning to resolve this TODO in this PR, or are you leaving this as future work?
created_at: 2023-03-02T15:47:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6,11 +6,11 @@
 linked_list_gen.v
 linked_list_proofs.v
 xor_swap_gen.v
-#xor_swap_proofs.v
+xor_swap_proofs.v
 xor_swap_rust_gen.v
 #xor_swap_rust_proofs.v
 c_data_gen.v
-#c_data_proofs.v
+c_data_proofs.v
path: heapster-saw/examples/_CoqProject
user: login: RyanGlScott
body: I'm surprised that this isn't adding back more of the `_proofs.v` files that you've changed in this PR, such as `arrays_proofs.v`. Any reason not to?
created_at: 2023-03-02T15:47:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,15 +6,107 @@ From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
 From CryptolToCoq Require Import SAWCoreBitvectors.
 
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
-
-Import SAWCorePrelude.
-
+From EnTree  Require Import Automation.
+Require Import Lia.
+From CryptolToCoq Require Import SAWCoreBitvectorsZifyU64.
+      
+Require Import Examples.common.
 Require Import Examples.arrays_gen.
 Import arrays.
 
+Import SAWCorePrelude.
+
 Import VectorNotations.
 
+Set Nested Proofs Allowed.
+Lemma UIP_bv :
+  forall {n} (x y : bitvector n) (p1 p2 : x = y), p1 = p2.
+Proof.
+  intros.
+  apply UIP_dec.
+  clear. intros.
+  refine (eq_dec _ boolEq _ n x y).
+  clear. intros.
+  split; intros H.
+  - destruct x; destruct y; auto.
+  - subst x. destruct y; reflexivity.
+Qed.
+Require Import Coq.Program.Tactics.
+
+Declare Scope bv_64.
+Local Open Scope bv_64.
+Bind Scope bv_64 with bitvector.
+
+Infix "+":= (bvAdd 64) (at level 50,  left associativity): bv_64.
+Infix "-":= (bvSub 64) (at level 50,  left associativity): bv_64.
+Infix "<":= (isBvslt 64) (at level 70): bv_64.
+Infix "<=":= (isBvsle 64) (at level 70): bv_64.
+
+(*This is a prototype of a tactic to solve all signed inequalities for
+Boolean vectors, as long as there is no overflow. Ideally, if the
+tactic fails, it will show you the bounds you need to prove that thre
+is no overflow. You probably missed them in your invariants.
+
+The idea is pretty simple: convert everything to to `Int` and, becasue
+there is no overflow, we can remove the module quantifiers and crush
+it with standard lia.
+
+TO DO:
+
+- Support all arith relations eq[ ], lt[ ], gt[ ], le[✓], ge[ ]
+
+- Don't directly apply rewrites to all subgoals for efficiency
+
+- Recognize when there is a terminal "node" to apply `lia`. Right now
+  we attempt lia at every step, whcih is wasteful.
+
+ *)
path: heapster-saw/examples/arrays_proofs.v
user: login: RyanGlScott
body: This is probably worth having a discussion about independently of this PR. Can you open an issue to track the design and discussion of this feature?
created_at: 2023-03-02T15:48:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -26,7 +117,120 @@ Definition zero_array_precond x
 Definition zero_array_invariant x x' i
   := isBvsle 64 (intToBv 64 0) i /\ isBvsle 64 i x /\ x = x'.
 
-Lemma no_errors_zero_array
+Record HeVector T :=
+  someVector {
+     hvLen1 : nat 
+    ; hvLen2 : _
+    ; theVector : BVVec hvLen1 hvLen2 T
+    }.
+Arguments someVector {T hvLen1 hvLen2} theVector.
+
+
+(* Simpler version of `inversion_sigma` where the inversion is only applied if the hyp has the same *)
+Ltac simple_inv_sigma:=
+  match goal with
+  | H: (_; ?x) = (_; ?y) |- _ => eapply inj_pair2 in H; try subst x
+  end.
+Ltac inv_with_sigma H:= inversion H; repeat simple_inv_sigma.
+Tactic Notation "inv_someVector" "in" "*" := 
+  match goal with H: someVector _ = someVector _ |- _ => inv_with_sigma H end.
+
+
+Lemma HeVectorToSigma:
+  forall len len' vec vec',
+  (exists (Plen : len = len'),
+    eq_rect len (fun x => BVVec 64 x (bitvector 64)) vec len' Plen = vec') ->
+  someVector vec = someVector vec'.
+Proof. intros * [Plen Heq]. subst len'.
+       rewrite <- eq_rect_eq in Heq; subst; auto.
+Qed.
+
+Hint Extern 101 (IntroArg ?n (someVector ?a = someVector ?b) _) =>
+       let e1 := argName n in IntroArg_intro e1;
+(eapply HeVectorToSigma in e1);
+revert e1; apply (IntroArg_fold n _ _) : refines prepostcond.
+
+Polymorphic Lemma IntroArg_someVector T n m a1 a2 b1 b2 (eq : a1 = a2) goal :
+  IntroArg n (eq_rect _ (fun x => BVVec m x T) b1 _ eq = b2) (fun _ => goal) ->
+  IntroArg n (@someVector T m a1 b1 = @someVector T m a2 b2) (fun _ => goal).
+Proof.
+  destruct eq.
+  intros HH a.
+  inv_with_sigma a.
+  eapply HH; reflexivity.
+Qed.
+
+Hint Extern 101 (IntroArg ?n ?A ?g) =>
+  simple apply IntroArg_someVector; idtac "Done it"
+  : refines prepostcond.
+
+Lemma no_errors_zero_array x y:
+  spec_refines_eq (zero_array x y)
+    (total_spec (fun '(len, vec, dec) =>  zero_array_precond len) (fun _ _ => True) (x,y, bvAdd _ x (intToBv _ 1))).
+Proof.
+  intros; unfold_function.
+  prove_refinement.
+  - wellfounded_decreasing_nat.
+    exact (bvToNat _ x1).
+  - prepost_case 0 0.
+    + exact (someVector a = someVector a0 /\
+            x = x1 /\
+            bvAdd _ x (intToBv _ 1) = x2).
+    + exact (someVector r = someVector r0).
+    + prepost_case 1 0.
+      * exact (someVector a = someVector a0 /\
+                 x = x2 /\
+                 x3 = bvSub _ x0 x1 /\
+                 zero_array_invariant x0 x x1).
+      * exact ( (someVector r = someVector r0)).
+      * prepost_exclude_remaining.
+  - prove_refinement_continue;
+      (* Need to add `inv_someVector` to the automation to reduce better*)
+      try inv_someVector in *.
+    (* with NoRewrite NoSolve *)
+    + reflexivity.
+    + assert (HH: isBvule _ x0 (bvsmax _)).
+      { clear - e_assume.
+        destruct e_assume.
+        eapply isBvule_to_isBvsle_pos; auto.
+        vm_compute; auto.
+        rewrite H0. vm_compute. reflexivity.
+      }
+      clear - HH. lia.
+    + reflexivity.
+    + repeat split. 
+      eapply e_assume.
+    + reflexivity.
+    + destruct_conjs; subst.
+      clear HPrePost HWf. lia.
+    + destruct_conjs; subst. auto.
+    + unfold zero_array_precond in *; destruct_conjs; subst; hnf; split.
+      * solve_bv_no_overflow. 
+      * split; auto.
+        solve_bv_no_overflow.
+    + reflexivity.
+    + unfold zero_array_precond, zero_array_invariant in *.
+      destruct_conjs; subst.
+      subst.
+      hnf.
+      rewrite and_bool_eq_false in *.
+      exfalso.
+      destruct e_if0 as [e_if0 | e_if0].
+      * eapply isBvslt_def_opp in e_if0.
+        rewrite <- i1 in e_if0.
+        vm_compute in e_if0; congruence.
+      * eapply isBvslt_def_opp in e_if0.
+        rewrite -> i2 in e_if0.
+        rewrite -> i0 in e_if0.
+        vm_compute in e_if0. congruence.
+    + reflexivity.
+      
+      Unshelve.
+      all: auto.
+      
+Qed.
+ 
+(* The old version
path: heapster-saw/examples/arrays_proofs.v
user: login: RyanGlScott
body: A personal thing, but I'd favor just removing the old, commented-out versions. They'll still exist in the `git` history if we want to look at them again in the future.
created_at: 2023-03-02T15:50:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -685,56 +685,56 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automatio*)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics. (* Great tacticals, move to automation. Perhaps `Require Export`? *)
path: heapster-saw/doc/tutorial/tutorial.md
user: login: scuellar
body: I guess not. 
created_at: 2023-03-07T16:10:37Z
author_association: COLLABORATOR
diff_hunk: @@ -685,56 +685,56 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automatio*)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics. (* Great tacticals, move to automation. Perhaps `Require Export`? *)
 
+(* Import our function definitions*)
 Require Import Examples.tutorial_c_gen.
 Import tutorial_c.
 ```
 
-It first imports all the SAW functionality we need and enables pretty
-printing. Then it imports our new definitions (e.g. `add`).
+It first imports all the SAW functionality we need and some useful
+tactics. Then it imports our new definitions (e.g. `add`).
 
 Our first proof will claim that the function `add` produces no
 errors. More specifically, it says that for all inputs (that's what
-`refinesFun` quantifies) `add` always refines to `noErrorsSpec`. That
-is, it returns a pure value.
+`spec_refines_eq` quantifies) `add` always refines to `safety_spec`. That
+is, it returns a pure value without errors.
 
 ```
-Lemma no_errors_add
-  : refinesFun add (fun _ _ => noErrorsSpec).
-Proof.
-```
-
-We will use our automation to quickly prove the lemma, but we must
-first unfold those definitions the the automation is unfamiliar with.
 
-```
-unfold add, add__tuple_fun, noErrorsSpec.
+Lemma no_errors_add (x y: bitvector 64) :
+  spec_refines_eq (add x y) (safety_spec (x,y)).
+Proof.
 ```
 
-Then our function `prove_refinement` will deal with the proof.
+We will use our automation to quickly prove the lemma,
 
 ```
-  prove_refinement.
-Qed.
+solve_trivial_spec 0 0. Qed.
 ```
 
 You can also attempt the same proof with `add_mistyped`, which
-obviously will fail, since `add_mistyped` has an error.
-
-```
-Lemma no_errors_add_mistyped
-  : refinesFun add_mistyped (fun _ => noErrorsSpec).
-Proof.
-  unfold add_mistyped, add_mistyped__tuple_fun, noErrorsSpec.
-  prove_refinement. 
-  (* Fails to solve the goal. *)
+obviously will fail, since `add_mistyped` has an error. First, you
+will note that `add_mistyped` only takes one argument (since only one
+was defined in it's signature)
+
+Lemma no_errors_add_mistyped (x: bitvector 64) :
+  spec_refines_eq (add_mistyped x) (safety_spec (x)).
+Proof. solve_trivial_spec 0 0.
+
+(* After rewriting the terms for clarity, you can see the
+   remaining goal says that an `ErrorS` is a refinement of
+   `RetS`. In other words, it's trying to prove that a trivially
+   pure function has an error. That's obviously false. *)
+      clarify_goal_tutorial.
 Abort.
path: heapster-saw/doc/tutorial/tutorial.md
user: login: scuellar
body: Good catch.
created_at: 2023-03-07T16:12:13Z
author_association: COLLABORATOR
diff_hunk: @@ -792,15 +792,12 @@ You will have to generate the `.vo` again to write proofs about
 `incr_ptr`. After you do so, we can easily prove that `incr_ptr`
 produces no errors.
 
-```
-Lemma no_errors_incr_ptr
-  : refinesFun incr_ptr (fun _ => noErrorsSpec).
-Proof.
-  unfold incr_ptr, incr_ptr__tuple_fun.
-  prove_refinement.
-Qed.
 ```
 
+Lemma no_errors_incr_ptr (x: bitvector 64) :
+  spec_refines_eq (incr_ptr x) (safety_spec x).
+Proof.  solve_trivial_spec 0 0. Qed.```
+
path: heapster-saw/doc/tutorial/tutorial.md
user: login: scuellar
body: Fixed in latest commit.
created_at: 2023-03-07T16:12:30Z
author_association: COLLABORATOR
diff_hunk: @@ -963,64 +960,54 @@ adds dynamic checks on the extracted code which we will see in the Coq
 code. 
 
 Let's go to `arrays_gen.v` (which has already been generated for you)
-and look for the definition of `zero_array__tuple_fun`. You will
-notice that it calls `errorM` twice but, in this case that's not a
+and look for the definition of `zero_array__bodies`. You will
+notice that it calls `errorS` twice but, in this case that's not a
 sign of a typing error! Heapster includes these errors to catch
 out-of-bounds array accesses and unrepresentable indices (i.e. index
 that can't be written as a machine integer). The code below is a
-simplification of the `zero_array__tuple_fun` with some notation for
+simplification of the `zero_array__bodies` with some notation for
 readability (see below for how to enable such pritty printing).
 
 ```
-zero_array__tuple_fun = 
-    (* ... Some ommited code ... *) 
-    LetRec f:=
-     (fun (e1 e2 : int64) (p1 : Vector int64 e1)
-        (_ _ _ : unit : Type) =>
-        (* ... Some ommited code ... *) 
-        let var__4 := (0)[1] in
-        let var__6 := e2 < e1 in
-		(*... Some ommited code ...*)
-	  if
-       not
-         ((if var__6 then 1 else var__4) ==
-          var__4)
-      then
-       if
-        ((17293822569102704640)[64] <= e2) &&
-        (e2 <= (1152921504606846975)[64])
-       then
-        If e2 <P e1
-        Then f e1 (e2 + (1)[64])
-               (p1 [e2 <- (0)[64]]) tt tt tt
-        Else errorM "ghost_bv <u top_bv"
-       else
-        errorM "Failed Assert at arrays.c:61:5"
-      else returnM p1, tt)
-      InBody (f e0 (0)[64] p0 tt tt tt), tt))
+(fun (e0 : int64) (p0 : Vector int64 e0) =>
+   CallS VoidEv emptyFunStack zero_array__frame
+     (mkFrameCall zero_array__frame 1 e0 (0)[64] p0 tt tt tt),
+  (fun (e0 e1 : int64) (p0 : Vector int64 e0) (_ _ _ : unit) =>
+   if negb ((if e1 < e0 then (-1)[1] else (0)[1]) == (0)[1])
+   then
+    if ((17293822569102704640)[64] <= e1) && (e1 <= (1152921504606846975)[64])
+    then
+     If e1 <P e0
+     Then CallS VoidEv emptyFunStack zero_array__frame
+            (mkFrameCall zero_array__frame 1 e0 (e1 + (1)[64]) 
+               (p0 [e1 <- (0)[64]]) tt tt tt)
+     Else ErrorS (Vector int64 e0) "ghost_bv <u top_bv"
+    else ErrorS (Vector int64 e0) "Failed Assert at arrays.c:61:5"
+   else RetS p0, tt))
 ```
  
-The arguments `e1`, `e2` and `p1` correspond to the length `len`, the
+The arguments `e0`, `e1` and `p1` correspond to the length `len`, the
path: heapster-saw/doc/tutorial/tutorial.md
user: login: scuellar
body: Good point. Added some text.
created_at: 2023-03-07T16:15:17Z
author_association: COLLABORATOR
diff_hunk: @@ -1057,12 +1045,10 @@ Definition zero_array_precond x
 
 
 We will not go into detail about the proof, but notice that the
-important steps are handled by custom automation. Namely we use the
-commands `prove_refinement_match_letRecM_l` and `prove_refinement` to
-handle refinements with and without recursion (respectively). The rest
-of the proof, consists of discharging simple inequalities and a couple
-of trivial entailments, where the left hand side is an error (and thus
-entails anything).
+important steps are handled by custom automation. 
+
+TODO: This proof is involved. Perhaps add some more details?
path: heapster-saw/doc/tutorial/tutorial.md
user: login: scuellar
body: It's a good point. The description more or less gets to the limit of what I understand, without going into technical details. Do you have any suggestion of how to improve this section?

We can also just commit the comment and leave it super high level at this point.
created_at: 2023-03-07T16:17:47Z
author_association: COLLABORATOR
diff_hunk: @@ -6,11 +6,11 @@
 linked_list_gen.v
 linked_list_proofs.v
 xor_swap_gen.v
-#xor_swap_proofs.v
+xor_swap_proofs.v
 xor_swap_rust_gen.v
 #xor_swap_rust_proofs.v
 c_data_gen.v
-#c_data_proofs.v
+c_data_proofs.v
path: heapster-saw/examples/_CoqProject
user: login: scuellar
body: I haven't finished the proofs in `arrays_proofs.v`, I only fixed the first one which is the one mentioned in the tutorial.
created_at: 2023-03-07T16:18:58Z
author_association: COLLABORATOR
diff_hunk: @@ -7,15 +6,107 @@ From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
 From CryptolToCoq Require Import SAWCoreBitvectors.
 
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
-
-Import SAWCorePrelude.
-
+From EnTree  Require Import Automation.
+Require Import Lia.
+From CryptolToCoq Require Import SAWCoreBitvectorsZifyU64.
+      
+Require Import Examples.common.
 Require Import Examples.arrays_gen.
 Import arrays.
 
+Import SAWCorePrelude.
+
 Import VectorNotations.
 
+Set Nested Proofs Allowed.
+Lemma UIP_bv :
+  forall {n} (x y : bitvector n) (p1 p2 : x = y), p1 = p2.
+Proof.
+  intros.
+  apply UIP_dec.
+  clear. intros.
+  refine (eq_dec _ boolEq _ n x y).
+  clear. intros.
+  split; intros H.
+  - destruct x; destruct y; auto.
+  - subst x. destruct y; reflexivity.
+Qed.
+Require Import Coq.Program.Tactics.
+
+Declare Scope bv_64.
+Local Open Scope bv_64.
+Bind Scope bv_64 with bitvector.
+
+Infix "+":= (bvAdd 64) (at level 50,  left associativity): bv_64.
+Infix "-":= (bvSub 64) (at level 50,  left associativity): bv_64.
+Infix "<":= (isBvslt 64) (at level 70): bv_64.
+Infix "<=":= (isBvsle 64) (at level 70): bv_64.
+
+(*This is a prototype of a tactic to solve all signed inequalities for
+Boolean vectors, as long as there is no overflow. Ideally, if the
+tactic fails, it will show you the bounds you need to prove that thre
+is no overflow. You probably missed them in your invariants.
+
+The idea is pretty simple: convert everything to to `Int` and, becasue
+there is no overflow, we can remove the module quantifiers and crush
+it with standard lia.
+
+TO DO:
+
+- Support all arith relations eq[ ], lt[ ], gt[ ], le[✓], ge[ ]
+
+- Don't directly apply rewrites to all subgoals for efficiency
+
+- Recognize when there is a terminal "node" to apply `lia`. Right now
+  we attempt lia at every step, whcih is wasteful.
+
+ *)
path: heapster-saw/examples/arrays_proofs.v
user: login: scuellar
body: Added #1836 
created_at: 2023-03-07T16:19:15Z
author_association: COLLABORATOR
diff_hunk: @@ -26,7 +117,120 @@ Definition zero_array_precond x
 Definition zero_array_invariant x x' i
   := isBvsle 64 (intToBv 64 0) i /\ isBvsle 64 i x /\ x = x'.
 
-Lemma no_errors_zero_array
+Record HeVector T :=
+  someVector {
+     hvLen1 : nat 
+    ; hvLen2 : _
+    ; theVector : BVVec hvLen1 hvLen2 T
+    }.
+Arguments someVector {T hvLen1 hvLen2} theVector.
+
+
+(* Simpler version of `inversion_sigma` where the inversion is only applied if the hyp has the same *)
+Ltac simple_inv_sigma:=
+  match goal with
+  | H: (_; ?x) = (_; ?y) |- _ => eapply inj_pair2 in H; try subst x
+  end.
+Ltac inv_with_sigma H:= inversion H; repeat simple_inv_sigma.
+Tactic Notation "inv_someVector" "in" "*" := 
+  match goal with H: someVector _ = someVector _ |- _ => inv_with_sigma H end.
+
+
+Lemma HeVectorToSigma:
+  forall len len' vec vec',
+  (exists (Plen : len = len'),
+    eq_rect len (fun x => BVVec 64 x (bitvector 64)) vec len' Plen = vec') ->
+  someVector vec = someVector vec'.
+Proof. intros * [Plen Heq]. subst len'.
+       rewrite <- eq_rect_eq in Heq; subst; auto.
+Qed.
+
+Hint Extern 101 (IntroArg ?n (someVector ?a = someVector ?b) _) =>
+       let e1 := argName n in IntroArg_intro e1;
+(eapply HeVectorToSigma in e1);
+revert e1; apply (IntroArg_fold n _ _) : refines prepostcond.
+
+Polymorphic Lemma IntroArg_someVector T n m a1 a2 b1 b2 (eq : a1 = a2) goal :
+  IntroArg n (eq_rect _ (fun x => BVVec m x T) b1 _ eq = b2) (fun _ => goal) ->
+  IntroArg n (@someVector T m a1 b1 = @someVector T m a2 b2) (fun _ => goal).
+Proof.
+  destruct eq.
+  intros HH a.
+  inv_with_sigma a.
+  eapply HH; reflexivity.
+Qed.
+
+Hint Extern 101 (IntroArg ?n ?A ?g) =>
+  simple apply IntroArg_someVector; idtac "Done it"
+  : refines prepostcond.
+
+Lemma no_errors_zero_array x y:
+  spec_refines_eq (zero_array x y)
+    (total_spec (fun '(len, vec, dec) =>  zero_array_precond len) (fun _ _ => True) (x,y, bvAdd _ x (intToBv _ 1))).
+Proof.
+  intros; unfold_function.
+  prove_refinement.
+  - wellfounded_decreasing_nat.
+    exact (bvToNat _ x1).
+  - prepost_case 0 0.
+    + exact (someVector a = someVector a0 /\
+            x = x1 /\
+            bvAdd _ x (intToBv _ 1) = x2).
+    + exact (someVector r = someVector r0).
+    + prepost_case 1 0.
+      * exact (someVector a = someVector a0 /\
+                 x = x2 /\
+                 x3 = bvSub _ x0 x1 /\
+                 zero_array_invariant x0 x x1).
+      * exact ( (someVector r = someVector r0)).
+      * prepost_exclude_remaining.
+  - prove_refinement_continue;
+      (* Need to add `inv_someVector` to the automation to reduce better*)
+      try inv_someVector in *.
+    (* with NoRewrite NoSolve *)
+    + reflexivity.
+    + assert (HH: isBvule _ x0 (bvsmax _)).
+      { clear - e_assume.
+        destruct e_assume.
+        eapply isBvule_to_isBvsle_pos; auto.
+        vm_compute; auto.
+        rewrite H0. vm_compute. reflexivity.
+      }
+      clear - HH. lia.
+    + reflexivity.
+    + repeat split. 
+      eapply e_assume.
+    + reflexivity.
+    + destruct_conjs; subst.
+      clear HPrePost HWf. lia.
+    + destruct_conjs; subst. auto.
+    + unfold zero_array_precond in *; destruct_conjs; subst; hnf; split.
+      * solve_bv_no_overflow. 
+      * split; auto.
+        solve_bv_no_overflow.
+    + reflexivity.
+    + unfold zero_array_precond, zero_array_invariant in *.
+      destruct_conjs; subst.
+      subst.
+      hnf.
+      rewrite and_bool_eq_false in *.
+      exfalso.
+      destruct e_if0 as [e_if0 | e_if0].
+      * eapply isBvslt_def_opp in e_if0.
+        rewrite <- i1 in e_if0.
+        vm_compute in e_if0; congruence.
+      * eapply isBvslt_def_opp in e_if0.
+        rewrite -> i2 in e_if0.
+        rewrite -> i0 in e_if0.
+        vm_compute in e_if0. congruence.
+    + reflexivity.
+      
+      Unshelve.
+      all: auto.
+      
+Qed.
+ 
+(* The old version
path: heapster-saw/examples/arrays_proofs.v
user: login: scuellar
body: Fair enough.
created_at: 2023-03-07T16:45:23Z
author_association: COLLABORATOR
diff_hunk: @@ -1057,12 +1045,10 @@ Definition zero_array_precond x
 
 
 We will not go into detail about the proof, but notice that the
-important steps are handled by custom automation. Namely we use the
-commands `prove_refinement_match_letRecM_l` and `prove_refinement` to
-handle refinements with and without recursion (respectively). The rest
-of the proof, consists of discharging simple inequalities and a couple
-of trivial entailments, where the left hand side is an error (and thus
-entails anything).
+important steps are handled by custom automation. 
+
+TODO: This proof is involved. Perhaps add some more details?
path: heapster-saw/doc/tutorial/tutorial.md
user: login: RyanGlScott
body: Ideally, we would include a more detailed tutorial that goes into the nuances of `spec_refines` proofs involving loops. But writing such a tutorial would take a fair bit of effort, so I can understand if you don't want to do that here. My recommendation would be to:

1. Remove this TODO (since TODOs in a tutorial look out of place), and
2. Open an issue as a reminder to write this more detailed tutorial.
created_at: 2023-03-07T17:00:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -685,56 +685,56 @@ Open a new coq file `tutorial_c_proofs.v` in the same folder
 
 ```
 From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreScaffolding.
+From CryptolToCoq Require Import SAWCoreVectorsAsCoqVectors.
+From CryptolToCoq Require Import SAWCoreBitvectors.
 From CryptolToCoq Require Import SAWCorePrelude.
-From CryptolToCoq Require Import CompMExtra.
 
-(* The following line enables pretty printing*)
-Import CompMExtraNotation. Open Scope fun_syntax.
+(* The following 2 lines allows better automatio*)
+Require Import Examples.common.
+Require Import Coq.Program.Tactics. (* Great tacticals, move to automation. Perhaps `Require Export`? *)
path: heapster-saw/doc/tutorial/tutorial.md
user: login: sauclovian-g
body: I've removed the comment
created_at: 2025-04-10T23:41:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1057,12 +1045,10 @@ Definition zero_array_precond x
 
 
 We will not go into detail about the proof, but notice that the
-important steps are handled by custom automation. Namely we use the
-commands `prove_refinement_match_letRecM_l` and `prove_refinement` to
-handle refinements with and without recursion (respectively). The rest
-of the proof, consists of discharging simple inequalities and a couple
-of trivial entailments, where the left hand side is an error (and thus
-entails anything).
+important steps are handled by custom automation. 
+
+TODO: This proof is involved. Perhaps add some more details?
path: heapster-saw/doc/tutorial/tutorial.md
user: login: sauclovian-g
body: I have removed the TODO and opened #2289 to improve the discussion later.
created_at: 2025-04-10T23:41:59Z
author_association: CONTRIBUTOR

PR comments:
user: login: scuellar
created_at: 2023-03-02T15:15:40Z
body: ~~@RyanGlScott I'm tagging you just in case you want to take a look~~. Actually, it would be great if you could review this.  


It didn't feel like using manual proves was instructive, so that's why I automated it. I would assume that more automation will be created for refinements, so hopfully what I wrote is a step in the right direction.
author_association: COLLABORATOR
user: login: sauclovian-g
created_at: 2025-04-10T23:43:33Z
body: I think if nothing explodes unexpectedly we can merge this
author_association: CONTRIBUTOR
user: login: RyanGlScott
created_at: 2025-04-11T01:52:39Z
body: https://github.com/GaloisInc/saw-script/actions/runs/14392377959/job/40362254462?pr=1827#step:11:215

```
COQDEP VFILES
*** Warning: in file xor_swap_proofs.v, library Automation is required from root EnTree and has not been found in the loadpath!
*** Warning: in file c_data_proofs.v, library Automation is required from root EnTree and has not been found in the loadpath!
*** Warning: in file common.v, library Automation is required from root EnTree and has not been found in the loadpath!
COQC linked_list_gen.v
make[1]: *** No rule to make target '../../saw-core-coq/coq/handwritten/CryptolToCoq/SpecMExtra.vo', needed by 'common.vo'.  Stop.
make[1]: *** Waiting for unfinished jobs....
COQC xor_swap_gen.v
make: *** [Makefile.coq:387: all] Error 2
```

Any ideas what is going on here?
author_association: CONTRIBUTOR
user: login: sauclovian-g
created_at: 2025-04-11T06:49:03Z
body: No. I mean, the obvious conclusion is that it can't find entree-specs. And the stuff in this directory didn't previously use entree-specs, so one might suspect that something needs to be added to the CoqProject file. But the saw-core-coq code's CoqProject file doesn't mention EnTree and those files successfully import from it. There isn't a direct use of Automation (except in a file that's commented out) but there is a use of TpDesc, and TpDesc.v lives in the same directory as Automation.v. So I don't understand...
author_association: CONTRIBUTOR
user: login: sauclovian-g
created_at: 2025-04-11T07:02:48Z
body: oh wait, that's a _warning_? so confused...

ah, the actual problem is that SpecMExtra.v is commented out in saw-core-coq. That was done a year ago in #2017, and that leads to #2026, and that suggests that it just isn't going to work as is.

Pfaugh 😿
author_association: CONTRIBUTOR
user: login: sauclovian-g
created_at: 2025-04-11T07:09:45Z
body: Since that's probably not going to get fixed anytime soon, @scuellar do you think it's better to comment out the proofs again and merge this, or leave it? (with the proviso that #2280 will make it a lot harder to handle later)

Unfortunately that means disabling all the proofs that this changeset was supposed to fix. But they worked before (probably at least, the old commits don't seem to have build status any more) and so it's still a step forward...
author_association: CONTRIBUTOR
user: login: sauclovian-g
created_at: 2025-04-11T22:09:32Z
body: I pushed a change to disable the relevant examples again, in case that's what we want. If not, it's easy enough to drop again.
author_association: CONTRIBUTOR