Local Open Scope logic.
Fixpoint HMAC_DRBG_update_round (HMAC: list byte -> list byte -> list byte) (provided_data K V: list byte) (round: nat): (list byte * list byte) :=
match round with
| O => (K, V)
| S round' =>
let (K, V) := HMAC_DRBG_update_round HMAC provided_data K V round' in
let K := HMAC (V ++ [Byte.repr (Z.of_nat round')] ++ provided_data) K in
let V := HMAC V K in
(K, V)
end.
Definition HMAC_DRBG_update_concrete (HMAC: list byte -> list byte -> list byte) (provided_data K V: list byte): (list byte * list byte) :=
let rounds := match provided_data with
| [] => 1%nat
| _ => 2%nat
end in
HMAC_DRBG_update_round HMAC provided_data K V rounds.
Definition update_rounds (non_empty_additional: bool): Z :=
if non_empty_additional then 2 else 1.

Lemma HMAC_DRBG_update_round_incremental_Z:
forall key V initial_state_abs contents i,
0 <= i ->
(key, V) = HMAC_DRBG_update_round HMAC256 contents
(hmac256drbgabs_key initial_state_abs)
(hmac256drbgabs_value initial_state_abs) (Z.to_nat i) ->
(HMAC256 (V ++ Byte.repr i :: contents) key,
HMAC256 V (HMAC256 (V ++ Byte.repr i :: contents) key)) =
HMAC_DRBG_update_round HMAC256 contents
(hmac256drbgabs_key initial_state_abs)
(hmac256drbgabs_value initial_state_abs) (Z.to_nat (i + 1)).