Section parm_sec.
Variable M_in_Z_ : Z_ (2 ^ w).
Variable ptM'cM'' : Z_ w * Z_ w * Z_ (2 ^ w) * Z_ (2 ^ w) * Z_ (2 ^ w).
Variable d_Sir_Si : Z_ (2 ^ w) * Z_ (2 ^ w).
Variable l_in_Z_ : Z_ (2 ^ w).
Variable x_i_in_Z_ : Z_ (2 ^ w).
Variable h : Z.
Let p_in_Z_w := fst (fst (fst (fst ptM'cM''))).
Let t_in_Z_w := snd (fst (fst (fst ptM'cM''))).
Let M'_in_Z_ := snd (fst (fst ptM'cM'')).
Let c_in_Z_ := snd (fst ptM'cM'').
Let M''_in_Z_ := snd ptM'cM''.
Let M := _Z M_in_Z_.
Let p := _Z p_in_Z_w.
Let t := _Z t_in_Z_w.
Let c := _Z c_in_Z_.
Let M'' := _Z M''_in_Z_.
Let M' := _Z M'_in_Z_.
Let l := _Z l_in_Z_.
Let x_i := _Z x_i_in_Z_.
Definition d_Si := fst d_Sir_Si.
Definition r_Si := snd d_Sir_Si.
Hypothesis d_Si_eq_r_Si_eq : P M p d_Si r_Si h l_in_Z_.
Hypothesis le_1_M : 1 <= M.
Hypothesis le_M_max : M <= 2 ^ (w - 1).
Hypothesis p_M : p = Zlog_sup M.
Hypothesis t_M : t = w - p \/ M = 1.
Hypothesis c_M : c = 2 ^ p.
Hypothesis M''_M : M'' = (2 ^ t * M) mod 2 ^ w.
Hypothesis M'_M : M' = 2 ^ (p + w) / M mod 2 ^ w.
unfold p. apply le_0__Z. Qed.
apply Zlt_le_weak. exact lt02w. Qed.
Local Hint Resolve le_0_w lt02w le02w : a.
Local Hint Resolve le_0_p : a.
clear x_i_in_Z_ x_i.
rewrite p_M. generalize le_1_M. case M. intro. absurd (2 <= 0); omega. intros q H.
elim (Zlog_sup_correct2 (Zpos q)). omega. omega. intros q H. absurd (2 <= Zneg q). apply Zlt_not_le.
unfold Z.lt. trivial. assumption. Qed.
clear x_i_in_Z_ x_i.
rewrite p_M. elim (Zle_lt_or_eq 1 M). intro H. left. apply Z.le_trans with (Zlog_sup 2). simpl. omega.
apply Zlog_sup_seq. omega. intro H. right. symmetry. trivial. assumption. Qed.
clear x_i_in_Z_ x_i.
elim le_1_p; intro H; omega. Qed.
clear x_i_in_Z_ x_i.
elim lt_0_p; intro H; omega. Qed.
Local Hint Resolve le_M_2pp le_1_p lt_0_p le_0_pm1 : a.
clear x_i_in_Z_ x_i.
elim (Zle_lt_or_eq 1 M). intro H. rewrite p_M. generalize le_1_M. case M. intro. absurd (2 <= 0); omega.
intros q H0. elim (Zlog_sup_correct2 (Zpos q)). omega. omega. intros q H0. absurd (1 <= Zneg q).
apply Zlt_not_le. unfold Z.lt. trivial. assumption. omega. assumption. Qed.
Local Hint Resolve lt_2pm1_M : a.
clear x_i_in_Z_ x_i.
elim (Zle_lt_or_eq 1 M). intro H. replace (2 ^ p) with (1 * M + (2 ^ p - M)). apply Zdiv_mult_plus. omega.
cut (M <= 2 ^ p). omega. auto with a. cut (2 ^ p < M + M). omega.
apply Z.lt_le_trans with (2 ^ (p - 1) + 1 + (2 ^ (p - 1) + 1)).
replace (2 ^ (p - 1) + 1 + (2 ^ (p - 1) + 1)) with (2 ^ (p - 1) + 2 ^ (p - 1) + 2). rewrite Z_pow_plus.
replace (p - 1 + 1) with p. omega. ring. elim le_0_pm1. omega. intro H0. absurd (1 < M). omega.
assumption. ring. cut (2 ^ (p - 1) < M). omega. elim lt_2pm1_M. omega. intro H0. absurd (1 < M). omega.
assumption. ring. intro H0. rewrite p_M. rewrite <- H0. trivial. assumption. Qed.
transitivity (2 ^ (p + w) / M / 2 ^ w * 2 ^ w + (2 ^ (p + w) / M) mod 2 ^ w).
apply f_equal2 with (f := Zplus). replace (2 ^ (p + w) / M / 2 ^ w) with 1. ring.
rewrite Zdivdivdiv. rewrite Zmult_comm. rewrite <- Zdivdivdiv. rewrite Zpower_exp; auto with a.
rewrite Z_div_mult. symmetry. exact div_M_1. apply Z.lt_gt. auto with a. apply Z.le_ge. auto with a.
apply Z.le_ge. auto with a. auto with a. omega. omega. auto with a. trivial. apply Zdivmod_split.
auto with a. Qed.
(* <KEEP TOGETHER - multired_equations *)
Let r'_i := ltw d_Si M_in_Z_ r_Si (minusw r_Si M_in_Z_).
Let s_i := ursh x_i_in_Z_ p_in_Z_w.
Let s'_i := multp2 s_i p_in_Z_w.
Let s''_i := ltw r'_i c_in_Z_ s_i (minusw s_i M''_in_Z_).
Let h_i := multp2 r'_i t_in_Z_w.
Let h'_i := plusw h_i s''_i.
Let q_i := uhwm h'_i M'_in_Z_.
Let q'_i := plusw q_i h'_i.
Let y_i := multw q'_i M_in_Z_.
Definition d_i := minusw s'_i y_i.
Definition r_i := minusw x_i_in_Z_ y_i.
(* KEEP TOGETHER> *)
Let d0 := d_Si. (* notation *)
Let r0 := r_Si. (* notation *)
(* <KEEP TOGETHER - multired_final *)
Let r'0 := ltw d0 M_in_Z_ r0 (minusw r0 M_in_Z_). (* notation *)
Let r''0 := ltw r'0 c_in_Z_ r'0 (minusw r'0 M_in_Z_). (* only needed after the loop *)
Definition r'''0 := ltw r''0 M_in_Z_ r''0 (minusw r''0 M_in_Z_). (* only needed after the loop *)
(* KEEP TOGETHER> *)
Let h_i' := multp2 r''0 t_in_Z_w.
Let h'_i' := plusw h_i' s_i.
Definition g' := r'''0. (* only needed after the loop *)
Let x := h * 2 ^ w + l.
Let x' := r''0 * 2 ^ w + x_i.
unfold x'. rewrite Zmod_km_plus. symmetry. unfold x_i. apply modred. apply le_0__Z. apply lt_z__Z. exact lt02w. Qed.
apply lt_0_Zpow. fold (0 + 0). apply Zplus_le_compat; auto with a. Qed.
apply lt_0_Zpow. auto with a. Qed.
Local Hint Resolve lt_0_2pp : a.
clear. cut (0 < w). omega. exact lt_0_w. Qed.
Local Hint Resolve le_0_wm1 lt_0_w : a.
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'.
rewrite p_M. apply Z.le_lt_trans with (w - 1). rewrite <- Zlog_sup_pow. apply Zlog_sup_seq.
assumption. auto with a. omega. Qed.
apply Zlt_le_weak. exact lt_p_w. Qed.
cut (p <= w). omega. exact le_p_w. Qed.
Local Hint Resolve lt_p_w le_p_w le_0_wmp : a.
unfold M. apply lt_z__Z. Qed.
apply Zlt_le_weak. exact lt_M_2pw. Qed.
Hint Resolve lt_M_2pw le_M_2pw : a.
unfold P in d_Si_eq_r_Si_eq. tauto. Qed.
unfold P in d_Si_eq_r_Si_eq. tauto. Qed.
clear x_i_in_Z_ x_i s_i s'_i s''_i h'_i q_i q'_i y_i h'_i' x'.
replace (h mod M * 2 ^ w) with (0 + h mod M * 2 ^ (w - p + p)). rewrite Zpower_exp. rewrite Zmult_assoc.
rewrite Zmod_plus_distr_l with (m := 2 ^ p). rewrite Z_mod_plus. rewrite modred with (x := 0).
replace (0 + l) with l. exact r_Si_eq_lit. ring. omega. apply lt_0_Zpow. auto with a.
apply Z.lt_gt. apply Z.lt_le_trans with M. omega. auto with a. apply lt_0_Zpow. auto with a. cut (p < w). omega. auto with a.
apply Z.le_ge. auto with a. replace (w - p + p) with w. ring. ring. Qed.
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'.
replace ((h mod M + M) * 2 ^ w) with (0 + (h mod M + M) * 2 ^ (w - p + p)). rewrite Zpower_exp. rewrite Zmult_assoc.
rewrite Zmod_plus_distr_l with (m := 2 ^ p). rewrite Z_mod_plus. rewrite modred with (x := 0).
replace (0 + l) with l. exact r_Si_eq_lit. ring. omega. apply lt_0_Zpow. auto with a.
apply Z.lt_gt. apply Z.lt_le_trans with M. omega. auto with a. apply lt_0_Zpow. auto with a. cut (p < w). omega. auto with a.
apply Z.le_ge. auto with a. replace (w - p + p) with w. ring. ring. Qed.

Lemma p2wp : 2 ^ w = 2 ^ (w - p) * 2 ^ p.