(** {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) : uint63_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.#[global]
Instance int_ops : ZnZ.Ops int :=
{|
 digits      := Pdigits; (* number of digits *)
 zdigits     := Uint63Axioms.digits; (* number of digits *)
 to_Z        := Uint63Axioms.to_Z; (* conversion to Z *)
 of_pos      := positive_to_int; (* positive -> N*int63 :  p => N,i
                                      where p = N*2^31+phi i *)
 head0       := Uint63.head0;  (* number of head 0 *)
 tail0       := Uint63.tail0;  (* number of tail 0 *)
 zero        := 0;
 one         := 1;
 minus_one   := Uint63Axioms.max_int;
 compare     := Uint63.compare;
 eq0         := Uint63Axioms.is_zero;
 opp_c       := Uint63.oppc;
 opp         := Uint63.opp;
 opp_carry   := Uint63.oppcarry;
 succ_c      := Uint63.succc;
 add_c       := Uint63.addc;
 add_carry_c := Uint63.addcarryc;
 succ        := Uint63.succ;
 add         := Uint63.add;
 add_carry   := Uint63Axioms.addcarry;
 pred_c      := Uint63.predc;
 sub_c       := Uint63.subc;
 sub_carry_c := Uint63.subcarryc;
 pred        := Uint63.pred;
 sub         := Uint63.sub;
 sub_carry   := Uint63.subcarry;
 mul_c       := mulc_WW;
 mul         := Uint63.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   := Uint63.mod;
 modulo      := Uint63.mod;
 gcd_gt      := Uint63.gcd;
 gcd         := Uint63.gcd;
 add_mul_div := Uint63.addmuldiv;
 pos_mod     := pos_mod_int;
 is_even     := Uint63Axioms.is_even;
 sqrt2       := Uint63.sqrt2;
 sqrt        := Uint63.sqrt;
 ZnZ.lor     := Uint63.lor;
 ZnZ.land    := Uint63.land;
 ZnZ.lxor    := Uint63.lxor
|}.

Lemma shift_unshift_mod_2 : forall n p a, 0 <= p <= n -> ((a * 2 ^ (n - p)) mod (2^n) / 2 ^ (n - p)) mod (2^n) = a mod 2 ^ p.