Section NMAC_to_HMAC.
Variable c p : nat.
Definition b := @b c p.
Variable h : Bvector c -> Bvector b -> Bvector c.
Variable iv : Bvector c.
Variable fpad : Bvector c -> Bvector p.
Definition GHMAC_2K := GHMAC_2K h iv fpad.
Variable opad ipad : Bvector b.
Hypothesis opad_ne_ipad : opad <> ipad.
Definition GHMAC := GHMAC h iv fpad opad ipad.
Variable A : OracleComp (list (Bvector b)) (Bvector c) bool.
Definition app_fpad := @app_fpad c p fpad.
Definition h_star := h_star p h.
Definition GNMAC := GNMAC h fpad.
Definition A_NMAC :=
x <-$ {0, 1}^(c + c);
[b, _] <-$2 A _ _ (f_oracle GNMAC _ x) tt;
ret b.
Definition A_HMAC :=
x <-$ {0, 1}^b;
[b, _] <-$2 A _ _ (f_oracle GHMAC _ x) tt;
ret b.
intuition.
unfold GHMAC_2K, HMAC_spec.GHMAC_2K, GNMAC, HMAC_spec.GNMAC, b, HMAC_spec.b.
remember (splitVector (c + p) (c + p) k) as z.
destruct z.
rewrite splitVector_append.
unfold app_fpad, hash_words.
simpl.
trivial.
Qed.
Definition HMAC_RKA_A : OracleComp (Bvector b * Bvector c) (Bvector c) bool :=
k_Out <--$ OC_Query _ (opad, iv);
k_In <--$ OC_Query _ (ipad, iv);
[b, _] <--$2 $ A _ _ (f_oracle GNMAC _ (Vector.append k_Out k_In)) tt;
$ ret b.
Local Opaque evalDist.
unfold A_HMAC, RKA_G0, GHMAC,  HMAC_RKA_A, GNMAC, HMAC_spec.GHMAC.
comp_skip.
simpl.
repeat ( inline_first; comp_simp).
comp_skip.
eapply comp_spec_eq_impl_eq.
eapply comp_spec_consequence.
eapply (@oc_comp_spec_eq _ _ _ _ _ _ _ _ _ _ _ _ _ _ (fun a b => a = b)).
trivial.
intuition.
unfold f_oracle.
eapply comp_spec_ret; intuition.
simpl.
specialize (GHMAC_2K_GNMAC_equiv (Vector.append (x xor opad) (x xor ipad)) a0); intuition.
rewrite splitVector_append in H1.
unfold dual_f.
eapply eq_trans.
eapply H1.
unfold GNMAC.
f_equal.
f_equal.
f_equal.
eapply BVxor_comm.
f_equal.
eapply BVxor_comm.
intuition.
destruct b2; simpl in *; subst; intuition.
comp_simp.
simpl.
inline_first.
comp_simp.
intuition.
Qed.
Definition A_NMAC_G1 :=
x1 <-$ {0, 1}^c;
x2 <-$ {0, 1}^c;
[b, _] <-$2 A _ _ (f_oracle GNMAC _ (Vector.append x1 x2)) tt;
ret b.
Definition A_NMAC_G1_0 :=
[x1, x2] <-$2 (
x <-$ {0, 1}^(c + c);
ret (splitVector c c x));
[b, _] <-$2 A _ _ (f_oracle GNMAC _ (Vector.append x1 x2)) tt;
ret b.
Definition A_NMAC_G1_1 :=
[x1, x2] <-$2 (
x1 <-$ {0, 1}^c;
x2 <-$ {0, 1}^c;
ret (x1, x2));
[b, _] <-$2 A _ _ (f_oracle GNMAC _ (Vector.append x1 x2)) tt;
ret b.

Theorem A_NMAC_G1_0_equiv :
Pr[A_NMAC] == Pr[A_NMAC_G1_0].