Local Open Scope nat.
Definition LBLOCK : nat := Z.to_nat LBLOCKz.
Definition CBLOCK : nat := Z.to_nat CBLOCKz.
Opaque LBLOCK CBLOCK.

(* Specifications: *)
Lemma LBLOCK_zeq: Z.of_nat LBLOCK = 16%Z.
Lemma hash_blocks_equation' : forall (r : registers) (msg : list int),
hash_blocks r msg =
match msg with
| [] => r
| _ :: _ => hash_blocks (hash_block r (firstn LBLOCK msg)) (skipn LBLOCK msg)
end.
Lemma length_hash_blocks: forall regs blocks,
length regs = 8%nat ->
(LBLOCKz | Zlength blocks) ->
length (hash_blocks regs blocks) = 8%nat.
Theorem Zmod_mod_mult :
forall n a b, (0 < a)%Z -> (0 <= b)%Z ->
Zmod (Zmod n (a * b)) b = Zmod n b.
Lemma generate_and_pad_lemma1:
forall hashed (dd: list byte) hashed' (dd': list byte) pad bitlen
(PAD : pad = 0 \/ dd' = [])
(H0 : Zlength dd' + 8 <= CBLOCKz)
(H1 : 0 <= pad < 8)
(H4: (LBLOCKz | Zlength hashed))
(H7 : ((Zlength hashed * 4 + Zlength dd) * 8)%Z = bitlen)
(H3: Zlength dd < CBLOCKz)
(H2 : (LBLOCKz | Zlength hashed'))
(H5 : intlist_to_bytelist hashed' ++ dd' =
intlist_to_bytelist hashed ++ dd ++ [Byte.repr 128] ++ list_repeat (Z.to_nat pad) Byte.zero),
let lastblock :=
(dd' ++
list_repeat (Z.to_nat (CBLOCKz - 8 - Zlength dd')) Byte.zero ++
intlist_to_bytelist [hi_part bitlen; lo_part bitlen])
in let lastblock' :=
bytelist_to_intlist lastblock
in forall (H99: Zlength lastblock = CBLOCKz),
generate_and_pad (intlist_to_bytelist hashed ++ dd) = hashed' ++ lastblock'.