(* KE EP TOGETHER> *)
unfold r'_i. elim d_Si_eq; intro H. left. rewrite ltw_true. rewrite r_Si_eq_a. rewrite H. apply modred. apply Zplus_le_0_compat.
apply le_0_mod_M. apply le_0_2pp. apply lt_plus_M_2p_2w. rewrite H. apply Zlt_le_trans with M. apply Zmod_lt_z_m. omega.
fold c. rewrite c_M. exact le_M_2pp. elim H; intro H0. elim (Zle_or_lt c d_Si); intro H1. rewrite ltw_false. simpl. left.
rewrite r_Si_eq_a. rewrite H0. fold M. 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) mod M) 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) mod M) mod 2 ^ p).
apply modred. apply Zplus_le_0_compat. apply le_0_mod_M. apply le_0_2pp. apply lt_plus_M_2p_2w. ring. auto with a. assumption.
rewrite ltw_true. right. rewrite r_Si_eq_a. rewrite <- H0. apply modred. apply Zplus_le_0_compat. apply le_0__Z. apply le_0_2pp.
apply Zlt_le_trans with (c + 2 ^ p). apply Zplus_lt_compat. assumption. apply Zmod_lt_z_m. auto with a.
rewrite Zpow_2_w_is_2Zpow_2_wm1. apply Zplus_le_compat. rewrite c_M. apply Zle_pow_le. auto with a. cut (p < w). omega.
auto with a. apply Zle_pow_le. auto with a. cut (p < w). omega. auto with a. assumption. elim H0; intro H1. left.
rewrite ltw_true. rewrite r_Si_eq_b. rewrite H1.
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 M) mod 2 ^ p) mod
(2 ^ (w - p) * 2 ^ p) - M) mod (2 ^ (w - p) * 2 ^ p)). (* workaround *)
rewrite <- p2wp. rewrite <- Zmod_minus_distr_l.
replace ((((h mod M + M) * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + M + ((h mod M + M) * 2 ^ w + (l mod 2 ^ p) mod M) mod 2 ^ p - M)
with ((((h mod M + M) * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + ((h mod M + M) * 2 ^ w + (l mod 2 ^ p) mod M) mod 2 ^ p).
trivial. ring. exact lt02w. 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.
replace (((h mod M * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + M + (h mod M * 2 ^ w + (l mod 2 ^ p) mod M) 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) mod M) mod 2 ^ p).
apply modred. apply Zplus_le_0_compat. apply le_0_mod_M. apply le_0_2pp. apply lt_plus_M_2p_2w. ring. auto with a. ring.
cut (p < w). omega. auto with a. apply Zle_ge. auto with a. auto with a. omega. omega. omega. ring. omega. auto with a.
omega. rewrite H1. apply Zlt_le_trans with M. apply Zmod_lt_z_m. omega. fold c. rewrite c_M. exact le_M_2pp.
elim (Zle_or_lt c d_Si); intro H2. rewrite ltw_false. simpl. left. rewrite r_Si_eq_b. rewrite H1. fold M.
rewrite <- Zmod_minus_distr_l.
replace ((((h mod M + M) * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + M + ((h mod M + M) * 2 ^ w + (l mod 2 ^ p) mod M) mod 2 ^ p - M)
with ((((h mod M + M) * 2 ^ w + l) / 2 ^ p * 2 ^ p) mod M + ((h mod M + M) * 2 ^ w + (l mod 2 ^ p) mod M) mod 2 ^ p).
rewrite modred. rewrite divmultmodM. rewrite Zmod_plus_m. rewrite <- divmultmodM. rewrite r'0plus. rewrite r'0plus. trivial.
omega. apply Zplus_le_0_compat. apply le_0_mod_M. apply le_0_2pp. apply lt_plus_M_2p_2w. ring. auto with a. assumption.
rewrite ltw_true. rewrite r_Si_eq_b. right. rewrite r'0plus. rewrite r'0plus. rewrite modred. rewrite H1. rewrite divmultmodM.
rewrite Zmod_plus_m. rewrite <- divmultmodM. trivial. omega. apply Zplus_le_0_compat. apply le_0__Z. apply le_0_2pp.
apply Zlt_le_trans with (c + 2 ^ p). apply Zplus_lt_compat. assumption. apply Zmod_lt_z_m. auto with a.
rewrite Zpow_2_w_is_2Zpow_2_wm1. apply Zplus_le_compat. rewrite c_M. apply Zle_pow_le. auto with a. cut (p < w). omega.
auto with a. apply Zle_pow_le. auto with a. cut (p < w). omega. auto with a. assumption. Qed.

(* Specifications: *)
Lemma r'_i_eq'_i : _Z r'_i = x mod M \/ _Z r'_i = x mod M + M \/ _Z r'_i = x mod M + M + M.
elim r'_i_eq; intro H; rewrite H. rewrite Zdiv_a_b_b_Zmod. replace w with (w - p + p). rewrite Zpower_exp.