(************************************************************************)
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
(* <O___,, *   INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2018     *)
(*   \VV/  **************************************************************)
(*    //   *      This file is distributed under the terms of the       *)
(*         *       GNU Lesser General Public License Version 2.1        *)
(************************************************************************)
(** * Int63 numbers defines indeed a cyclic structure : Z/(2^31)Z *)
(** Author: Arnaud Spiwack (+ Pierre Letouzey) *)
Require Export ZArith.
Require Export Int63.
Local Open Scope int63_scope.
(** {2 Operators } **)
Definition Pdigits := Eval compute in P_of_succ_nat (size - 1).
Fixpoint positive_to_int_rec (n:nat) (p:positive) :=
match n, p with
| O, _ => (Npos p, 0)
| S n, xH => (0%N, 1)
| S n, xO p =>
let (N,i) := positive_to_int_rec n p in
(N, i << 1)
| S n, xI p =>
let (N,i) := positive_to_int_rec n p in
(N, (i << 1) + 1)
end.
Definition positive_to_int := positive_to_int_rec size.
Definition mulc_WW x y :=
let (h, l) := mulc x y in
if is_zero h then
if is_zero l then W0
else WW h l
else WW h l.
Notation "n '*c' m" := (mulc_WW n m) (at level 40, no associativity) : int63_scope.
Definition pos_mod p x :=
if p <= digits then
let p := digits - p in
(x << p) >> p
else x.
Notation pos_mod_int := pos_mod.
Instance int_ops : ZnZ.Ops int :=
{|
digits      := Pdigits; (* number of digits *)
zdigits     := Int63.digits; (* number of digits *)
to_Z        := Int63.to_Z; (* conversion to Z *)
of_pos      := positive_to_int; (* positive -> N*int63 :  p => N,i
where p = N*2^31+phi i *)
head0       := Int63.head0;  (* number of head 0 *)
tail0       := Int63.tail0;  (* number of tail 0 *)
zero        := 0;
one         := 1;
minus_one   := Int63.max_int;
compare     := Int63.compare;
eq0         := Int63.is_zero;
opp_c       := Int63.oppc;
opp         := Int63.opp;
opp_carry   := Int63.oppcarry;
succ_c      := Int63.succc;
add_c       := Int63.addc;
add_carry_c := Int63.addcarryc;
succ        := Int63.succ;
add         := Int63.add;
add_carry   := Int63.addcarry;
pred_c      := Int63.predc;
sub_c       := Int63.subc;
sub_carry_c := Int63.subcarryc;
pred        := Int63.pred;
sub         := Int63.sub;
sub_carry   := Int63.subcarry;
mul_c       := mulc_WW;
mul         := Int63.mul;
square_c    := fun x => mulc_WW x x;
div21       := diveucl_21;
div_gt      := diveucl; (* this is supposed to be the special case of
division a/b where a > b *)
div         := diveucl;
modulo_gt   := Int63.mod;
modulo      := Int63.mod;
gcd_gt      := Int63.gcd;
gcd         := Int63.gcd;
add_mul_div := Int63.addmuldiv;
pos_mod     := pos_mod_int;
is_even     := Int63.is_even;
sqrt2       := Int63.sqrt2;
sqrt        := Int63.sqrt;
ZnZ.lor     := Int63.lor;
ZnZ.land    := Int63.land;
ZnZ.lxor    := Int63.lxor
|}.
Local Open Scope Z_scope.
Proof (fun x => mulc_WW_spec x x).

Lemma pos_mod_spec w p : φ(pos_mod p w) = φ(w) mod (2 ^ φ(p)).