(* end mocked_md *)

Inductive hmac256drbgabs :=
  HMAC256DRBGabs: forall (key: list byte) (V: list byte) (reseed_counter entropy_len: Z) (prediction_resistance: bool) (reseed_interval: Z), hmac256drbgabs.(* end mocked_md *)

Inductive hmac256drbgabs :=
  HMAC256DRBGabs: forall (key: list byte) (V: list byte) (reseed_counter entropy_len: Z) (prediction_resistance: bool) (reseed_interval: Z), hmac256drbgabs.Definition hmac256drbgstate: Type := (mdstate * (list val * (val * (val * (val * val)))))%type.Definition hmac256drbgabs_entropy_len (a: hmac256drbgabs): Z :=
  match a with HMAC256DRBGabs _ _ _ entropy_len _ _ => entropy_len end.Definition hmac256drbgabs_value (a: hmac256drbgabs): list byte :=
  match a with HMAC256DRBGabs _ V _ _ _ _ => V end.Definition hmac256drbgabs_key (a: hmac256drbgabs): list byte :=
  match a with HMAC256DRBGabs key _ _ _ _ _ => key end.Definition hmac256drbgabs_prediction_resistance (a: hmac256drbgabs): bool :=
  match a with HMAC256DRBGabs _ _ _ _ pr _ => pr end.Definition hmac256drbgabs_reseed_counter (a: hmac256drbgabs): Z :=
  match a with HMAC256DRBGabs _ _ reseed_counter _ _ _ => reseed_counter end.Definition hmac256drbgabs_reseed_interval (a: hmac256drbgabs): Z :=
  match a with HMAC256DRBGabs _ _ _ _ _ reseed_interval => reseed_interval end.Definition hmac256drbgabs_increment_reseed_counter (a: hmac256drbgabs): hmac256drbgabs :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval => HMAC256DRBGabs key V (reseed_counter + 1) entropy_len prediction_resistance reseed_interval end.Definition hmac256drbgabs_update_value (a: hmac256drbgabs) (new_value: list byte): hmac256drbgabs :=
  match a with HMAC256DRBGabs key _ reseed_counter entropy_len prediction_resistance reseed_interval => HMAC256DRBGabs key new_value reseed_counter entropy_len prediction_resistance reseed_interval end.Definition hmac256drbgabs_update_key (a: hmac256drbgabs) (new_key: list byte): hmac256drbgabs :=
  match a with HMAC256DRBGabs _ V reseed_counter entropy_len prediction_resistance reseed_interval => HMAC256DRBGabs new_key V reseed_counter entropy_len prediction_resistance reseed_interval end.Definition hmac256drbgabs_update_reseed_counter (a: hmac256drbgabs) (new_counter: Z): hmac256drbgabs :=
  match a with HMAC256DRBGabs key V _ entropy_len prediction_resistance reseed_interval => HMAC256DRBGabs key V new_counter entropy_len prediction_resistance reseed_interval end.Definition hmac256drbgabs_metadata_same (a: hmac256drbgabs) (b: hmac256drbgabs): Prop :=
  match a with HMAC256DRBGabs _ _ reseed_counter entropy_len prediction_resistance reseed_interval =>
               match b with HMAC256DRBGabs _ _ reseed_counter' entropy_len' prediction_resistance' reseed_interval' =>
                            reseed_counter = reseed_counter'
                            /\ entropy_len = entropy_len'
                            /\ prediction_resistance = prediction_resistance'
                            /\ reseed_interval = reseed_interval'
               end
  end.Definition hmac256drbgabs_of_state_handle (a: DRBG_state_handle) entropy_len reseed_interval: hmac256drbgabs :=
  match a with ((V, key, reseed_counter),_, prediction_resistance) =>
               HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval
  end.Definition hmac256drbgabs_to_state_handle (a: hmac256drbgabs): DRBG_state_handle :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval =>
               ((V, key, reseed_counter), 32(*256*) (* security strength, not used *), prediction_resistance)
  end.Definition hmac256drbgstate_md_info_pointer (a: hmac256drbgstate): val := fst (fst a).Definition t_struct_mbedtls_md_info := Tstruct _mbedtls_md_info_t noattr.Definition t_struct_hmac256drbg_context_st := Tstruct _mbedtls_hmac_drbg_context noattr.Definition hmac256drbgabs_to_state (a: hmac256drbgabs) (old: hmac256drbgstate):hmac256drbgstate :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval =>
               match old with (md_ctx', _) =>
                            (md_ctx', (map Vubyte V, (Vint (Int.repr reseed_counter), (Vint (Int.repr entropy_len), (Val.of_bool prediction_resistance, Vint (Int.repr reseed_interval))))))
               end
  end.Definition hmac256drbgabs_common_mpreds sh (final_state_abs: hmac256drbgabs) (old_state: hmac256drbgstate) (ctx: val) (info_contents: reptype t_struct_mbedtls_md_info): mpred :=
                  let st := hmac256drbgabs_to_state final_state_abs old_state in
                  (data_at sh t_struct_hmac256drbg_context_st st ctx) *
                  (data_at sh t_struct_mbedtls_md_info info_contents (hmac256drbgstate_md_info_pointer st)) *
                  (hmac256drbg_relate final_state_abs st).Definition hmac256drbgabs_hmac_drbg_update (a:hmac256drbgabs) (additional_data: list byte): hmac256drbgabs :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval =>
               let (key', V') := HMAC256_DRBG_update additional_data key V in
               HMAC256DRBGabs key' V' reseed_counter entropy_len prediction_resistance reseed_interval
  end.Definition mbedtls_HMAC256_DRBG_reseed_function (entropy_stream: ENTROPY.stream) (a:hmac256drbgabs)
           (additional_input: list byte): ENTROPY.result DRBG_state_handle :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval =>
               let sec_strength:Z := 32 (*not used -- measured in bytes, since that's how the calculations in DRBG_instantiate_function work *) in
               let state_handle: DRBG_state_handle := ((V, key, reseed_counter), sec_strength, prediction_resistance) in
               let max_additional_input_length := 256 
               in HMAC256_DRBG_reseed_function entropy_len entropy_len max_additional_input_length 
                     entropy_stream state_handle prediction_resistance additional_input
  end.Definition hmac256drbgabs_reseed (a: hmac256drbgabs) (s: ENTROPY.stream) (additional_data: list byte) : hmac256drbgabs :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval =>
               match (mbedtls_HMAC256_DRBG_reseed_function s a additional_data) with
                 | ENTROPY.success ((V', key', reseed_counter'), _, pr') _ =>
                   HMAC256DRBGabs key' V' reseed_counter' entropy_len pr' reseed_interval
                 | ENTROPY.error _ _ => a
               end
  end.Definition get_stream_result {X} (result: ENTROPY.result X): ENTROPY.stream :=
  match result with
    | ENTROPY.success _ s => s
    | ENTROPY.error _ s => s
  end.Definition result_success {X} (result: ENTROPY.result X): Prop :=
  match result with
    | ENTROPY.success _ _ => True
    | ENTROPY.error _ _ => False
  end.Parameter ENT_GenErr: Z.Parameter ENT_GenErrAx: Vzero <> Vint (Int.repr ENT_GenErr)  /\ Int.repr ENT_GenErr <> Int.repr (-20864).Definition return_value_relate_result {X} (result: ENTROPY.result X) (ret_value: val): Prop :=
  match result with
    | ENTROPY.error e _ => match e with
                             | ENTROPY.generic_error => ret_value = Vint (Int.repr ENT_GenErr) (*WAS: ret_value <> Vzero*)
                             | ENTROPY.catastrophic_error => ret_value = Vint (Int.repr (-9))
                           end
    | ENTROPY.success _ _ => ret_value = Vzero
  end.Parameter Stream: ENTROPY.stream -> mpred.Definition mbedtls_HMAC256_DRBG_generate_function (entropy_stream: ENTROPY.stream) (a:hmac256drbgabs) 
            (requested_number_of_bytes: Z) (additional_input: list byte): ENTROPY.result (list byte * DRBG_state_handle) :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval =>
               HMAC256_DRBG_generate_function (HMAC256_DRBG_reseed_function entropy_len entropy_len 256) 
                      (*10000*) reseed_interval 
                      1024 (*max_number_of_bytes_per_request*)
                      256 (*max_additional_input_length*) 
                      entropy_stream
                      ((V, key, reseed_counter), 
                        32(*256*) (*max security strength in bytes, not used *), 
                        prediction_resistance) 
                      requested_number_of_bytes 
                      32 (*requested security strength, not used *)
                      prediction_resistance additional_input
  end.Definition hmac256drbgabs_generate (a: hmac256drbgabs) (s: ENTROPY.stream) (bytes: Z) (additional_data: list byte) : hmac256drbgabs :=
  match a with HMAC256DRBGabs key V reseed_counter entropy_len prediction_resistance reseed_interval =>
               match (mbedtls_HMAC256_DRBG_generate_function s a bytes additional_data) with
                 | ENTROPY.success (_, ((V', key', reseed_counter'), _, pr')) _ =>
                   HMAC256DRBGabs key' V' reseed_counter' entropy_len pr' reseed_interval
                 | ENTROPY.error _ _ => a
               end
  end.Definition  RI_range (z:Z): Prop:= 0 < z /\ z+1 < Int.max_signed.Definition GetEntropy_PostSep sh len s buf :=
  match ENTROPY.get_bytes (Z.to_nat len) s with
            | ENTROPY.error _ _ => memory_block sh len buf
            | ENTROPY.success bytes _ =>
              data_at sh (tarray tuchar len) (map Vubyte bytes) buf
                 end.Definition size_of_HMACDRBGCTX:Z:= sizeof (Tstruct _mbedtls_hmac_drbg_context noattr).(*********************************** hmac_drbg_seed specification ******************************)

(*Parameter max_personalization_string_length: Z. (*NIST SP 800-90A, page 38, Table2: 2^35 bits;
         Our personalization string is a list of bytes, so have max length 2^32*)
  Axiom max_personalization_string336: 336 <= max_personalization_string_length.*)
  (*Definition max_personalization_string_length: Z := 20. *)(*Appendix B2 of NIST SP 800-90A says: 160 bits. We measure in bytes*)
Definition max_personalization_string_length: Z := 336.(*= MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT -48*) 

(*Max entropy_length*)
Definition max_elength: Z:= 2^32.Inductive hmac_any:=
  hmac_any_empty: hmac_any
| hmac_any_rep: forall key data : list byte, hmac_any
| hmac_any_full: forall k:list byte, hmac_any.Inductive hmac_any:=
  hmac_any_empty: hmac_any
| hmac_any_rep: forall key data : list byte, hmac_any
| hmac_any_full: forall k:list byte, hmac_any.Inductive hmac_any:=
  hmac_any_empty: hmac_any
| hmac_any_rep: forall key data : list byte, hmac_any
| hmac_any_full: forall k:list byte, hmac_any.Inductive hmac_any:=
  hmac_any_empty: hmac_any
| hmac_any_rep: forall key data : list byte, hmac_any
| hmac_any_full: forall k:list byte, hmac_any.Definition hmac_interp (d:hmac_any) (r: mdstate):mpred :=
  match d with
    hmac_any_empty => md_empty r
  | hmac_any_rep key data => md_relate key data r
  | hmac_any_full k => md_full k r
  end.(*********************************** end of hmac_drbg_seed specification ******************************)
Definition setPR_ABS res (a: hmac256drbgabs): hmac256drbgabs :=
  match a with HMAC256DRBGabs key V x el r reseed_interval => 
               HMAC256DRBGabs key V x el res reseed_interval
  end.Definition setPR_CTX res (r: hmac256drbgstate): hmac256drbgstate :=
  match r with (md_ctx, (V, (rc, (el, (r, ri))))) => 
               (md_ctx, (V, (rc, (el, (res, ri))))) 
  end.Definition setEL_ABS el (a: hmac256drbgabs): hmac256drbgabs :=
  match a with HMAC256DRBGabs key V x _ pr reseed_interval => 
               HMAC256DRBGabs key V x el pr reseed_interval
  end.Definition setEL_CTX el (r: hmac256drbgstate): hmac256drbgstate :=
  match r with (md_ctx, (V, (rc, (_, (pr, ri))))) => 
               (md_ctx, (V, (rc, (el, (pr, ri))))) 
  end.Definition setRI_ABS ri (a: hmac256drbgabs): hmac256drbgabs :=
  match a with HMAC256DRBGabs key V x el pr _ => 
               HMAC256DRBGabs key V x el pr ri
  end.Definition setRI_CTX ri (r: hmac256drbgstate): hmac256drbgstate :=
  match r with (md_ctx, (V, (rc, (el, (pr, _))))) => 
               (md_ctx, (V, (rc, (el, (pr, ri))))) 
  end.Definition HmacDrbgVarSpecs : varspecs := (sha._K256, tarray tuint 64)::nil.Definition ndfs_merge fA cA A PA QA FSA (HFSA: FSA = NDmk_funspec fA cA A PA QA) 
                    fB cB B PB QB FSB (HFSB: FSB = NDmk_funspec fB cB B PB QB): option funspec.

Lemma hmac_init_merge: ndfs_merge _ _ _ _ _ (snd UNDER_SPEC.hmac_reset_spec) (eq_refl _) _ _ _ _ _ (snd UNDER_SPEC.hmac_starts_spec) (eq_refl _) = Some hmac_init_funspec.