packages feed

cpsa-4.4.3: coq/Derives.v

(* Derivability

Copyright (c) 2021 The MITRE Corporation

This program is free software: you can redistribute it and/or
modify it under the terms of the BSD License as published by the
University of California. *)

(** * Derivability *)

Require Import List ListSet Bool Lia Alg Sem_tactics.

(** [derives pub t] when [t] can be derived using the terms in [pub]. *)

Inductive derives (pub: list alg): alg -> Prop :=
| Der_mem: forall x: alg, In x pub -> derives pub x
| Der_tagg: forall s, derives pub (Tg s)
| Der_pair: forall x y,
    derives pub x -> derives pub y -> derives pub (Pr x y)
| Der_encr: forall x y,
    derives pub x -> derives pub y -> derives pub (En x y)
| Der_hash: forall x,
    derives pub x -> derives pub (Hs x)
| Der_frst: forall x y, derives pub (Pr x y) -> derives pub x
| Der_scnd: forall x y, derives pub (Pr x y) -> derives pub y
| Der_decr: forall x y,
    derives pub (En x y) -> derives pub (inv y) -> derives pub x.
#[global]
Hint Constructors derives : core.

(* There is no good way to implement derives directly in code.  There
   is an easy way to do it with analyze-then-synthesize.  Here is the
   algorithm used in CPSA and in the role compiler:

synth(T, t): bool :=
  if t in T return true;
  if t = (t1, t2) return synth t1 && synth t2;
  if t = (enc t1 t2) return synth t1 && synth t2;
  if t = (hash t1) return synth t1;
  if t = "..." return true.

analyze(T): set of terms :=
  while T changes do
      let t = some element in T;
      if t = (t1, t2) then add t1 and t2 to T
      else if t = (enc t1 t2) and synth(T, invk(t2)) then add t1 to T;
   done;
   return T.
*)

(* synth pub t when t can be synthesized using the terms in pub. *)
Inductive synth (pub: alg -> Prop): alg -> Prop :=
| Synth_mem: forall x: alg, pub x -> synth pub x
| Synth_tag: forall i, synth pub (Tg i)
| Synth_pair: forall x y,
    synth pub x -> synth pub y -> synth pub (Pr x y)
| Synth_encr: forall x y,
    synth pub x -> synth pub y -> synth pub (En x y)
| Synth_hash: forall x,
    synth pub x -> synth pub (Hs x).
#[global]
Hint Constructors synth : core.

(* analyze pub t when t can be analyzed using the terms in pub. *)
Inductive analyze (pub: list alg): alg -> Prop :=
| Analyze_mem: forall x: alg, In x pub -> analyze pub x
| Analyze_frst: forall x y, analyze pub (Pr x y) -> analyze pub x
| Analyze_scnd: forall x y, analyze pub (Pr x y) -> analyze pub y
| Analyze_decr: forall x y,
    analyze pub (En x y) -> synth (analyze pub) (inv y) -> analyze pub x.

Theorem derives_implies_analyze_then_synth:
  forall pub x, derives pub x -> synth (analyze pub) x.
Proof.
  intros pub x H.
  induction H; auto.
  - apply Synth_mem; apply Analyze_mem; assumption.
  - inv IHderives; auto.
    apply Analyze_frst in H0.
    apply Synth_mem; assumption.
  - inv IHderives; auto.
    apply Analyze_scnd in H0.
    apply Synth_mem; assumption.
  - inv IHderives1; auto.
    apply Analyze_decr in H1; auto.
Qed.

(* Failed attempt that the final Theorem *)

Theorem analyze_then_synth_implies_derives:
  forall pub x, synth (analyze pub) x -> derives pub x.
Proof.
  intros pub x H.
  induction H; auto.
  induction H.
  - apply Der_mem; auto.
  - eapply Der_frst; eauto.
  - eapply Der_scnd; eauto.
  - eapply Der_decr; eauto.
    clear IHanalyze H x.
    (* HELP!!! *)
    give_up.
Abort.

(* Analyze stratified *)

Inductive analyze_strat (pub: list alg): nat -> alg -> Prop :=
| Analyze_strat_mem: forall x,
    In x pub ->
    analyze_strat pub 0 x
| Analyze_strat_incl: forall n x,
    analyze_strat pub n x ->
    analyze_strat pub (S n) x
| Analyze_strat_frst: forall n x y,
    analyze_strat pub n (Pr x y) ->
    analyze_strat pub (S n) x
| Analyze_strat_scnd: forall n x y,
    analyze_strat pub n (Pr x y) ->
    analyze_strat pub (S n) y
| Analyze_strat_decr: forall n x y,
    analyze_strat pub n (En x y) ->
    synth (analyze_strat pub n) (inv y) ->
    analyze_strat pub (S n) x.
#[global]
Hint Constructors analyze_strat : core.

Lemma analyze_strat_zero:
  forall pub t,
    analyze_strat pub 0 t <-> In t pub.
Proof.
  split; intros.
  - inv H; auto.
  - apply Analyze_strat_mem; auto.
Qed.

Lemma analyze_strat_zero_then_synth:
  forall pub t,
    synth (analyze_strat pub 0) t <-> synth (fun y => In y pub) t.
Proof.
  split; intros.
  - induction H; simpl; auto.
    rewrite analyze_strat_zero in H.
    apply Synth_mem; auto.
  - induction H; simpl; auto.
Qed.

Lemma synth_implies_derives:
  forall pub x, synth (fun y => In y pub) x -> derives pub x.
Proof.
  intros pub x H.
  induction H; auto.
Qed.

Lemma analyze_strat_derives:
  forall pub n t,
    synth (analyze_strat pub n) t -> derives pub t.
Proof.
  induction n; intros.
  - rewrite analyze_strat_zero_then_synth in H.
    apply synth_implies_derives; auto.
  - induction H; simpl; auto.
    inv H.
    + apply IHn.
      apply Synth_mem; auto.
    + apply Der_frst with (y := y); auto.
    + apply Der_scnd with (x := x0); auto.
    + apply IHn in H2.
      apply Der_decr with (y := y); auto.
Qed.

Lemma analyze_strat_monotonic_1:
  forall pub m t,
    synth (analyze_strat pub m) t ->
    synth (analyze_strat pub (S m)) t.
Proof.
  intros.
  induction H; simpl; auto.
Qed.

Lemma analyze_strat_monotonic_2:
  forall pub m n t,
    synth (analyze_strat pub m) t ->
    synth (analyze_strat pub (n + m)) t.
Proof.
  intros.
  induction n; simpl; auto.
  apply analyze_strat_monotonic_1; auto.
Qed.

Lemma analyze_strat_monotonic:
  forall pub m n t,
    m <= n ->
    synth (analyze_strat pub m) t ->
    synth (analyze_strat pub n) t.
Proof.
  intros pub m n t H G.
  apply analyze_strat_monotonic_2 with (n := n - m) in G.
  assert (F: n - m + m = n).
  - lia.
  - rewrite F in G; auto.
Qed.

(* Reflection for synth *)

Fixpoint synthb (pub: list alg) t: bool :=
  set_mem alg_dec t pub ||
          match t with
          | Pr x y => synthb pub x && synthb pub y
          | En x y => synthb pub x && synthb pub y
          | Hs x => synthb pub x
          | Tg _ => true
          | _ => false
          end.

Lemma synthb_correct :
  forall pub x, synth (fun y => In y pub) x <-> synthb pub x = true.
Proof.
  split.
  - intro H.
    induction H; try apply orb_true_iff; intuition auto with *.
    destruct x; apply orb_true_iff; left; apply set_mem_correct2; auto.
  - induction x; intro H; simpl in H; apply orb_true_iff in H;
      destruct H; auto;
        try match goal with
            | [ H: set_mem alg_dec _ pub = true |- _ ] =>
              apply set_mem_correct1 in H; auto
            end; try intuition auto with *.
    + apply andb_true_iff in H.
      destruct H; auto.
    + apply andb_true_iff in H.
      destruct H; auto.
Qed.