(* Calls forward_if with the current precondition to which the provided conditions are added *)
(* QQQ TODO does this already exist? Add to library? *)
Ltac forward_if_diff add := match add with
| (PROPx ?P2 (LOCALx ?Q2 (SEPx ?R2))) => match goal with
  | |- semax ?Delta (PROPx ?P1 (LOCALx ?Q1 (SEPx ?R1))) _ _ =>
    let P3 := fresh "P3" in let Q3 := fresh "Q3" in let R3 := fresh "R3" in
    pose (P3 := P1 ++ P2); pose (Q3 := Q1 ++ Q2); pose (R3 := R1 ++ R2);
    simpl in P3, Q3, R3;
    forward_if (PROPx P3 (LOCALx Q3 (SEPx R3)));
    subst P3 Q3 R3
  end
end.

(* Specifications: *)
Lemma Vundef_is_Vint: repeat_op_table 4 Vundef id = repeat_op_table 4 (Vint Int.zero) id.
Lemma key_expansion_final_eq: forall key_chars, pow_fun GrowKeyByOne (Z.to_nat (Nb * (Nr + 2) - Nk)) (key_bytes_to_key_words key_chars) = KeyExpansion2 (key_bytes_to_key_words key_chars).
Lemma body_key_expansion: semax_body Vprog Gprog f_mbedtls_aes_setkey_enc key_expansion_spec.
Lemma list_equiv: forall {T: Type}{d: Inhabitant T} (l1 l2: list T) (n: Z), Zlength l1 = n -> Zlength l2 = n -> (forall j, 0 <= j < n -> Znth j l1 = Znth j l2) -> l1 = l2.
Lemma add_no_overflow: forall n i log (Hn: 1 <= n < 256) (Hlog : forall j : Z, 1 <= j < 256 -> Znth j log = log3 (Int.repr j)) (H1: forall i : Z, Int.unsigned (Znth i RSb) <= Byte.max_unsigned) (H3 : (if Int.eq (Znth i RSb) Int.zero then Int.zero else Int.one) <> Int.zero), Int.min_signed <= Int.signed (Int.repr (Znth n log)) + Int.signed (Int.repr (Znth (Int.unsigned (Znth i RSb)) log)) <= Int.max_signed.
Lemma body_gen_tables: semax_body Vprog Gprog f_aes_gen_tables gen_tables_spec.
Lemma Znth_partially_expanded_key: forall key i, 0 <= i < 7 -> forall j, 0 <= j < 8 + i*8 -> (Znth j (map Vint (pow_fun GrowKeyByOne (Z.to_nat (i * 8)) key) ++ repeat_op_table (60 - i * 8) Vundef id)) = Vint (Znth j (KeyExpansion2 key)).
Lemma Zlength_partially_expanded_key: forall i key_chars, 0 <= i < 7 -> Zlength key_chars = 32 -> Zlength (map Vint (pow_fun GrowKeyByOne (Z.to_nat (i * 8)) (key_bytes_to_key_words key_chars)) ++ repeat_op_table (60 - i * 8) Vundef id) = 68.
Lemma update_partially_expanded_key: forall k j j' v key_chars, (* TODO what's the value of v? *) j = j'+k-8 -> upd_Znth (j' + k) (map Vint (pow_fun GrowKeyByOne (Z.to_nat j) (key_bytes_to_key_words key_chars)) ++ repeat_op_table (60 - j) Vundef id) v = (map Vint (pow_fun GrowKeyByOne (Z.to_nat (j + 1)) (key_bytes_to_key_words key_chars)) ++ repeat_op_table (60 - (j + 1)) Vundef id).
Lemma Vundef_is_Vint: repeat_op_table 4 Vundef id = repeat_op_table 4 (Vint Int.zero) id.