NB: This Coq documentation contains a revised version of the Coq implementation of these papers [1], [2], [3], [4], and is also the support for ongoing research. A partial archive (14/01/2001) is available at here. Drop us a line if you are interested in a complete, up-to-date archive.

Library multi_sub_triple

Require Import ssreflect ssrbool eqtype.
Require Import Arith_ext ZArith_ext Lists_ext.
Require Import machine_int multi_int.
Import MachineInt.
Require Import mips_seplog mips_tactics mips_contrib mapstos.
Require Import multi_sub_prg.

Local Open Scope machine_int_scope.
Local Open Scope heap_scope.
Local Open Scope nodup_scope.
Import expr_m.
Local Open Scope mips_expr_scope.
Import assert_m.
Local Open Scope mips_assert_scope.
Local Open Scope mips_cmd_scope.
Local Open Scope mips_hoare_scope.

Variables k a b c t j u bor atmp btmp : reg.

Lemma multi_sub_triple : forall k a b c t j u bor atmp btmp,
  nodup(k, a, b, c, t, j, u, bor, atmp, btmp, r0) ->
  forall nk va vb vc, u2Z vc + 4 * Z_of_nat nk < Zbeta 1 ->
  forall A B, length A = nk -> length B = nk ->
{{ fun s h => exists C, length C = nk /\ [a]_s = va /\
   [b]_s = vb /\ [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
   (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h }}
 multi_sub k a b c t j u bor atmp btmp
{{ fun s h => exists C, length C = nk /\ (var_e c |--> C ** TT) s h /\
   Sum nk C = Sum nk A - Sum nk B + u2Z [bor]_s * Zbeta nk }}.
Proof.
move=> k a b c t j u bor atmp btmp Hset nk va vb vc Hnc A B Ha Hb.
rewrite /multi_sub.

addiu j zero zero16;

NextAddiu.
move=> s h [C [HlenC [Hra [Hrb [Hrc [Hrk H]]]]]].
rewrite /wp_addiu; repeat reg_upd; repeat (split; trivial).
exists C; repeat (split; trivial).
by Assert_upd.

addi t c zero16

NextAddiu.
move=> s h [[C [HlenC [Hra [Hrb [Hrc [Hrk H]]]]]] Hj].
rewrite /wp_addiu; repeat reg_upd; repeat (split; trivial).
exists C; repeat (split; trivial).
by Assert_upd.

addi bor zero zero16;

NextAddiu.
move=> s h [[[C [HlenC [Hra [Hrb [Hrc [Hrk H]]]]]] Hj] Ht].
rewrite /wp_addiu; repeat reg_upd; repeat (split; trivial).
exists C; repeat (split; trivial).
by Assert_upd.

while (bne j k) (

apply hoare_prop_m.hoare_while_invariant with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj <= nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\ nbor <= 1 /\
  Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj).

move=> s h [[[[C [HlenC [Hra [Hrb [Hrc [Hrk H]]]]]] Hj] Ht Hbor]].
exists C, O, 0; repeat (split => //).
by rewrite store.get_r0 add_com add_0 sext_Z2u // u2Z_Z2u in Hj.
by apply le_O_n.
rewrite Ht sext_0 add_0 Hrc; ring.
by rewrite sext_Z2u // add_0 store.get_r0 u2Z_Z2u in Hbor.

move=> s h [[C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk2 [Hrt [Hrbor [Hnbor HInv]]]]]]]]]]]]] Hjk]]; rewrite /= in Hjk.
move/negPn : Hjk; move/Zeq_boolP => Hjk.
exists C; repeat (split; trivial).
apply con_Q_con_TT with (var_e a |--> A ** var_e b |--> B).
by assoc_comm Hmem.
have -> : nk = nj by rewrite Hrj Hrk in Hjk; apply Z_of_nat_inj.
by rewrite Hrbor -HInv.

lwxs atmp j b;

apply hoare_lwxs_back_alt'' with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\ nbor <= 1 /\
  Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [atmp]_s = nth nj B zero32).

move=> s h [[C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk2 [Hrt [Hrbor [Hnbor HInv]]]]]]]]]]]]] Hjk]];
  rewrite /= in Hjk. move/Zeq_boolP : Hjk => Hjk.
have {Hjk}Hjk : (nj < nk)%nat.
  rewrite Hrj Hrk in Hjk.
  apply le_neq_lt => //;by apply Z_of_nat_inj_neq.

exists (nth nj B zero32); split.
- Decompose_32 B nj B1 B2 HlenB1 HB'; last by rewrite Hb.
  rewrite HB' (decompose_equiv _ _ _ _ _ HlenB1) !assert_m.con_assoc_equiv assert_m.con_com_equiv
    !assert_m.con_assoc_equiv assert_m.con_com_equiv !assert_m.con_assoc_equiv in Hmem.
  move: Hmem; apply monotony => // h'.
  apply mapsto_ext => //.
  by rewrite [mult]lock /= -lock shl_Z2u Hrj inj_mult Zmult_comm.
- rewrite /update_store_lwxs.
  exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
  by Assert_upd.

addu btmp atmp bor;

apply hoare_addu with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\
  nbor <= 1 /\ Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [atmp]_s = nth nj B zero32 /\ [btmp]_s = nth nj B zero32 [.+] [bor]_s).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk2 [Hrt [Hrbor [Hnbor [HInv Hratmp]]]]]]]]]]]]]]].
exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
by rewrite Hratmp.

sltu u btmp atmp;

apply hoare_sltu with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\
  nbor <= 1 /\ Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [btmp]_s = nth nj B zero32 [.+] [bor]_s /\
  [u]_s = if Zlt_bool (u2Z [btmp]_s) (u2Z (nth nj B zero32)) then one32 else zero32).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk2 [Hrt [Hrbor [Hnbor [HInv [Hratmp Hrtmp']]]]]]]]]]]]]]]].

exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
by rewrite Hratmp.

lwxs atmp j a;

apply hoare_lwxs_back_alt'' with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\
  nbor <= 1 /\ Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [atmp]_s = nth nj A zero32 /\ [btmp]_s = nth nj B zero32 [.+] [bor]_s /\
  [u]_s = if Zlt_bool (u2Z [btmp]_s) (u2Z (nth nj B zero32)) then one32 else zero32).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk2 [Hrt [Hrbor [Hnbor [HInv [Hrbtmp Hru]]]]]]]]]]]]]]]].

exists (nth nj A zero32); split.
- Decompose_32 A nj A1 A2 HlenA1 HA'; last by rewrite Ha.
  rewrite HA' (decompose_equiv _ _ _ _ _ HlenA1) !assert_m.con_assoc_equiv assert_m.con_com_equiv !assert_m.con_assoc_equiv in Hmem.
  move: Hmem; apply monotony => // h'.
  apply mapsto_ext => //.
  by rewrite [mult]lock /= -lock shl_Z2u Hrj inj_mult Zmult_comm.
- rewrite /update_store_lwxs; exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
  by Assert_upd.

ifte_beq u, r0 thendo

apply while.hoare_seq with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\
  u2Z [bor]_s = nbor /\ nbor <= 1 /\
  Sum nj C + u2Z ([atmp]_s) * Zbeta nj = Sum nj A - Sum nj B +
  u2Z (nth nj A zero32) * Zbeta nj - u2Z (nth nj B zero32) * Zbeta nj + nbor * Zbeta (S nj)).

apply while.hoare_ifte.

addiu u r0 one16 ;

apply hoare_addiu with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  [u]_s = one32 /\ u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\
  nbor <= 1 /\ Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [atmp]_s = nth nj A zero32 /\ [btmp]_s = nth nj B zero32 [.+] [bor]_s /\
  u2Z [btmp]_s = u2Z (nth nj B zero32) + nbor).

move=> s h [[C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk2 [Hrt [Hrbor [Hnbor [HInv [Hratmp [Hrbtmp Hru]]]]]]]]]]]]]]]]] Hu]; rewrite /= in Hu.
rewrite store.get_r0 u2Z_Z2u // in Hu.
move/Zeq_boolP : Hu => Hu.
exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
- by Assert_upd.
- by rewrite add_com add_0 sext_Z2u.
- rewrite Hrbtmp -Hrbor u2Z_add //.
  apply u2Z_add_no_overflow.
  rewrite -Hrbtmp.
  apply Znot_gt_le.
  move/Zgt_lt.
  move/Zlt_boolP => X.
  by rewrite Hru X u2Z_Z2u // u2Z_Z2u in Hu.

multu atmp one;

apply hoare_multu with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  [u]_s = one32 /\ u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\
  nbor <= 1 /\ Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [atmp]_s = nth nj A zero32 /\ [btmp]_s = nth nj B zero32 [.+] [bor]_s /\
  u2Z [btmp]_s = u2Z (nth nj B zero32) + nbor /\
  store.utoZ s = u2Z (nth nj A zero32)).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hu [Hrj [Hjk2 [Hrt [Hrbor [Hnbor [HInv [Hratmp [Hrbtmp Hru]]]]]]]]]]]]]]]]]].
exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
by rewrite store.utoZ_multu Hu umul_1 u2Z_zext Hratmp.

msubu btmp one;

apply hoare_msubu with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\
  nbor <= 1 /\ Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [atmp]_s = nth nj A zero32 /\ [btmp]_s = nth nj B zero32 [.+] [bor]_s /\
  u2Z [btmp]_s = u2Z (nth nj B zero32) + nbor /\
  ((u2Z [btmp]_s <= u2Z (nth nj A zero32) -> store.utoZ s = u2Z (nth nj A zero32) - u2Z [btmp]_s) /\
   (u2Z (nth nj A zero32) < u2Z [btmp]_s -> store.utoZ s = Zbeta 2 + u2Z (nth nj A zero32) - u2Z [btmp]_s))).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hone [Hrj [Hjk [Hrt [Hrbor [Hnbor [Hinv [Hratmp [Hrbtmp [Hrbtmp2 Hm]]]]]]]]]]]]]]]]]]].
exists C, nj, nbor.
rewrite Hone umul_1.
repeat reg_upd; repeat (split; trivial).
- by Assert_upd.
- move=> H; rewrite store.msubu_utoZ Hm ?(@u2Z_zext 32) //; last by apply Zle_ge; trivial.
  apply Zlt_trans with (Zbeta 1) => //; by apply max_u2Z.
- move=> H; rewrite store.msubu_utoZ_overflow Hm ?u2Z_zext //.
  apply Zlt_trans with (Zbeta 1) => //; by apply max_u2Z.

sltu bor atmp btmp;

apply hoare_sltu with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ nbor <= 1 /\
  Sum nj C = Sum nj A - Sum nj B + nbor * Zbeta nj /\
  [atmp]_s = nth nj A zero32 /\
  [btmp]_s = nth nj B zero32 [.+] Z2u 32 nbor /\
  u2Z [btmp]_s = u2Z (nth nj B zero32) + nbor /\
  (u2Z [btmp]_s <= u2Z (nth nj A zero32) ->
    store.utoZ s = u2Z (nth nj A zero32) - u2Z [btmp]_s) /\
  (u2Z (nth nj A zero32) < u2Z [btmp]_s ->
    store.utoZ s = Zbeta 2 + u2Z (nth nj A zero32) - u2Z [btmp]_s) /\
  [bor]_s = if Zlt_bool (u2Z [atmp]_s) (u2Z [btmp]_s) then one32 else zero32).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk [Hrt [Hrbor [Hnbor [Hinv [Hratmp [Hrbtmp [Hrbtmp2 [Hinv1 Hinv2]]]]]]]]]]]]]]]]]]].
exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
by rewrite -Hrbor Z2u_u2Z.

mflhxu atmp;

apply hoare_mflhxu'.

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk [Hrt [Hnbor [Hinv [Hratmp [Hrbtmp [Hrbtmp2 [Hm1 [Hm2 Hrbor]]]]]]]]]]]]]]]]]]].

case: (Z_lt_le_dec (u2Z [atmp]_s) (u2Z [btmp]_s)).
- move/Zlt_boolP => X.
  rewrite X in Hrbor.
  move/Zlt_boolP : X => X.
  rewrite Hratmp in X.
  exists C, nj, (u2Z one32); repeat reg_upd.
  do 6 (split; trivial).
  by Assert_upd.
  do 4 (split; trivial).
  by rewrite Hrbor.
  split; first by rewrite u2Z_Z2u.
  move: {Hm1 Hm2}(Hm2 X) => Hm.
  have Hacx0 : store.acx s = Z2u store.acx_size 0.
    apply store.utoZ_acx_beta2; rewrite Hm.
    apply Zlt_plus_swap, Zplus_le_lt_compat; by [apply Zle_refl | rewrite Zopp_involutive].
  rewrite store.utoZ_def Hacx0{Hacx0} u2Z_Z2u // in Hm.
  rewrite Zmult_0_l -Zplus_0_r_reverse in Hm.
  rewrite (_ : Zbeta 2 = Zbeta 1 * (Zbeta 1 - 1) + Zbeta 1) // Zplus_comm (Zmult_comm (Zbeta 1)) in Hm.
  rewrite (_ : forall a b c d, a + b + c - d = a + (b + c - d)) in Hm; last by (move=> *; ring).
  apply poly_eq_inv in Hm; last first.
    rewrite Zbeta1_Zpower2.
    split; first by apply min_u2Z.
    split.
    by split; [apply min_u2Z | apply max_u2Z].
    split; first by done.
    split.
    apply Zle_plus_swap.
    rewrite Zplus_comm.
    apply Zplus_le_compat; by [apply Zlt_le_weak, max_u2Z | apply min_u2Z].
    apply Zlt_plus_swap; apply Zplus_lt_compat_l; by rewrite Zopp_involutive.
  case: Hm => _ Hm.
  rewrite Hinv Hm (Zbeta_S nj) Hrbtmp2 u2Z_Z2u //; ring.
- move/Zle_not_lt.
  move/Zlt_boolP.
  move/negbTE => X.
  rewrite X in Hrbor.
  move/Zlt_boolP : X.
  move/Znot_lt_le => X.
  rewrite Hratmp in X.
  exists C, nj, (u2Z zero32).
  repeat reg_upd; repeat (split; trivial).
  by Assert_upd.
  by rewrite Hrbor.
  by rewrite u2Z_Z2u.
  move: {Hm1 Hm2}(Hm1 X) => Hm.
  have H0 : store.utoZ s < Zbeta 1.
    rewrite Hm.
    apply Zlt_plus_swap.
    apply Zlt_le_trans with (Zbeta 1); first by apply max_u2Z.
    apply Zle_plus_swap, Zle_plus_trans_L => //. by apply neg_Zle, min_u2Z.
  rewrite -(proj2 (proj2 (store.utoZ_lo_beta1 _ H0))).
  rewrite Hinv Hm Hrbtmp2 u2Z_Z2u //; ring.

nop);

apply hoare_nop'.

we are in the branch where btmp = atmp + bor has overflowed

move=> s h [[C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk [Hrt [Hrbor [Hnbor [Hinv [Hratmp [Hrbtmp Hru]]]]]]]]]]]]]]]] Huzero]];
  rewrite /= in Huzero; move/negbTE : Huzero; move/Zeq_boolP => Huzero.
exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
have [X1 X2] : nbor = 1 /\ u2Z (nth nj B zero32) = Zbeta 1 - 1.
  have H : u2Z [btmp]_s < u2Z (nth nj B zero32).
    apply/Zlt_boolP.
    apply: Bool.not_false_is_true => X.
    by rewrite Hru X in Huzero.
  rewrite Hrbtmp in H.
  apply u2Z_add_overflow' in H; rewrite -Zbeta1_Zpower2 in H.
  move: (max_u2Z (nth nj B zero32)) => H'; rewrite -Zbeta1_Zpower2 in H'; omega.
rewrite Hratmp Hinv X1 X2 !Zmult_1_l (Zbeta_S nj); ring.

sw ctmp zero16 t;

apply hoare_sw_back'' with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * Z_of_nat nj /\ u2Z [bor]_s = nbor /\ nbor <= 1 /\
  Sum (S nj) C = Sum (S nj) A - Sum (S nj) B + nbor * Zbeta (S nj)).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk [Hrt [Hrbor [Hnbor Hinv]]]]]]]]]]]]]].

have Htmp : [ add_e (var_e t) (int_e (sext 16 zero16)) ]e_s =
            [ add_e (var_e c) (int_e (Z2u 32 (Z_of_nat (4 * nj)))) ]e_s.
  rewrite [mult]lock /= -lock sext_Z2u // add_0.
  apply u2Z_inj.
  rewrite u2Z_add_Z_of_nat.
  rewrite inj_mult Hrt Hrc; ring.
  rewrite inj_mult -Zbeta1_Zpower2 Hrc; simpl Z_of_nat; omega.

exists (int_e (nth nj C zero32)).
Decompose_32 C nj C1 C2 HlenC1 HC'; last by rewrite HlenC.
rewrite HC' (decompose_equiv _ _ _ _ _ HlenC1) !assert_m.con_assoc_equiv assert_m.con_com_equiv !assert_m.con_assoc_equiv assert_m.con_com_equiv !assert_m.con_assoc_equiv assert_m.con_com_equiv !assert_m.con_assoc_equiv in Hmem.
move: Hmem; apply monotony => // ht.
by apply mapsto_ext.
apply currying => h' H'; simpl app in H'.
exists (update_list C nj [atmp]_s), nj, nbor.
repeat (split; trivial).
by apply len_update_list.
rewrite HC' update_list_app HlenC1 // -minus_n_n /= (decompose_equiv _ _ _ _ _ HlenC1).
assoc_comm H'.
by move: H'; apply mapsto_ext.

rewrite HC' app_comm_cons -app_ass update_list_app'; last by rewrite app_length /= HlenC1 plus_comm.
rewrite update_list_app; last by rewrite HlenC1; apply le_refl.
rewrite HlenC1 -minus_n_n; simpl update_list; simpl app; rewrite -Sum_beyond; last first.
  by rewrite app_length /= HlenC1 plus_comm.
rewrite (Sum_cut nj C1 HlenC1 (S nj) (C1 ++ [atmp]_s :: nil) ([atmp]_s :: nil)) //; last first.
  by rewrite app_length /= HlenC1 plus_comm.
rewrite HC' -Sum_beyond // in Hinv.
rewrite minus_Sn_n -/(Zbeta nj) Zmult_comm Hinv.

Decompose_32 A nj A1 A2 HlenA1 HA'; last by rewrite Ha.
rewrite {3}HA' app_comm_cons -app_ass -Sum_beyond; last by rewrite app_length /= HlenA1 plus_comm.
rewrite (Sum_cut nj A1 HlenA1 (S nj) (A1 ++ nth nj A zero32 :: nil) (nth nj A zero32 :: nil)) //; last first.
  by rewrite app_length /= HlenA1 plus_comm.
rewrite minus_Sn_n.

Decompose_32 B nj B1 B2 HlenB1 HB'; last by rewrite Hb.
rewrite {3}HB' app_comm_cons -app_ass -Sum_beyond; last by rewrite app_length /= HlenB1 plus_comm.
rewrite (Sum_cut nj B1 HlenB1 (S nj) (B1 ++ nth nj B zero32 :: nil) (nth nj B zero32 :: nil)) //; last first.
  by rewrite app_length /= HlenB1 plus_comm.
rewrite minus_Sn_n.

rewrite HA' -Sum_beyond // app_nth2; last by rewrite HlenA1.
rewrite HlenA1 -minus_n_n HB' -Sum_beyond // app_nth2; last by rewrite HlenB1.
rewrite HlenB1 -minus_n_n -/(Zbeta nj) /=; ring.

addiu t t four16;

apply hoare_addiu with (fun s h => exists C, exists nj, exists nbor,
  length C = nk /\ [a]_s = va /\ [b]_s = vb /\
  [c]_s = vc /\ u2Z [k]_s = Z_of_nat nk /\
  (var_e a |--> A ** var_e b |--> B ** var_e c |--> C) s h /\
  u2Z [j]_s = Z_of_nat nj /\ (nj < nk)%nat /\
  u2Z [t]_s = u2Z vc + 4 * (Z_of_nat nj + 1) /\ u2Z [bor]_s = nbor /\
  nbor <= 1 /\ Sum (S nj) C = Sum (S nj) A - Sum (S nj) B + nbor * Zbeta (S nj)).

move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk [Hrt [Hbor [Hnbor Hinv]]]]]]]]]]]]]].

exists C, nj, nbor; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
rewrite u2Z_add sext_Z2u // u2Z_Z2u //.
- omega.
- rewrite -Zbeta1_Zpower2; omega.

addiu j j one16

apply hoare_addiu'.
move=> s h [C [nj [nbor [HlenC [Hra [Hrb [Hrc [Hrk [Hmem [Hrj [Hjk [Hrt [Hbor [Hnbor Hinv]]]]]]]]]]]]]].

exists C, (S nj), nbor; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
rewrite sext_Z2u // u2Z_add_Z2u //.
by rewrite Hrj Z_S.
move: (min_u2Z vc) => ?; rewrite -Zbeta1_Zpower2; omega.
by rewrite Z_S.
Qed.