Open Scope Z.
Local Open Scope logic.
(* 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.
(* TODO floyd put this in library *)
Ltac replace_temp name new_value := match goal with
| |- context [ (temp name ?old_value) ] =>
let E := fresh "E" in assert_PROP (old_value = new_value) as E;
[ | replace (temp name old_value) with (temp name new_value) by congruence; clear E ]
end.
Tactic Notation "replace_temp" constr(name) constr(new_value) :=
replace_temp name new_value.
Tactic Notation "replace_temp" constr(name) constr(new_value) "by" tactic(t) :=
replace_temp name new_value; [ t | ].
Definition first_loop_inv00 ctx key init_done key_chars ctx_sh key_sh ish i gv :=
PROP ( )
LOCAL (
temp _RK  (field_address t_struct_aesctx [StructField _buf] ctx);
temp _key key; temp _keybits (Vint (Int.repr 256));
gvars gv)
SEP (
field_at ctx_sh t_struct_aesctx [StructField _nr] (Vint (Int.repr 14)) ctx;
field_at ctx_sh t_struct_aesctx [StructField _rk]
(field_address t_struct_aesctx [StructField _buf] ctx) ctx;
field_at ctx_sh t_struct_aesctx [StructField _buf]
(partially_filled i 68 (fun i => get_uint32_le key_chars (i*4))) ctx;
data_at key_sh (tarray tuchar (4 * 8)) (map Vint (map Int.repr key_chars)) key;
data_at ish tint (Vint (Int.repr init_done)) (gv _aes_init_done);
tables_initialized (gv _tables)).
Definition first_loop_inv0 ctx key init_done key_chars ctx_sh key_sh ish gv :=
EX i: Z, first_loop_inv00 ctx key init_done key_chars ctx_sh key_sh ish i gv.
Definition main_loop_invariant0 ctx key ctx_sh key_sh ish key_chars init_done i gv :=
PROP ( )
LOCAL (
temp _RK (offset_val (i*32) (field_address t_struct_aesctx [StructField _buf] ctx));
gvars gv
) SEP (
field_at ctx_sh t_struct_aesctx [StructField _nr] (Vint (Int.repr 14)) ctx;
field_at ctx_sh t_struct_aesctx [StructField _rk]
(field_address t_struct_aesctx [StructField _buf] ctx) ctx;
field_at ctx_sh t_struct_aesctx [StructField _buf]
(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) ctx;
data_at key_sh (tarray tuchar (4 * 8)) (map Vint (map Int.repr key_chars)) key;
data_at ish tint (Vint (Int.repr init_done)) (gv _aes_init_done);
tables_initialized (gv _tables)
).
Definition main_loop_invariant ctx key ctx_sh key_sh ish key_chars init_done gv :=
EX i: Z, main_loop_invariant0 ctx key ctx_sh key_sh ish key_chars init_done i gv.

(* Specifications: *)
(* TODO this does not hold, we have to replace Vundef by (Vint Int.zero) in the whole proof *)
Lemma Vundef_is_Vint:
repeat_op_table 4 Vundef id = repeat_op_table 4 (Vint Int.zero) id.
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)).