Section PRP_PRF.
Variable n : nat. (* bit vector length *)
Hint Resolve getUnusedR_wf : wftac.
Hint Resolve well_formed_perm_1 : wftac.
Definition getUnusedBvector := @getUnusedR (Bvector n) _ _ (Rnd n).
Definition well_formed_Bvector_perm := @well_formed_perm (Bvector n) _ _ _ (Rnd n).
Definition randomPerm_Bvector := @randomPerm (Bvector n) _ _ _ (Rnd n).
intuition.
eapply getUnusedR_wf; wftac.
simpl.
eapply in_getAllBvectors.
Qed.
intuition.
eapply well_formed_perm_1 in H.
destruct H.
intuition.
unfold getUnusedBvector.
eapply getUnusedR_wf; wftac.
eauto.
Qed.
Hint Resolve getUnusedBvector_wf : wftac.
(* A random permutation in which the loop that gets an unused value from the range is unrolled one step.  This is useful when comparing to a random function. *)
Definition randomPerm_unroll(p : (list (Bvector n * Bvector n)) * Bvector n) : Comp (list (Bvector n * Bvector n) * Bvector n) :=
let (f, d) := p in
match f#d with
| None => (r <-$ (r0 <-$ {0, 1}^n; if (negb (inRange _ f r0)) then ret r0 else getUnusedBvector f) ; ret ((d, r) :: f, r))
| Some r => ret (f, r)
end.
intuition.
unfold randomPerm_unroll.
case_eq (ls#b0); intuition; wftac.
edestruct H; eauto.
eapply getUnusedBvector_wf_h.
eauto.
Qed.
(* A random permutation in which the loop that gets an unused value form the range is unrolled one step and the permutation keeps track of whether the first attempt located a value that is already in the range.  This is useful when comparing to a random function. *)
Definition randomPerm_bad(p : (list (Bvector n * Bvector n)) *  Bvector n) : Comp (list (Bvector n * Bvector n) * Bvector n) :=
let (f, d) := p in
match f#d with
| None =>
r0 <-$ {0,1} ^ n;
r <-$ if (negb (inRange _ f r0)) then ret r0 else getUnusedBvector f;
ret (if (inRange _ f r0) then ((d, r) :: (d, r0) :: f) else ((d, r) :: f), r)
| Some r => ret (f, r)
end.
Fixpoint checkBad(f : list (Bvector n * Bvector n)) : bool :=
match f with
| nil => false
| (d, r) :: f' =>
orb (inRange _ f' r) (checkBad f')
end.
intuition.
unfold randomPerm_bad.
case_eq (ls#d); intuition.
wftac.
wftac.
Qed.
Hint Resolve randomPerm_bad_wf : wftac.
intuition.
unfold randomPerm_Bvector, randomPerm, randomPerm_unroll.
case_eq (s#d); intuition.
unfold getUnusedR.
comp_skip.
eapply repeat_unroll_eq; wftac.
eapply well_formed_perm_1 in H; eauto.
destruct H.
exists x0.
eapply filter_In; intuition.
destruct (inRange _ s x0); intuition.
Qed.
intuition.
unfold randomPerm_unroll in *.
case_eq (ls#d); intuition.
rewrite H1 in H0.
simpl in *.
intuition.
inversion H2; clear H2; subst.
trivial.
rewrite H1 in H0.
apply getSupport_Bind_In in H0.
destruct H0.
intuition.
apply getSupport_Bind_In in H2.
destruct H2.
intuition.
simpl in H3.
intuition.
inversion H0; clear H0; subst.
case_eq (inRange _ ls x0); intuition;
rewrite H0 in H4.
simpl in *.
apply filter_In in H4.
intuition.
eapply well_formed_perm_cons; eauto.
destruct (inRange _ ls r); intuition.
simpl in *.
intuition. subst.
eapply well_formed_perm_cons; eauto.
Qed.
intuition.
destruct p.
eapply randomPerm_unroll_preserves_wf; eauto.
Qed.
intuition.
unfold randomPerm_bad in *.
case_eq (ls#d); intuition;
rewrite H1 in H0.
simp_in_support.
trivial.
simp_in_support.
case_eq (inRange _ ls x); intuition;
rewrite H0 in H3.
simp_in_support.
simpl in *.
intuition.
inversion H3; clear H3; subst.
apply filter_In in H4.
intuition.
unfold well_formed_Bvector_perm, well_formed_perm in *.
intuition.
destruct (in_dec (EqDec_dec _) d lsd).
specialize (H6 d).
intuition.
simpl in *.
rewrite eqbBvector_complete in H7.
discriminate.
edestruct (H (d :: lsd)).
econstructor; trivial.
intuition.
simpl in H7.
intuition. subst.
trivial.
specialize (H6 d0).
intuition.
simpl in H7.
destruct (eqbBvector d0 d).
discriminate.
trivial.
intuition.
destruct (in_dec (EqDec_dec _) r x0).
exists (removeFirst (EqDec_dec _) x0 r).
intuition.
simpl.
case_eq (eqbBvector r0 r); intuition.
apply eqbBvector_sound in H11.
subst.
exfalso.
eapply removeFirst_NoDup_not_in; eauto.
case_eq (eqbBvector r0 x); intuition.
apply eqbBvector_sound in H12.
subst.
assert (inRange  _ ls x = false).
eapply H8.
eapply removeFirst_in_iff.
eauto.
congruence.
eapply H8.
eapply removeFirst_in_iff.
eauto.
simpl.
eapply in_getAllBvectors.
eapply removeFirst_NoDup.
trivial.
eapply eq_add_S.
simpl in H10.
rewrite H10.
symmetry.
eapply removeFirst_length.
trivial.
destruct x0.
simpl in *.
omega.
exists x0.
intuition.
simpl.
simpl in n1.
intuition.
case_eq (eqbBvector r0 r); intuition.
apply eqbBvector_sound in H13.
subst.
intuition.
case_eq (eqbBvector r0 x); intuition.
apply eqbBvector_sound in H14.
subst.
assert (inRange _ ls x = false).
eapply H8.
simpl.
right.
trivial.
congruence.
eapply H8.
simpl.
intuition.
simpl.
eapply in_getAllBvectors.
inversion H7; clear H7; subst.
trivial.
repeat simp_in_support.
eapply well_formed_perm_cons; trivial.
simpl in *.
discriminate.
Qed.

Lemma randomPerm_bad_preserves_wf_pair : forall ls d p,
well_formed_Bvector_perm ls ->
In p (getSupport (randomPerm_bad (ls, d))) ->
well_formed_Bvector_perm (fst p).