val lemma_cdf_list_1344: i:size_nat{i < List.Tot.length cdf_list_1344} ->
  Lemma (uint_v (List.Tot.index cdf_list_1344 i) < pow2 15)
let lemma_cdf_list_1344 i =
  assert_norm (List.Tot.length cdf_list_1344 = 7);
  assert_norm (uint_v (List.Tot.index cdf_list_1344 0) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_1344 1) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_1344 2) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_1344 3) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_1344 4) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_1344 5) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_1344 6) < pow2 15)
val lemma_cdf_list_1344: i:size_nat{i < List.Tot.length cdf_list_1344} ->
  Lemma (uint_v (List.Tot.index cdf_list_1344 i) < pow2 15)
let lemma_cdf_list_1344 i =
assert_norm (List.Tot.length cdf_list_1344 = 7);
assert_norm (uint_v (List.Tot.index cdf_list_1344 0) < pow2 15);
assert_norm (uint_v (List.Tot.index cdf_list_1344 1) < pow2 15);
assert_norm (uint_v (List.Tot.index cdf_list_1344 2) < pow2 15);
assert_norm (uint_v (List.Tot.index cdf_list_1344 3) < pow2 15);
assert_norm (uint_v (List.Tot.index cdf_list_1344 4) < pow2 15);
assert_norm (uint_v (List.Tot.index cdf_list_1344 5) < pow2 15);
assert_norm (uint_v (List.Tot.index cdf_list_1344 6) < pow2 15)
Spec.Frodo.Params.fst.checked
Spec.SHA3.fst.checked Spec.Matrix.fst.checked Spec.Frodo.Gen.fst.checked prims.fst.checked Lib.Sequence.fsti.checked Lib.IntTypes.fsti.checked Lib.ByteSequence.fsti.checked FStar.Pervasives.fsti.checked FStar.Mul.fst.checked FStar.Math.Lemmas.fst.checked FStar.List.Tot.fst.checked
Spec.Frodo.Params.fst
Lib.IntTypes.size_nat Prims.b2t Prims.op_LessThan FStar.List.Tot.Base.length Lib.IntTypes.int_t Lib.IntTypes.U16 Lib.IntTypes.SEC Spec.Frodo.Params.cdf_list_1344 FStar.Pervasives.assert_norm Lib.IntTypes.uint_v FStar.List.Tot.Base.index Prims.pow2 Prims.unit Prims.op_Equality Prims.int
module Spec.Frodo.Params

open FStar.Mul
open Lib.IntTypes
open Lib.Sequence
open Lib.ByteSequence

open Spec.Matrix

#set-options "--z3rlimit 50 --fuel 0 --ifuel 0"

type frodo_alg =
  | Frodo64 (* this variant is used only for testing purposes *)
  | Frodo640
  | Frodo976
  | Frodo1344

type frodo_gen_a =
  | SHAKE128
  | AES128

let _: squash (inversion frodo_alg) = allow_inversion frodo_alg
let _: squash (inversion frodo_gen_a) = allow_inversion frodo_gen_a


inline_for_extraction
let params_n (a:frodo_alg) : x:size_pos{x % 8 = 0 /\ x <= 1344} =
  match a with
  | Frodo64 -> 64
  | Frodo640 -> 640
  | Frodo976 -> 976
  | Frodo1344 -> 1344


inline_for_extraction
let params_logq (a:frodo_alg) : x:size_pos{x <= 16} =
  match a with
  | Frodo64 | Frodo640 -> 15
  | Frodo976 | Frodo1344 -> 16


inline_for_extraction
let params_extracted_bits (a:frodo_alg) : x:size_pos{x < params_logq a /\ x <= 8} =
  match a with
  | Frodo64 | Frodo640 -> 2
  | Frodo976 -> 3
  | Frodo1344 -> 4


inline_for_extraction
let crypto_bytes (a:frodo_alg) : x:size_pos{x <= 32} =
  match a with
  | Frodo64 | Frodo640 -> 16
  | Frodo976 -> 24
  | Frodo1344 -> 32


let params_nbar = 8
let bytes_seed_a = 16

let bytes_pkhash (a:frodo_alg) : size_pos =
  crypto_bytes a

let bytes_mu (a:frodo_alg) : size_pos =
  params_extracted_bits a * params_nbar * params_nbar / 8

let publicmatrixbytes_len (a:frodo_alg) : size_pos =
  params_logq a * (params_n a * params_nbar / 8)

let secretmatrixbytes_len (a:frodo_alg) : size_pos =
  2 * params_n a * params_nbar

let ct1bytes_len (a:frodo_alg) : size_pos =
  params_logq a * (params_nbar * params_n a / 8)

let ct2bytes_len (a:frodo_alg) : size_pos =
  params_logq a * (params_nbar * params_nbar / 8)

let crypto_publickeybytes (a:frodo_alg) : size_pos =
  bytes_seed_a + publicmatrixbytes_len a

let crypto_secretkeybytes (a:frodo_alg) : size_pos =
  crypto_bytes a + crypto_publickeybytes a + secretmatrixbytes_len a + bytes_pkhash a

let crypto_ciphertextbytes (a:frodo_alg) : size_pos =
  ct1bytes_len a + ct2bytes_len a

val expand_crypto_publickeybytes: a:frodo_alg ->
  Lemma (crypto_publickeybytes a == bytes_seed_a + publicmatrixbytes_len a)
let expand_crypto_publickeybytes a = ()

val expand_crypto_secretkeybytes: a:frodo_alg ->
  Lemma (crypto_secretkeybytes a ==
    crypto_bytes a + crypto_publickeybytes a + secretmatrixbytes_len a + bytes_pkhash a)
let expand_crypto_secretkeybytes a = ()

val expand_crypto_ciphertextbytes: a:frodo_alg ->
  Lemma (crypto_ciphertextbytes a == ct1bytes_len a + ct2bytes_len a)
let expand_crypto_ciphertextbytes a = ()

val params_n_sqr: a:frodo_alg ->
  Lemma (params_n a * params_n a <= max_size_t /\ params_n a <= maxint U16)
let params_n_sqr a =
  assert (params_n a <= maxint U16);
  Math.Lemmas.lemma_mult_lt_sqr (params_n a) (params_n a) (maxint U16);
  Math.Lemmas.pow2_plus 16 16


inline_for_extraction noextract
let frodo_shake_st =
    inputByteLen:nat
  -> input:bytes{length input == inputByteLen}
  -> outputByteLen:size_nat
  -> lbytes outputByteLen


inline_for_extraction
let frodo_shake (a:frodo_alg) : frodo_shake_st =
  match a with
  | Frodo64 | Frodo640 -> Spec.SHA3.shake128
  | Frodo976 | Frodo1344 -> Spec.SHA3.shake256


inline_for_extraction noextract
let frodo_gen_matrix_st =
    n:size_nat{n * n <= max_size_t /\ n <= maxint U16 /\ n % 4 = 0}
  -> seed:lbytes 16
  -> matrix n n


inline_for_extraction
let frodo_gen_matrix (a:frodo_gen_a) : frodo_gen_matrix_st =
  match a with
  | SHAKE128 -> Spec.Frodo.Gen.frodo_gen_matrix_shake
  | AES128 -> Spec.Frodo.Gen.frodo_gen_matrix_aes


(** CDF tables *)
unfold let cdf_list_640: list uint16 =
  [ u16 4643; u16 13363; u16 20579; u16 25843; u16 29227; u16 31145; u16 32103; u16 32525;
    u16 32689; u16 32745; u16 32762; u16 32766; u16 32767 ]

unfold let cdf_list_976: list uint16 =
  [ u16 5638; u16 15915; u16 23689; u16 28571; u16 31116; u16 32217;  u16 32613; u16 32731;
    u16 32760; u16 32766; u16 32767 ]

unfold let cdf_list_1344: list uint16 =
  [ u16 9142; u16 23462; u16 30338; u16 32361; u16 32725; u16 32765; u16 32767 ]


inline_for_extraction
let cdf_table_len (a:frodo_alg) : size_pos =
  match a with
  | Frodo64 | Frodo640 -> 13
  | Frodo976 -> 11
  | Frodo1344 -> 7


inline_for_extraction
let cdf_list (a:frodo_alg) : x:list uint16{List.Tot.length x == cdf_table_len a} =
  match a with
  | Frodo64 | Frodo640 ->
    assert_norm (List.Tot.length cdf_list_640 = 13);
    cdf_list_640
  | Frodo976 ->
    assert_norm (List.Tot.length cdf_list_976 = 11);
    cdf_list_976
  | Frodo1344 ->
    assert_norm (List.Tot.length cdf_list_1344 = 7);
    cdf_list_1344


inline_for_extraction
let cdf_table (a:frodo_alg) : lseq uint16 (cdf_table_len a) =
  createL (cdf_list a)


val lemma_cdf_list_640: i:size_nat{i < List.Tot.length cdf_list_640} ->
  Lemma (uint_v (List.Tot.index cdf_list_640 i) < pow2 15)
let lemma_cdf_list_640 i =
  assert_norm (List.Tot.length cdf_list_640 = 13);
  assert_norm (uint_v (List.Tot.index cdf_list_640 0) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 1) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 2) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 3) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 4) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 5) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 6) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 7) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 8) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 9) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 10) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 11) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_640 12) < pow2 15)


val lemma_cdf_list_976: i:size_nat{i < List.Tot.length cdf_list_976} ->
  Lemma (uint_v (List.Tot.index cdf_list_976 i) < pow2 15)
let lemma_cdf_list_976 i =
  assert_norm (List.Tot.length cdf_list_976 = 11);
  assert_norm (uint_v (List.Tot.index cdf_list_976 0) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 1) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 2) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 3) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 4) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 5) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 6) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 7) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 8) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 9) < pow2 15);
  assert_norm (uint_v (List.Tot.index cdf_list_976 10) < pow2 15)


val lemma_cdf_list_1344: i:size_nat{i < List.Tot.length cdf_list_1344} ->
  Lemma (uint_v (List.Tot.index cdf_list_1344 i) < pow2 15)
val lemma_cdf_list_1344: i:size_nat{i < List.Tot.length cdf_list_1344} ->
  Lemma (uint_v (List.Tot.index cdf_list_1344 i) < pow2 15)
i: Lib.IntTypes.size_nat{i < FStar.List.Tot.Base.length Spec.Frodo.Params.cdf_list_1344}
  -> FStar.Pervasives.Lemma
    (ensures
      Lib.IntTypes.uint_v (FStar.List.Tot.Base.index Spec.Frodo.Params.cdf_list_1344 i) <
      Prims.pow2 15)