Section ZModulo.
Variable digits : positive.
Hypothesis digits_ne_1 : digits <> 1%positive.
Definition wB := base digits.
Definition t := Z.
Definition zdigits := Zpos digits.
Definition to_Z x := x mod wB.
Notation "[| x |]" := (to_Z x)  (at level 0, x at level 99).
Notation "[+| c |]" :=
(interp_carry 1 wB to_Z c)  (at level 0, c at level 99).
Notation "[-| c |]" :=
(interp_carry (-1) wB to_Z c)  (at level 0, c at level 99).
Notation "[|| x ||]" :=
(zn2z_to_Z wB to_Z x)  (at level 0, x at level 99).
Let digits_gt_1 := spec_more_than_1_digit.
Hint Resolve wB_pos : core.
Hint Resolve spec_to_Z_1 spec_to_Z_2 : core.
Definition of_pos x :=
let (q,r) := Z.pos_div_eucl x wB in (N_of_Z q, r).
Definition zero := 0.
Definition one := 1.
Definition minus_one := wB - 1.
Definition compare x y := Z.compare [|x|] [|y|].
Definition opp_c x :=
if eq0 x then C0 0 else C1 (- x).
Definition opp x := - x.
Definition opp_carry x := - x - 1.
Definition succ_c x :=
let y := Z.succ x in
if eq0 y then C1 0 else C0 y.
Definition add_c x y :=
let z := [|x|] + [|y|] in
if Z_lt_le_dec z wB then C0 z else C1 (z-wB).
Definition add_carry_c x y :=
let z := [|x|]+[|y|]+1 in
if Z_lt_le_dec z wB then C0 z else C1 (z-wB).
Definition succ := Z.succ.
Definition add := Z.add.
Definition add_carry x y := x + y + 1.
Definition pred_c x :=
if eq0 x then C1 (wB-1) else C0 (x-1).
Definition sub_c x y :=
let z := [|x|]-[|y|] in
if Z_lt_le_dec z 0 then C1 (wB+z) else C0 z.
Definition sub_carry_c x y :=
let z := [|x|]-[|y|]-1 in
if Z_lt_le_dec z 0 then C1 (wB+z) else C0 z.
Definition pred := Z.pred.
Definition sub := Z.sub.
Definition sub_carry x y := x - y - 1.
Definition mul_c x y :=
let (h,l) := Z.div_eucl ([|x|]*[|y|]) wB in
if eq0 h then if eq0 l then W0 else WW h l else WW h l.
Definition mul := Z.mul.
Definition square_c x := mul_c x x.
Definition div x y := Z.div_eucl [|x|] [|y|].
Definition div_gt := div.
Definition modulo x y := [|x|] mod [|y|].
Definition modulo_gt x y := [|x|] mod [|y|].
Definition gcd x y := Z.gcd [|x|] [|y|].
Definition gcd_gt x y := Z.gcd [|x|] [|y|].
Definition div21 a1 a2 b :=
Z.div_eucl ([|a1|]*wB+[|a2|]) [|b|].
Definition add_mul_div p x y :=
([|x|] * (2 ^ [|p|]) + [|y|] / (2 ^ ((Zpos digits) - [|p|]))).

Lemma spec_add_mul_div : forall x y p,
[|p|] <= Zpos digits ->
[| add_mul_div p x y |] =
([|x|] * (2 ^ [|p|]) +
[|y|] / (2 ^ ((Zpos digits) - [|p|]))) mod wB.