(* KE EP TOGETHER> *)
unfold r'_i. elim d_Si_eq; intro H. rewrite ltw_true. rewrite r_Si_eq_a. rewrite H. apply modred. apply Zplus_le_0_compat.
apply Zmod_le_0_z. omega. apply Zmod_le_0_z. apply lt_0_Zpow. auto with a. apply Zlt_le_trans with (M + 2 ^ p).
apply Zplus_lt_le_compat. apply Zmod_lt_z_m. omega. apply Zlt_le_weak. apply Zmod_lt_z_m. apply lt_0_Zpow. auto with a.
rewrite Zpow_2_w_is_2Zpow_2_wm1. apply Zplus_le_compat. assumption. apply Zle_pow_le. auto with a. cut (p < w). omega.
auto with a. rewrite H. fold M. apply Zmod_lt_z_m. omega. elim H; intro H0. rewrite ltw_false. simpl. rewrite r_Si_eq_a. fold M.
rewrite H0. rewrite <- Zmod_minus_distr_l.
replace (((h mod M * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + M + (h mod M * 2 ^ w + l) mod 2 ^ p - M)
with (((h mod M * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + (h mod M * 2 ^ w + l) mod 2 ^ p).
apply modred. apply Zplus_le_0_compat. apply Zmod_le_0_z. omega. apply Zmod_le_0_z. apply lt_0_Zpow. auto with a.
apply Zlt_le_trans with (M + 2 ^ p). apply Zplus_lt_le_compat. apply Zmod_lt_z_m. omega. apply Zlt_le_weak. apply Zmod_lt_z_m.
apply lt_0_Zpow. auto with a. rewrite Zpow_2_w_is_2Zpow_2_wm1. apply Zplus_le_compat. assumption. apply Zle_pow_le. auto with a.
cut (p < w). omega. auto with a. ring. exact lt02w. rewrite H0. fold M.
cut (0 <= ((h mod M * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M). omega. apply Zmod_le_0_z. omega. elim H0; intro H1.
rewrite ltw_true. rewrite r_Si_eq_b. rewrite H1. rewrite p2wp. rewrite Zmult_assoc. rewrite mod_over_div.
rewrite Zmod_mult_distr_l with (a := h mod M + M). replace (h mod M + M) with (h mod M + 1 * M). rewrite Z_mod_plus.
rewrite <- Zmod_mult_distr_l. rewrite <- mod_over_div. rewrite <- Zmult_assoc. rewrite <- Zmult_assoc. rewrite <- Zpower_exp.
replace (w - p + p) with w. rewrite mod2p with (c' := h mod M). apply modred. apply Zplus_le_0_compat.
apply Zmod_le_0_z. omega. apply Zmod_le_0_z. apply lt_0_Zpow. auto with a. apply Zlt_le_trans with (M + 2 ^ p).
apply Zplus_lt_le_compat. apply Zmod_lt_z_m. omega. apply Zlt_le_weak. apply Zmod_lt_z_m. apply lt_0_Zpow. auto with a.
rewrite Zpow_2_w_is_2Zpow_2_wm1. apply Zplus_le_compat. assumption. apply Zle_pow_le. auto with a. cut (p < w). omega.
auto with a. ring. cut (p < w). omega. auto with a. apply Zle_ge. auto with a. apply lt_0_Zpow. auto with a. omega. omega.
omega. ring. omega. apply lt_0_Zpow. auto with a. omega. rewrite H1. fold M. apply Zmod_lt_z_m. omega.
rewrite ltw_false. simpl. rewrite r_Si_eq_b. rewrite H1.
(* rewrite p2wp. *) (* does not work: Cannot solve a second-order unification problem *)
(* replace ((h mod M + M) * 2 ^ w) with ((h mod M + M) * (2 ^ (w - p) * 2 ^ p)). *) (* again, does not work *)
transitivity ((((((h mod M + M) * (2 ^ (w - p) * 2 ^ p) + l) / 2 ^ p * 2 ^ p) mod M + M +
((h mod M + M) * (2 ^ (w - p) * 2 ^ p) + l) mod 2 ^ p) mod
(2 ^ (w - p) * 2 ^ p) - M) mod (2 ^ (w - p) * 2 ^ p)). (* workaround *)
rewrite <- p2wp. trivial. (* this works *)
rewrite Zmult_assoc. rewrite mod_over_div.
rewrite Zmod_mult_distr_l with (a := h mod M + M). replace (h mod M + M) with (h mod M + 1 * M). rewrite Z_mod_plus.
rewrite <- Zmod_mult_distr_l. rewrite <- mod_over_div. rewrite <- Zmult_assoc. rewrite <- Zmult_assoc. rewrite <- Zpower_exp.
replace (w - p + p) with w. rewrite mod2p with (c' := h mod M). rewrite <- Zmod_minus_distr_l. fold M.
replace (((h mod M * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + M + (h mod M * 2 ^ w + l) mod 2 ^ p - M)
with (((h mod M * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + (h mod M * 2 ^ w + l) mod 2 ^ p). apply modred.
apply Zplus_le_0_compat. apply Zmod_le_0_z. omega. apply Zmod_le_0_z. apply lt_0_Zpow. auto with a.
apply Zlt_le_trans with (M + 2 ^ p). apply Zplus_lt_le_compat. apply Zmod_lt_z_m. omega. apply Zlt_le_weak. apply Zmod_lt_z_m.
apply lt_0_Zpow. auto with a. rewrite Zpow_2_w_is_2Zpow_2_wm1. apply Zplus_le_compat. assumption. apply Zle_pow_le. auto with a.
cut (p < w). omega. auto with a. ring. auto with a. ring. cut (p < w). omega. auto with a. apply Zle_ge. auto with a.
apply lt_0_Zpow. auto with a. omega. omega. omega. ring. omega. apply lt_0_Zpow. auto with a. omega. rewrite H1. fold M.
cut (0 <= (((h mod M + M) * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M). omega. apply Zmod_le_0_z. omega. Qed.
Let x'' := h mod M * 2 ^ w + l.

(* Specifications: *)
Lemma sum_r'_i : forall a b : Z, (a mod M + b mod M) / M = 0 \/ (a mod M + b mod M) / M = 1.
clear x_i_in_Z_ x_i s_i s'_i s''_i h'_i q_i q'_i y_i h'_i h'_i' x'.