(* Extra function on equality *)

(* Specifications: *)
Lemma cast_refl : forall i, cast i i = Some (fun P H => H).
Lemma cast_diff : forall i j, i =? j = false -> cast i j = None.
Definition eqo i j :=
(if i =? j as b return ((b = true -> i = j) -> option (i=j))
then fun Heq : true = true -> i = j =>
Some (Heq (eq_refl true))
else fun _ : false = true -> i = j => None) (eqb_correct i j).
Lemma eqo_refl : forall i, eqo i i = Some (eq_refl i).
Lemma eqo_diff : forall i j, i =? j = false -> eqo i j = None.
(** Comparison *)
Lemma eqbP x y : reflect (φ  x  = φ  y ) (x =? y).
Lemma is_zero_spec x : is_zero x = true <-> x = 0%uint63.
Local Open Scope Z_scope.
(** Addition *)
Lemma addc_spec x y : [+| x +c y |] = φ  x  + φ  y .
Lemma succ_spec x : φ (succ x)  = (φ  x  + 1) mod wB.
(** Subtraction *)
Lemma subc_spec x y : [-| x -c y |] = φ  x  - φ  y .
Lemma pred_spec x : φ (pred x) = (φ  x  - 1) mod wB.
Lemma subcarry_spec x y : φ (subcarry x y) = (φ  x  - φ  y  - 1) mod wB.
(** GCD *)
Lemma to_Z_gcd : forall i j, φ (gcd i j)  = Zgcdn (2 * size) (φ  j) (φ  i).
Lemma gcd_spec a b : Zis_gcd (φ  a) (φ  b) (φ (gcd a b)).
(** Head0, Tail0 *)
Lemma head00_spec x : φ  x = 0 -> φ (head0 x) = φ  digits .
Lemma eqm_sub x y : x ≡ y → x - y ≡ 0.
Lemma eqm_subE x y : x ≡ y ↔ x - y ≡ 0.
Lemma int_eqm x y : x = y → φ x ≡ φ y.
(* ADD *)
Lemma add_assoc x y z: (x + (y + z) = (x + y) + z)%uint63.
Lemma add_comm x y: (x + y = y + x)%uint63.
Lemma add_le_r m n:
if  (n <=? m + n)%uint63 then  (φ m + φ n < wB)%Z else  (wB <= φ m + φ n)%Z.
Lemma add_cancel_l x y z : (x + y = x + z)%uint63 -> y = z.
Lemma add_cancel_r x y z : (y + x = z + x)%uint63 -> y = z.
Coercion b2i (b: bool) : int := if b then 1%uint63 else 0%uint63.
(* LSR *)
Lemma lsr0 i : 0 >> i = 0%uint63.
Lemma lsr_add i m n: ((i >> m) >> n = if n <=? m + n then i >> (m + n) else 0)%uint63.
(* LSL *)
Lemma lsl0 i: 0 << i = 0%uint63.
Lemma lsl0_r i : i << 0 = i.
Lemma lsl_add_distr x y n: (x + y) << n = ((x << n) + (y << n))%uint63.
Lemma lsr_M_r x i (H: (digits <=? i = true)%uint63) : x >> i = 0%uint63.
(* BIT *)
Lemma bit_0_spec i: φ (bit i 0) = φ i mod 2.
Lemma bit_split i : ( i = (i >> 1 ) << 1 + bit i 0)%uint63.
Lemma bit_lsr x i j :
(bit (x >> i) j = if j <=? i + j then bit x (i + j) else false)%uint63.
Lemma bit_b2i (b: bool) i : bit b i = (i =? 0)%uint63 && b.
Lemma bit_1 n : bit 1 n = (n =? 0)%uint63.
Local Hint Resolve Z.lt_gt Z.div_pos : zarith.
Lemma to_Z_split x : φ x = φ (x  >> 1) * 2 + φ (bit x 0).
Lemma bit_M i n (H: (digits <=? n = true)%uint63): bit i n = false.
Lemma bit_ext i j : (forall n, bit i n = bit j n) -> i = j.
Lemma bit_lsl x i j : bit (x << i) j =
(if (j <? i) || (digits <=? j) then false else bit x (j - i))%uint63.
(* LOR *)
Lemma lor_lsr i1 i2 i: (i1 lor i2) >> i = (i1 >> i) lor (i2 >> i).
Lemma lor_le x y : (y <=? x lor y)%uint63 = true.
Lemma bit_0 n : bit 0 n = false.
Lemma addmuldiv_spec x y p :
φ p <= φ digits  ->
φ (addmuldiv p x y)  = (φ x * (2 ^ φ p) + φ y / (2 ^ (φ digits - φ  p))) mod wB.
(* is_even *)
Lemma is_even_bit i : is_even i = negb (bit i 0).
Lemma is_even_spec x : if is_even x then φ x mod 2 = 0 else φ x mod 2 = 1.
Lemma is_even_0 : is_even 0 = true.
Ltac elim_div :=
unfold Z.div, Z.modulo;
match goal with
|  H : context[ Z.div_eucl ?X ?Y ] |-  _ =>
generalize dependent H; generalize (Z_div_mod_full X Y) ; case (Z.div_eucl X Y)
|  |-  context[ Z.div_eucl ?X ?Y ] =>
generalize (Z_div_mod_full X Y) ; case (Z.div_eucl X Y)
end; unfold Remainder.