val lemma_of_to_quad32_mask (a:poly) : Lemma
  (of_quad32 (to_quad32 a) == mask a 128)
let lemma_of_to_quad32_mask a =
  reveal_to_quad32 a;
  reveal_of_quad32 (to_quad32 a);
  lemma_index_all ();
  lemma_reverse_define_all ();
  lemma_mask_define_all ();
  lemma_equal (mask a 128) (of_quad32 (to_quad32 a))
val lemma_of_to_quad32_mask (a:poly) : Lemma
  (of_quad32 (to_quad32 a) == mask a 128)
let lemma_of_to_quad32_mask a =
reveal_to_quad32 a;
reveal_of_quad32 (to_quad32 a);
lemma_index_all ();
lemma_reverse_define_all ();
lemma_mask_define_all ();
lemma_equal (mask a 128) (of_quad32 (to_quad32 a))
Vale.Math.Poly2.Bits.fst.checked
Vale.Arch.TypesNative.fsti.checked prims.fst.checked FStar.UInt.fsti.checked FStar.Pervasives.fsti.checked FStar.Mul.fst.checked FStar.Classical.fsti.checked
Vale.Math.Poly2.Bits.fst
Vale.Math.Poly2_s.poly Vale.Math.Poly2.lemma_equal Vale.Math.Poly2.mask Vale.Math.Poly2.Bits_s.of_quad32 Vale.Math.Poly2.Bits_s.to_quad32 Prims.unit Vale.Math.Poly2.Lemmas.lemma_mask_define_all Vale.Math.Poly2.Lemmas.lemma_reverse_define_all Vale.Math.Poly2.Lemmas.lemma_index_all Vale.Math.Poly2.Bits_s.reveal_of_quad32 Vale.Math.Poly2.Bits_s.reveal_to_quad32
module Vale.Math.Poly2.Bits
open FStar.Mul
open Vale.Arch.TypesNative

let lemma_to_of_uint n u =
  let a = of_uint n u in
  let u' = to_uint n a in
  lemma_index a;
  lemma_reverse_define_all ();
  let s = UInt.to_vec #n u in
  let s' = UInt.to_vec #n u' in
  assert (equal s s');
  ()

let rec of_nat x =
  if x = 0 then zero
  else
    let p = shift (of_nat (x / 2)) 1 in
    if x % 2 = 0 then p else p +. one

let rec lemma_of_to_vec_zero (i:nat) (n:nat) : Lemma
  (requires i < n)
  (ensures index (to_vec #n 0) i == false)
  [SMTPat (index (to_vec #n 0) i)]
  =
  if i + 1 < n then lemma_of_to_vec_zero i (n - 1)

let lemma_of_uint_zero (n:nat) : Lemma
  (ensures of_uint_ n 0 == zero)
  =
  lemma_bitwise_all ();
  lemma_equal (of_uint_ n 0) zero

let rec lemma_of_nat_of_uint n x
  =
  if n > 0 then
  (
    lemma_of_nat_of_uint (n - 1) (x / 2);
    lemma_bitwise_all ();
    lemma_equal (of_nat x) (of_uint n x)
  )

let rec lemma_to_nat_rec (len:nat) (p:poly) (c:nat) (n:nat) (i:nat) : Lemma
  (requires degree p < len /\ normalize (poly_nat_eq_rec len p c n))
  (ensures p.[len - n + i] == (of_nat c).[i])
  =
  lemma_bitwise_all ();
  if (i > 0 && n > 0) then lemma_to_nat_rec len p (c / 2) (n - 1) (i - 1)

let lemma_to_nat len p c =
  lemma_bitwise_all ();
  let f (i:int) : Lemma (p.[i] == (of_nat c).[i]) =
    if 0 <= i then lemma_to_nat_rec len p c len i
    in
  FStar.Classical.forall_intro f;
  lemma_equal p (of_nat c)

let of_nat32 n =
  lemma_of_nat_of_uint 32 n;
  of_uint 32 n

let lemma_of_nat_of_uint32 (x:nat32) : Lemma
  (ensures of_nat32 x == of_nat x)
  =
  lemma_of_nat_of_uint 32 x

let of_nat32_zero =
  lemma_bitwise_all ();
  lemma_zero_nth 32;
  lemma_equal (of_nat32 0) zero

let of_nat32_ones =
  lemma_bitwise_all ();
  lemma_to_nat 32 (ones 32) 0xffffffff

let of_nat32_eq a b =
  lemma_of_nat_of_uint 32 a;
  lemma_of_nat_of_uint 32 b;
  lemma_to_of_uint 32 a;
  lemma_to_of_uint 32 b;
  ()

let of_nat32_xor a b =
  lemma_bitwise_all ();
  lemma_ixor_nth_all 32;
  lemma_equal (of_nat32 a +. of_nat32 b) (of_nat32 (ixor a b))

let of_nat32_and a b =
  lemma_bitwise_all ();
  lemma_iand_nth_all 32;
  lemma_equal (poly_and (of_nat32 a) (of_nat32 b)) (of_nat32 (iand a b))

let lemma_poly128_extract_nat32s a0 a1 a2 a3 =
  let a = poly128_of_nat32s a0 a1 a2 a3 in
  lemma_bitwise_all ();
  lemma_equal (of_nat32 a0) (mask a 32);
  lemma_equal (of_nat32 a1) (mask (shift a (-32)) 32);
  lemma_equal (of_nat32 a2) (mask (shift a (-64)) 32);
  lemma_equal (of_nat32 a3) (shift a (-96));
  ()

#reset-options "--z3rlimit 20"
let lemma_quad32_of_nat32s a0 a1 a2 a3 =
  let a = poly128_of_nat32s a0 a1 a2 a3 in
  reveal_to_quad32 a;
  lemma_bitwise_all ();
  lemma_quad32_vec_equal (Mkfour a0 a1 a2 a3) (to_quad32 a)
#reset-options

let lemma_quad32_to_nat32s a =
  let Mkfour a0 a1 a2 a3 = to_quad32 a in
  reveal_to_quad32 a;
  lemma_bitwise_all ();
  lemma_equal a (poly128_of_nat32s a0 a1 a2 a3)

let lemma_quad32_extract_nat32s a =
  let Mkfour a0 a1 a2 a3 = to_quad32 a in
  lemma_quad32_to_nat32s a;
  lemma_poly128_extract_nat32s a0 a1 a2 a3;
  ()

let lemma_quad32_double a =
  let q = to_quad32 a in
  let lo = quad32_double_lo q in
  let hi = quad32_double_hi q in
  let n = monomial 64 in
  reveal_to_quad32 a;
  reveal_of_double32 lo;
  reveal_of_double32 hi;
  lemma_split_define a 64;
  lemma_add_define_all ();
  lemma_reverse_define_all ();
  lemma_index_all ();
  lemma_equal (of_double32 lo) (a %. n);
  lemma_equal (of_double32 hi) (a /. n);
  ()

let lemma_of_double32_degree (d:double32) =
  reveal_of_double32 d

let lemma_of_quad32_degree (q:quad32) =
  reveal_of_quad32 q

#reset-options "--z3rlimit 30"
let lemma_to_of_quad32 q =
  reveal_of_quad32 q;
  reveal_to_quad32 (of_quad32 q);
  let a = of_quad32 q in
  let Mkfour q0 q1 q2 q3 = q in
  let Mkfour q0' q1' q2' q3' = to_quad32 a in
  lemma_index a;
  lemma_reverse_define_all ();
  let s0 = UInt.to_vec #32 q0 in
  let s1 = UInt.to_vec #32 q1 in
  let s2 = UInt.to_vec #32 q2 in
  let s3 = UInt.to_vec #32 q3 in
  let s0' = UInt.to_vec #32 q0' in
  let s1' = UInt.to_vec #32 q1' in
  let s2' = UInt.to_vec #32 q2' in
  let s3' = UInt.to_vec #32 q3' in
  assert (equal s0 s0');
  assert (equal s1 s1');
  assert (equal s2 s2');
  assert (equal s3 s3');
  ()
#reset-options

let lemma_of_to_quad32 a =
  reveal_to_quad32 a;
  reveal_of_quad32 (to_quad32 a);
  lemma_index_all ();
  lemma_reverse_define_all ();
  lemma_equal a (of_quad32 (to_quad32 a))
val lemma_of_to_quad32_mask (a:poly) : Lemma
  (of_quad32 (to_quad32 a) == mask a 128)
a: Vale.Math.Poly2_s.poly
  -> FStar.Pervasives.Lemma
    (ensures
      Vale.Math.Poly2.Bits_s.of_quad32 (Vale.Math.Poly2.Bits_s.to_quad32 a) ==
      Vale.Math.Poly2.mask a 128)