val main: Prims.unit -> St C.exit_code
let main () : St C.exit_code =
  test_many C.String.(!$"[HMAC_DRBG]") test_one vectors_low;
  C.EXIT_SUCCESS
val main: Prims.unit -> St C.exit_code
let main () : St C.exit_code =
test_many C.String.(!$"[HMAC_DRBG]") test_one vectors_low;
C.EXIT_SUCCESS
Hacl.Test.HMAC_DRBG.fst.checked
Test.Lowstarize.fst.checked Spec.HMAC_DRBG.Test.Vectors.fst.checked Spec.HMAC_DRBG.fsti.checked Spec.Hash.Definitions.fst.checked prims.fst.checked LowStar.Printf.fst.checked LowStar.BufferOps.fst.checked LowStar.Buffer.fst.checked Lib.IntTypes.fsti.checked Lib.ByteBuffer.fsti.checked Hacl.HMAC_DRBG.fsti.checked FStar.UInt8.fsti.checked FStar.UInt32.fsti.checked FStar.Pervasives.Native.fst.checked FStar.Pervasives.fsti.checked FStar.List.Tot.fst.checked FStar.Int32.fsti.checked FStar.HyperStack.ST.fsti.checked C.String.fsti.checked C.Loops.fst.checked C.fst.checked
Hacl.Test.HMAC_DRBG.fst
Prims.unit C.EXIT_SUCCESS C.exit_code Hacl.Test.HMAC_DRBG.test_many FStar.Pervasives.Native.tuple8 Spec.Hash.Definitions.hash_alg Test.Lowstarize.lbuffer FStar.UInt8.t FStar.Pervasives.Native.tuple2 C.String.op_Bang_Dollar Hacl.Test.HMAC_DRBG.test_one Hacl.Test.HMAC_DRBG.vectors_low
module Hacl.Test.HMAC_DRBG

open FStar.HyperStack.ST
open Test.Lowstarize

open Lib.IntTypes

open Hacl.HMAC_DRBG
open Spec.HMAC_DRBG.Test.Vectors

module D = Spec.Hash.Definitions
module L = Test.Lowstarize
module B = LowStar.Buffer

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

(* FStar.Reflection only supports up to 8-tuples *)
noextract
let vectors_tmp = List.Tot.map 
  (fun x -> x.a, h x.entropy_input, h x.nonce, h x.personalization_string, 
         h x.entropy_input_reseed, h x.additional_input_reseed,
         (h x.additional_input_1, h x.additional_input_2),
         h x.returned_bits)
  test_vectors

%splice[vectors_low] (lowstarize_toplevel "vectors_tmp" "vectors_low")

// Cheap alternative to friend Lib.IntTypes needed because Test.Lowstarize uses UInt8.t
assume val declassify_uint8: squash (uint8 == UInt8.t)

let vec8 = L.lbuffer UInt8.t

let vector = D.hash_alg & vec8 & vec8 & vec8 & vec8 & vec8 & (vec8 & vec8) & vec8

// This could replace TestLib.compare_and_print
val compare_and_print: b1:B.buffer UInt8.t -> b2:B.buffer UInt8.t -> len:UInt32.t 
  -> Stack bool
  (requires fun h0 -> B.live h0 b1 /\ B.live h0 b2 /\ B.length b1 == v len /\ B.length b2 == v len)
  (ensures  fun h0 _ h1 -> B.modifies B.loc_none h0 h1)
let compare_and_print b1 b2 len =
  push_frame();
  LowStar.Printf.(printf "Expected: %xuy\n" len b1 done);
  LowStar.Printf.(printf "Computed: %xuy\n" len b2 done);
  let b = Lib.ByteBuffer.lbytes_eq #len b1 b2 in
  if b then 
    LowStar.Printf.(printf "PASS\n" done)
  else
    LowStar.Printf.(printf "FAIL\n" done);
  pop_frame();
  b

let test_one (vec:vector) : Stack unit (requires fun _ -> True) (ensures fun _ _ _ -> True) =
  let a, 
      LB entropy_input_len entropy_input, 
      LB nonce_len nonce,
      LB personalization_string_len personalization_string,
      LB entropy_input_reseed_len entropy_input_reseed,
      LB additional_input_reseed_len additional_input_reseed,
      (LB additional_input_1_len additional_input_1,
       LB additional_input_2_len additional_input_2),
      LB returned_bits_len returned_bits = vec 
  in
  B.recall entropy_input;
  B.recall nonce;
  B.recall personalization_string;
  B.recall entropy_input_reseed;
  B.recall additional_input_reseed;
  B.recall additional_input_1;
  B.recall additional_input_2;  
  B.recall returned_bits;
  // We need to check this at runtime because Low*-ized vectors don't carry any refinements
  if not (Spec.HMAC_DRBG.is_supported_alg a &&
          min_length a <=. entropy_input_len && 
          entropy_input_len <=. max_length &&
          min_length a /. 2ul <=. nonce_len && 
          nonce_len <=. max_length &&
          personalization_string_len <=. max_personalization_string_length &&
          min_length a <=. entropy_input_reseed_len && 
          entropy_input_reseed_len <=. max_length &&
          additional_input_reseed_len <=. max_additional_input_length &&
          additional_input_1_len <=. max_additional_input_length &&
          additional_input_2_len <=. max_additional_input_length &&
          0ul <. returned_bits_len && 
          returned_bits_len <=. max_output_length)
  then C.exit (-1l)
  else
    begin
    push_frame();
    let output = B.alloca (u8 0) returned_bits_len in
    let st = alloca a in
    instantiate a st 
      entropy_input_len entropy_input 
      nonce_len nonce
      personalization_string_len personalization_string;
    reseed a st 
      entropy_input_reseed_len entropy_input_reseed
      additional_input_reseed_len additional_input_reseed;
    let ok = generate a output st returned_bits_len 
      additional_input_1_len additional_input_1
    in
    if ok then
      let ok = generate a output st returned_bits_len 
        additional_input_2_len additional_input_2 
      in
      if ok then
        let ok = compare_and_print returned_bits output returned_bits_len in
        if ok then ()
        else C.exit 1l
      else C.exit 1l
    else C.exit 1l;
    pop_frame()
    end

inline_for_extraction noextract
let test_many #a (label:C.String.t) 
  (f:a -> Stack unit (fun _ -> True) (fun _ _ _ -> True)) (vec: L.lbuffer a) 
=
  C.String.print label;
  C.String.(print !$"\n");
  let L.LB len vs = vec in
  let f (i:UInt32.t{0 <= v i /\ v i < v len}): Stack unit
    (requires fun h -> True)
    (ensures fun h0 _ h1 -> True)
  =
    let open LowStar.BufferOps in
    B.recall vs;
    LowStar.Printf.(printf "HMAC-DRBG Test %ul/%ul\n" (i +! 1ul) len done);
    f vs.(i)
  in
  C.Loops.for 0ul len (fun _ _ -> True) f
val main: Prims.unit -> St C.exit_code
_: Prims.unit -> FStar.HyperStack.ST.St C.exit_code