(*SHA256-specific Modules*)
(* Lemma of_length_proof_irrel {A:Set} n (l: list A) M: Vector.to_list (@of_list_length _ n l M) = l. *)
Definition iv_v : Bvector c := Vector.of_list sha_iv.
(* Lemma opad_length: length (bytesToBits (HP.HMAC_SHA256.sixtyfour (Integers.Byte.unsigned HP.Opad))) = b.  Definition fpad_v (v:Bvector c): Bvector p := of_list_length _ (fpad_length v).  Lemma fpad_eq : forall (v : Bvector c) (l : Blist), l = Vector.to_list v -> fpad l = Vector.to_list (fpad_v v).  Fixpoint splitAndPad_aux (m:list Blist) (M: Forall (fun x => length x = 512%nat) m): list (Bvector b) := (match m as l return (Forall (fun x => length x = 512%nat) l) -> list (Bvector b) with nil => fun F => nil |  cons h t => fun F => cons (of_list_length h (Forall_inv F)) (splitAndPad_aux t (Forall_tl _ _ _ _ F)) end) M.  Lemma splitAndPad_aux_consD h t M: splitAndPad_aux (cons h t) M = (of_list_length h (Forall_inv M)) :: (splitAndPad_aux t (Forall_tl _ _ _ _ M)).  Definition splitAndPad_v (m: Blist): list (Bvector b). apply (splitAndPad_aux (sha_splitandpad_blocks m)). apply InBlocks_Forall_512. apply sha_splitandpad_inc_InBlocks. Defined.  Lemma splitAndPad_nil: exists pf, splitAndPad_v nil = cons (@of_list_length bool 512 (sha_splitandpad_inc nil) pf) nil.  Lemma length_splitandpad_inner m : Forall2 (fun (bv : Vector.t bool b) (bl : list bool) => bl = Vector.to_list bv) (splitAndPad_v m) (sha_splitandpad_blocks m).  Module EQ256 <: EQUIV_Inst SHA256. Definition c := c. Definition C := C. Definition p := p. Definition b := b. Definition B := B. Definition BS: (SHA256.BlockSize * 8)%nat = b. reflexivity. Qed. Definition h := sha_h. Definition h_length := sha_h_length. (*  Definition h_v := h_v. Definition h_eq := h_eq.*)
Definition ir: list int := SHA256.init_registers.
apply sha_iv_length. Qed.
(*Definition iv_length := sha_iv_length.*)
Definition iv_v: Bvector c := iv_v. (*of_list_length _ iv_length.*)
apply concat_InBlocks. apply sha_splitandpad_blocks_512. Qed.
Definition hashblock : list int -> list int -> list int := SHA256.hash_block.
reflexivity. Qed.
Definition hashblocks: list int -> list int -> list int:= SHA256.hash_blocks.
Definition d := 16%nat.
Definition HBS_eq : forall r msg : list int,
hashblocks r msg =
match msg with
| List.nil => r
| _ :: _ => hashblocks (hashblock r (firstn d msg)) (skipn d msg)
end := SHA256.hash_blocks_equation.
Definition gap:list byte -> list int := SHA256.generate_and_pad.
intros. rewrite <- pad_compose_equal. apply gap_divide16. Qed.
unfold SHA256.Hash.
rewrite functional_prog.SHA_256'_eq; reflexivity.
Qed.

Lemma FOLD_HB_eq: forall l ls, length l = (c + p)%nat ->
Forall (fun x => length x = (c + p)%nat) ls ->
fold_left h (l :: ls) (Vector.to_list iv_v) =
hash_blocks_bits (HMAC_spec_concat.HMAC_Concat.b c p) B h
(Vector.to_list iv_v) (l ++ concat ls).