(* Lemma 1: M = Prefix(Pad(M)) *)
(* TODO: replace InWords with InBlocks 4? *)
Inductive InWords : list byte -> Prop :=
| words_nil : InWords []
| words_word : forall (a b c d : byte) (msg : list byte),
InWords msg -> InWords (a :: b :: c :: d :: msg).
(* *** New definition for this lemma. *)
Definition pad (msg : list byte) : list byte :=
let n := Zlength msg in
msg ++ [Byte.repr 128%Z]
++ list_repeat (Z.to_nat (-(n + 9) mod 64)) Byte.zero
++ intlist_to_bytelist (([Int.repr (n * 8 / Int.modulus); Int.repr (n * 8)])%list).
Definition generate_and_pad' (msg : list byte) : list int :=
bytelist_to_intlist (pad msg).
(* ----------------- ^ Definitions *)

(* Specifications: *)
Lemma fstpad_len :
forall (msg : list byte),
Datatypes.length (msg ++ [Byte.repr 128]
++ list_repeat (Z.to_nat (- (Zlength msg + 9) mod 64)) Byte.zero)
= (Datatypes.length msg + (S (Z.to_nat (- (Zlength msg + 9) mod 64))))%nat.
Lemma InWords_len4 : forall (l : list byte),
Nat.divide (Z.to_nat WORD) (length l) -> InWords l.
(* TODO: clear out the SearchAbouts / clean up proof *)
Lemma pad_len_64_mod : forall (msg : list byte),
(Zlength (pad msg)) mod 64 = 0.
(* more usable versions *)
Lemma pad_len_64 : forall (msg : list byte), exists (n : Z),
Zlength (pad msg) = 64 * n /\ n >= 0.
Lemma pad_len_64_nat : forall (msg : list byte), exists (n : nat),
(length (pad msg))%nat = (64 * n)%nat.
Lemma total_pad_len_Zlist : forall (msg : list byte), exists (n : nat),
length
(msg ++ [Byte.repr 128] ++ list_repeat (Z.to_nat (- (Zlength msg + 9) mod 64)) Byte.zero)
=  (n * Z.to_nat WORD (* 4 *))%nat.
Lemma pad_inwords :
forall (msg : list byte),
InWords (msg ++ [Byte.repr 128]
++ list_repeat (Z.to_nat (- (Zlength msg + 9) mod 64)) Byte.zero).