Library stealth

Require Import Coq.Bool.Bool.
Require Import Coq.Arith.Arith.
Require Import Coq.Arith.EqNat.
Require Import Coq.omega.Omega.
Require Import Coq.Lists.List.
Require Import Coq.omega.Omega.
Require Import Coq.Sets.Multiset.
Require Import Coq.Lists.ListSet.
Require Import Coq.Strings.String.
Require Import Coq.Classes.RelationClasses.
Open Scope string_scope.

Import ListNotations.


Set Implicit Arguments.
Scheme Equality for list.
Contents :
0: General House Keeping
1: Syntax definitions
2: Equality, membership and extraction functions for the syntax 2A: Equality functions 2B: Membership functions 2C: Extraction of submembers functions
3: Tests and Definitions for Well formedness 3A: Functions to test no or One Input / Output in facts 3B: Definitions on Variables and Terms for Equivalence proof 3B: Well formedness definitions 3C: Some useful lemmas on well formedness
4: Substitution
5: Ground terms and rules instances
6: Tamarin Reduction
7: Example
8: Definitions from Chapter 5 of the thesis
9: Definitions from Chapter 6 of the thesis
10: Definitions and Proofs from Chapter 6 and 7 10A: Types of Facts allowed in the system
11: Definitions from Chapter 6 of thesis
==========================

0: General House Keeping

===========================

Fixpoint trueForAll {A:Type} (f:A->Prop) (l:list A) : Prop :=
  match l with
  | [] => True
  | h::ts => (f h) /\ (trueForAll f ts)
  end.

Fixpoint btrueForAll {A:Type} (f:A->bool) (l:list A) : bool :=
  match l with
  | [] => true
  | h::ts => andb (f h) (btrueForAll f ts)
  end.

Fixpoint trueForOne {A:Type} (f:A->Prop) (l:list A) : Prop :=
  match l with
  | [] => True
  | h::ts => (f h) \/ (trueForAll f ts)
  end.

Fixpoint appendAny {A:Type} l1 l2 : list A :=
  match l1 with
  | [] => l2
  | h :: t => h :: (appendAny t l2)
  end.

Fixpoint consEnd {A:Type} fs f : (list A) :=
  match fs with
  | [] => [f]
  | h :: t => h :: (consEnd t f)
  end.

Fixpoint lastElement {A:Type} (a:A) (als:list A) : A :=
  match als with
  | [] => a
  | h :: t => lastElement h t
  end.

Fixpoint secondLastElement {A:Type} (a:A) (als:list A) : A :=
  match als with
  | [] => a
  | h::[] => a
  | h1 :: h2 :: t => lastElement h1 (h2::t)
  end.

Fixpoint listWithoutLastElement {A:Type} (als:list A) : list A :=
  match als with
  | [] => []
  | h::[] => []
  | h :: t => h:: listWithoutLastElement t
  end.

Definition isLastElement {A:Type} (a:A) (als:list A) : Prop := (eq a (lastElement a als)).

Lemma listEq : forall {A:Type} (h1:A) h2 ts2 ts1, h1=h2 -> ts2=ts1 -> h1::ts2=h2::ts1.

Lemma listEqHead : forall {A:Type} (h:A) ts2 ts1, ts2=ts1 -> h::ts2=h::ts1.

Lemma listEqTail : forall {A:Type} (h1:A) h2 ts, h1=h2 -> h1::ts=h2::ts.

Fixpoint removeElement {A:Type} (eqA:forall a b : A, {a = b} + {a <> b}) (e:A) (l:list A) : list A :=
  match l with
    | [] => []
    | h::ts => if (eqA h e) then ts else (h::(removeElement eqA e ts))
  end.

Inductive prefixList {A:Type} : (list A) -> (list A) -> Prop :=
  | Empty_PreFix : forall l, prefixList [] l
  | Head_PreFix : forall l1 l2 a, prefixList l1 l2 -> prefixList (a::l1) (a::l2)
  | Next_PreFix : forall l1 l2 a, prefixList l1 l2 -> prefixList l1 (a::l2).

Fixpoint NotIn {A:Type} (a : A) (ls : list A) : Prop :=
  match ls with
    | [] => True
    | h::ts => a <> h /\ NotIn a ts
  end.

Fixpoint noCommonElements {A:Type} (f1:list A) (f2:list A): Prop :=
 match f1 with
  | [] => True
  | f11::f1s => NotIn f11 f2 /\ noCommonElements f1s f2
end.

Fixpoint termsDoNotAppear {A:Type} (f1: list A) (f2:list (list A)): Prop :=
 match f2 with
  | [] => True
  | f21::f2s => noCommonElements f1 f21 /\ termsDoNotAppear f1 f2s
end.

Fixpoint someCommonElements {A:Type} (f1:list A) (f2:list A): Prop :=
 match f1 with
  | [] => False
  | f11::f1s => In f11 f2 \/ someCommonElements f1s f2
end.

Fixpoint mapFunction {A:Type} {B:Type} (f:A -> B) (als:list A) : (list B) :=
  match als with
    | [] => []
    | h::ts => (f h)::(mapFunction f ts)
  end.

Fixpoint mapListFunction {A:Type} {B:Type} (f:A -> (list B)) (als:list A) : (list B) :=
  match als with
    | [] => []
    | h::ts => appendAny (f h) (mapListFunction f ts)
  end.



Inductive orderedSubList {A:Type} : (list A) -> (list A) -> Prop :=
 | Empty_O_SubList : forall l, orderedSubList [] l
 | Same_O_SubList : forall l1 l2 h1 h2, orderedSubList l1 l2 -> orderedSubList (h1::l1) (h2::l2)
 | Next_O_SubList : forall (l1:list A) l2 h, orderedSubList l1 l2 -> orderedSubList l1 (h::l2).

Lemma idIsOrderedSublist : forall {A:Type} (rl:list A), orderedSubList rl rl.



============================ 1: Syntax definitions ===========================


Definition freshNameSetup : Type := string. Definition freshNameProto : Type := string.
Definition sidTerm : Type := string.
Definition publicName : Type := string.
Inductive name : Type :=
  | Fresh_S : freshNameSetup -> name
  | Fresh_P : freshNameProto -> name
  | Pub : publicName -> name.

Definition n : string := "n".
Definition x : string := "x".

Definition names : Type := list name.

Definition variable : Type := string.
Definition variables : Type := list variable.

Inductive baseTerm : Type :=
  | Var : variable -> baseTerm
  | Name : name -> baseTerm.

Definition baseTerms : Type := list baseTerm.

Definition func_name : Type := string.

Inductive term : Type :=
  | Func : func_name -> list baseTerm -> term
  | Bterm : baseTerm -> term.

Definition terms : Type := list term.

Inductive tpair: Type :=
  | pair : term -> term -> tpair
  | emptypair : tpair.

Definition tpairs : Type := list tpair.
Action Label with facts (values)

Inductive actionLabel : Type :=
  | ActLabel : name -> terms -> actionLabel.
I'm not sure if this should be name, of some over kind
Label with facts : List of Action Label with facts (values)


Inductive label : Type :=
 | BasicLabel : list actionLabel -> label
 | LoggedLabel : actionLabel -> list actionLabel -> label
 | LoggedSIDLabel : baseTerm -> actionLabel -> list actionLabel -> label.

Definition emptyLabel := (BasicLabel []).

Inductive fact : Type :=
  | IN : terms -> fact
An input
  | OUT : terms -> fact
An output
  | K : terms -> fact
Attacker knowledge
  | STATE : name -> terms -> fact
General protocol state informtaion. I'm not sure if this should be name, or some over kind kind of identifier
  | FR_P : baseTerm -> fact.
A new fresh name in protocol stage

Definition facts : Type := list fact.

A rule is a triple : pattern followed by Label followed by patterns

Definition trace : Type := list label.

Inductive rule : Type :=
  | RuleSetup : facts -> label -> facts -> rule
  | RuleProto : facts -> label -> facts -> rule.

A ruleList : List of rule
Definition ruleList : Type := list rule.

===================================

2: Equality, membership and extraction functions for the syntax

=================================== =================================== 2A: Equality functions =================================== We have defined two versions for the same definitions anything starting with "b" returns a bool otherwise Prop

Inductive b2p : bool -> Prop :=
  | b2pt : True -> b2p true.

"beq_string s1 s2 "checks whether two strings are equal

Definition beq_string (s1:string) (s2:string) : bool :=
           if (string_dec s1 s2) then true else false.

Lemma beq_string_EQ : forall s1 s2, beq_string s1 s2 = true -> s1 = s2.

Fixpoint beq_A_list (A:Type) (beq_A: A->A->bool) (s1:list A) (s2:list A) : bool :=
  match s1,s2 with
   | [],[] => true
   | h1::ts1, h2::ts2 => andb (beq_A h1 h2) (beq_A_list beq_A ts1 ts2)
   | _, _ => false
  end.

Fixpoint eq_A_list (A:Type) (eq_A: A->A->Prop) (s1:list A) (s2:list A) : Prop :=
  match s1,s2 with
   | [],[] => True
   | h1::ts1, h2::ts2 => (eq_A h1 h2) /\ (eq_A_list eq_A ts1 ts2)
   | _, _ => False
  end.

"beq_string_list s1 s2 "checks whether two lists of strings are equal

Definition beq_string_list : (list string) -> (list string) -> bool := beq_A_list beq_string.

Definition eq_string (s1:string) (s2:string) : Prop := b2p (beq_string s1 s2).

Definition eq_string_list (s1: list string) (s2:list string) : Prop := b2p (beq_string_list s1 s2).

"eq_base_term t1 t2 "checks whether two baseterms are equal

Fixpoint beq_name (n1:name) (n2:name) : bool :=
  match n1,n2 with
    | Fresh_P s1 , Fresh_P s2 => beq_string s1 s2
    | Fresh_S s1 , Fresh_S s2 => beq_string s1 s2
    | Pub s1, Pub s2 => beq_string s1 s2
    | _, _ => false
   end.

Definition eq_name (n1:name) (n2:name) : Prop := b2p (beq_name n1 n2).

Definition beq_names : (list name) -> (list name) -> bool := beq_A_list beq_name.

Lemma beq_name_EQ : forall n1 n2, beq_name n1 n2 = true -> n1 = n2.

Definition name_dec : forall b1 b2 : name, {b1 = b2} + {b1 <> b2}.
Defined.

Fixpoint beq_baseTerm (t1:baseTerm) (t2:baseTerm) : bool :=
  match t1,t2 with
    | Var x,Var y => beq_string x y
    | Name n1, Name n2 => beq_name n1 n2
    | _, _ => false
   end.

Fixpoint eq_baseTerm (t1:baseTerm) (t2:baseTerm) : Prop :=
  match t1,t2 with
    | Var x,Var y => eq_string x y
    | Name n1, Name n2 => eq_name n1 n2
    | _, _ => False
   end.

Definition baseTerm_dec : forall b1 b2 : baseTerm, {b1 = b2} + {b1 <> b2}.
Defined.

Definition beq_baseTerms : (list baseTerm) -> (list baseTerm) -> bool := beq_A_list beq_baseTerm.

Definition eq_baseTerms : (list baseTerm) -> (list baseTerm) -> Prop := eq_A_list eq_baseTerm.

Definition baseTerms_dec : forall bl1 bl2 : (list baseTerm), {bl1 = bl2} + {bl1 <> bl2}.
Defined.

Definition beq_term (t1:term) (t2:term) : bool :=
  match t1,t2 with
    | (Bterm b1), (Bterm b2) => beq_baseTerm b1 b2
    | (Func f1 l1), (Func f2 l2) => andb (beq_string f1 f2) (beq_baseTerms l1 l2)
    | _, _ => false
   end.

Definition beq_terms : (list term) -> (list term) -> bool := beq_A_list beq_term.

Definition eq_term (t1:term) (t2:term) : Prop :=
  match t1,t2 with
    | (Bterm b1), (Bterm b2) => eq_baseTerm b1 b2
    | (Func f1 l1), (Func f2 l2) => (eq_string f1 f2) /\ (eq_baseTerms l1 l2)
    | _, _ => False
   end.

Definition eq_terms : (list term) -> (list term) -> Prop := eq_A_list eq_term.

Definition term_dec : forall t1 t2 : term, {t1 = t2} + {t1 <> t2}.
Defined.

Definition terms_dec : forall ts1 ts2 : terms, {ts1 = ts2} + {ts1 <> ts2}.
Defined.

Fixpoint beq_fact (f1:fact) (f2:fact) : bool :=
  match f1,f2 with
   | IN ts1, IN ts2 => beq_terms ts1 ts2
   | OUT ts1, OUT ts2 => beq_terms ts1 ts2
   | K ts1, K ts2 => beq_terms ts1 ts2
   | STATE n1 ts1, STATE n2 ts2 => andb (beq_name n1 n2) (beq_terms ts1 ts2)
   | FR_P bt1, FR_P bt2 => beq_baseTerm bt1 bt2
   | _, _ => false
  end.

Fixpoint eq_fact (f1:fact) (f2:fact) : Prop :=
  match f1,f2 with
   | IN ts1, IN ts2 => eq_terms ts1 ts2
   | OUT ts1, OUT ts2 => eq_terms ts1 ts2
   | K ts1, K ts2 => eq_terms ts1 ts2
   | STATE n1 ts1, STATE n2 ts2 => eq_name n1 n2 /\ eq_terms ts1 ts2
   | FR_P bt1, FR_P bt2 => eq_baseTerm bt1 bt2
   | _, _ => False
  end.

Definition eq_facts : (list fact) -> (list fact) -> Prop := eq_A_list eq_fact.

Definition beq_facts : (list fact) -> (list fact) -> bool := beq_A_list beq_fact.

Definition fact_dec : forall f1 f2 : fact, {f1 = f2} + {f1 <> f2}.
Defined.

Definition facts_dec : forall fs1 fs2 : facts, {fs1 = fs2} + {fs1 <> fs2}.
Defined.

Definition tpair_dec : forall tp1 tp2 : tpair, {tp1 = tp2} + {tp1 <> tp2}.
Defined.

Definition tpairs_dec : forall ts1 ts2 : tpairs, {ts1 = ts2} + {ts1 <> ts2}.
Defined.

Definition beq_var (v1:variable) (v2:variable) : bool := beq_string v1 v2.
Definition beq_vars_list : (list variable) -> (list variable) -> bool := beq_A_list beq_var.

Definition beq_actionLabel (a1:actionLabel) (a2:actionLabel) : bool :=
  match a1, a2 with
   | ActLabel n1 ts1, ActLabel n2 ts2 => andb (beq_name n1 n2) (beq_terms ts1 ts2)
   end.

Definition beq_actionLabels : (list actionLabel) -> (list actionLabel) -> bool := beq_A_list beq_actionLabel.

Definition actionLabel_dec : forall t1 t2 : actionLabel, {t1 = t2} + {t1 <> t2}.
Defined.

Definition actionLabels_dec : forall t1 t2 : list actionLabel, {t1 = t2} + {t1 <> t2}.
Defined.

Definition eq_actionLabel (a1:actionLabel) (a2:actionLabel) : Prop := b2p (beq_actionLabel a1 a2).

Definition eq_actionLabels (al1:list actionLabel) (al2:list actionLabel) : Prop := b2p (beq_actionLabels al1 al2).

Definition label_dec : forall l1 l2 : label, {l1 = l2} + {l1 <> l2}.
Defined.

Definition beq_label (l1:label) (l2:label) : bool :=
  match l1, l2 with
   | BasicLabel ll1 , BasicLabel ll2 => beq_actionLabels ll1 ll2
   | LoggedLabel al1 ll1 , LoggedLabel al2 ll2 => andb (beq_actionLabel al1 al2) (beq_actionLabels ll1 ll2)
   | _, _ => false
  end.

Definition eq_label (l1:label) (l2:label) : Prop :=
  match l1, l2 with
   | BasicLabel ll1 , BasicLabel ll2 => eq_A_list eq_actionLabel ll1 ll2
   | LoggedLabel lg1 ll1 , LoggedLabel lg2 ll2 => eq_A_list eq_actionLabel ll1 ll2
                                                    /\ eq_actionLabel lg1 lg2
   | _, _ => False
  end.

Definition beq_trace : trace -> trace -> bool := beq_A_list beq_label.

Definition eq_trace : trace -> trace -> Prop := eq_A_list eq_label.

Definition rule_dec : forall r1 r2 : rule, {r1 = r2} + {r1 <> r2}.
Defined.

Definition rules_dec : forall r1 r2 : ruleList, {r1 = r2} + {r1 <> r2}.
Defined.

============================================== 2B: Membership functions : MEMBERSHIP TESTS ==================================================

Fixpoint member {A:Type} (r:A) (rl:list A) : Prop :=
  match rl with
   | [] => False
   | r1::rs => r=r1 \/ (member r rs)
  end.

Fixpoint memberWith {A:Type} (x : A) (l : list A) (beq_test : A->A->bool) : bool :=
    match l with
      | [] => false
      | h :: ts => orb (beq_test x h) (memberWith x ts beq_test)
    end.

Fixpoint memberOnce {A:Type} (a : A) (ls : list A) : Prop :=
  match ls with
    | [] => False
    | h::ts => a = h /\ NotIn a ts
  end.

Definition removeFact : fact -> facts -> facts := removeElement fact_dec.

Fixpoint removeFacts (facts1:facts) (facts2:facts) : facts :=
  match facts1 with
    | [] => facts2
    | h::ts => removeFact h (removeFacts ts facts2)
  end.


Fixpoint subList (l1:list fact) (l2:list fact) : Prop :=
  match l1,l2 with
    | [],_ => True
    | _,[] => False
    | h1::t,l2 => (In h1 l2) /\ (subList t (removeFact h1 l2))
  end.

Definition b_inLabel (al:actionLabel) (lb:label) : bool :=
 match lb with
   | BasicLabel ll1 => memberWith al ll1 beq_actionLabel
   | LoggedLabel lg1 ll1 => orb (beq_actionLabel al lg1) (memberWith al ll1 beq_actionLabel)
   | LoggedSIDLabel t lg1 ll1 => orb (beq_actionLabel al lg1) (memberWith al ll1 beq_actionLabel)
  end.

"inLabel al lb" verifies whether the action label "al" is in the label "lb" or not
Fixpoint inLabel (al:actionLabel) (lb:label) : Prop :=
    match lb with
      | BasicLabel ll => member al ll
      | LoggedLabel lg ll => ( eq_actionLabel lg al) \/ member al ll
      | LoggedSIDLabel t lg ll => ( eq_actionLabel lg al) \/ member al ll
    end.

"inLoggedSIDLabel al lb" verifies whether the action label "al" is in the LoggedSIDLabel "lb" or not
Fixpoint inLoggedSIDLabel (al:actionLabel) (lb:label) : Prop :=
    match lb with
      | BasicLabel ll => False
      | LoggedLabel lg ll => False
      | LoggedSIDLabel t lg ll => ( eq_actionLabel lg al)
    end.

"al_in_Trace al tr" verifies whether the action label "al" is in the trace "tr" or not
Fixpoint al_in_Trace (al:actionLabel) (tr:trace) : Prop :=
    match tr with
      | [] => False
      | lbl1 :: lbs => inLabel al lbl1 \/ (al_in_Trace al lbs)
    end.

"LoggedAL_in_Trace al tr" verifies whether the action label "al" is in the trace "tr" or not
Fixpoint LoggedAL_in_Trace (al:actionLabel) (tr:trace) : Prop :=
    match tr with
      | [] => False
      | lbl1 :: lbs => inLoggedSIDLabel al lbl1 \/ (LoggedAL_in_Trace al lbs)
    end.

"LoggedLbl_in_Trace al tr" verifies whether the Label "lbl" is in the trace "tr" or not
Fixpoint LoggedLbl_in_Trace (lbl:label) (tr:trace) : Prop :=
    match tr with
      | [] => False
      | lbl1 :: lbs => (eq_label lbl lbl1) \/ (LoggedLbl_in_Trace lbl lbs)
    end.

"b_lbl_inTrace lb tr" verifies whether label "lb" is in trace "tr" or not "lb" is either the first member of "tr" or somehere before the end of trace

Definition b_label_in_Trace (lb:label) (tr:trace) : bool := memberWith lb tr beq_label.

Definition b_labelS_in_Trace (lb:label) (tr:trace) : bool := memberWith lb tr beq_label.

Definition beq_trace_in_Traces (tr:trace) (trlist:list trace) : bool := memberWith tr trlist beq_trace.


"beq_actionLabelName a1 a2 "checks whether two action labels in template have the same name
Definition beq_actionLabelName (a1:actionLabel) (a2:actionLabel) : bool :=
  match a1, a2 with
   | ActLabel n1 ts1, ActLabel n2 ts2 => (beq_name n1 n2)
   end.

Definition eq_actionLabelName (a1:actionLabel) (a2:actionLabel) : Prop := b2p (beq_actionLabelName a1 a2).

"inLabelName al lb" verifies whether the action label "al" is in the label "lb" or not
Definition b_inLabelwithName (al:actionLabel) (lb:label) : bool :=
 match lb with
   | BasicLabel ll1 => memberWith al ll1 beq_actionLabelName
   | LoggedLabel lg1 ll1 => orb (beq_actionLabelName al lg1) (memberWith al ll1 beq_actionLabelName)
   | LoggedSIDLabel t lg1 ll1 => orb (beq_actionLabelName al lg1) (memberWith al ll1 beq_actionLabelName)
  end.

Fixpoint memberName (al:actionLabel) (lb:list actionLabel) : Prop :=
  match lb with
   | [] => False
   | l1::ls => (eq_actionLabelName al l1) \/ (memberName al ls)
  end.

Fixpoint inLabelwithName (al:actionLabel) (lb:label) : Prop :=
    match lb with
      | BasicLabel ll => memberName al ll
      | LoggedLabel lg ll => ( eq_actionLabelName lg al) \/ memberName al ll
      | LoggedSIDLabel t lg ll => ( eq_actionLabelName lg al) \/ memberName al ll
    end.

Fixpoint b_ALinTemplatewithName (al:actionLabel) (tm:trace) : bool :=
  match tm with
  | [] => false
  | tm1::tms => orb (b_inLabelwithName al tm1) (b_ALinTemplatewithName al tms)
  end.

Fixpoint b_ALinStdTemplateswithName (al:actionLabel) (StdTemps:list trace) : bool :=
  match StdTemps with
  | [] => false
  | tm1::tms => orb (b_ALinTemplatewithName al tm1) (b_ALinStdTemplateswithName al tms)
  end.

Definition ALinTemplatewithName (al:actionLabel) (tm:trace) : Prop := b2p (b_ALinTemplatewithName al tm).

Definition ALinStdTemplateswithName (al:actionLabel) (tms:list trace) : Prop := b2p (b_ALinStdTemplateswithName al tms).

Fixpoint InList (tm : term) (tmlist : terms) : bool :=
  match tmlist with
  | [] => false
  | ml1::mls => orb (beq_term tm ml1) (InList tm mls)
  end.

Fixpoint commonTerms (v1:terms) (v2:terms): terms :=
 match v1 with
  | [] => []
  | v11 :: v1s => if InList v11 v2 then (v11::(commonTerms v1s v2)) else commonTerms v1s v2
end.

Fixpoint commonTermsAL (alp1:actionLabel) (alp2:actionLabel): terms :=
  match alp1, alp2 with
  | ActLabel nm1 vars1, ActLabel nm2 vars2 => commonTerms vars1 vars2
  end.


Fixpoint hasFunction (tm:terms) : Prop :=
match tm with
  | tm1::tms => match tm1 with
                          | Func _ _ => True
                          | _ => hasFunction tms
                 end
  | [] => False
end.

Fixpoint hasPubNameInBaseTerms (btm:baseTerms) : Prop :=
match btm with
    | btm1::btms => match btm1 with
                       | (Var _) => hasPubNameInBaseTerms btms
                       | (Name nm) => match nm with
                                          | Pub _ => True
                                          | _ => hasPubNameInBaseTerms btms
                                         end
                      end
  | [] => False
end.

Fixpoint b_hasPubNameInBaseTerms (btm:baseTerms) : bool :=
match btm with
    | btm1::btms => match btm1 with
                       | (Var _) => b_hasPubNameInBaseTerms btms
                       | (Name nm) => match nm with
                                          | Pub _ => true
                                          | _ => b_hasPubNameInBaseTerms btms
                                         end
                      end
  | [] => false
end.

Fixpoint hasPubName (tm:terms) : Prop :=
match tm with
  | tm1::tms => match tm1 with
                    | Func f bts => hasPubNameInBaseTerms bts
                    | Bterm bt => match bt with
                       | (Var _) => hasPubName tms
                       | (Name nm) => match nm with
                                          | Pub _ => True
                                          | _ => hasPubName tms
                                         end
                      end

                 end
  | [] => False
end.

Fixpoint getPubNameInBaseTerms (t:term) (btm:baseTerms) : term :=
match btm with
    | btm1::btms => match btm1 with
                       | (Var _) => getPubNameInBaseTerms t btms
                       | (Name nm) => match nm with
                                          | Pub pn => Bterm (Name (Pub pn))
                                          | _ => getPubNameInBaseTerms t btms
                                         end
                      end
  | [] => t
end.

Fixpoint getPubName (t:term) (tm:terms) : term :=
match tm with
  | tm1::tms => match tm1 with
                    | Func f bts => getPubNameInBaseTerms t bts
                    | Bterm bt => match bt with
                       | (Var _) => getPubName t tms
                       | (Name nm) => match nm with
                                          | Pub pn => Bterm (Name (Pub pn))
                                          | _ => getPubName t tms
                                         end
                      end

                 end
  | [] => t
end.

Fixpoint b_hasPubName (tm:terms) : bool :=
match tm with
  | tm1::tms => match tm1 with
                    | Func f bts => b_hasPubNameInBaseTerms bts
                    | Bterm bt => match bt with
                       | (Var _) => b_hasPubName tms
                       | (Name nm) => match nm with
                                          | Pub _ => true
                                          | _ => b_hasPubName tms
                                         end
                      end

                 end
  | [] => false
end.

Fixpoint b_hasFunction (tm:terms) : bool :=
match tm with
  | tm1::tms => match tm1 with
                          | Func _ _ => true
                          | _ => b_hasFunction tms
                 end
  | [] => false
end.

Fixpoint selectFunctions (tm: terms) : terms :=
match tm with
  | Func f bt1::tms => (Func f bt1)::(selectFunctions tms)
  | _ ::tms => (selectFunctions tms)
  | [] => []
end.

================================================================================ 2C: Extraction of submembers : Functions to extract facts/logs etc. from rules =================================================================================

Fixpoint premiseFacts (r:rule) : facts :=
  match r with
    | RuleSetup f1 l f2 => f1
    | RuleProto f1 l f2 => f1
  end.

Fixpoint conclFacts (r:rule) : facts :=
  match r with
    | RuleSetup f1 l f2 => f2
    | RuleProto f1 l f2 => f2
  end.

Fixpoint allPremiseFacts (rs:(list rule)) : facts :=
  match rs with
    | [] => []
    | r::rst => appendAny (premiseFacts r) (allPremiseFacts rst)
   end.

Fixpoint allConclFacts (rs:(list rule)) : facts :=
  match rs with
    | [] => []
    | r::rst => appendAny (conclFacts r) (allConclFacts rst)
  end.

Fixpoint allFactsRL (rs:(list rule)) : facts :=
  appendAny (allPremiseFacts rs) (allConclFacts rs).

Fixpoint labelR (r:rule) : label :=
  match r with
    | RuleSetup f1 l f2 => l
    | RuleProto f1 l f2 => l
  end.

Fixpoint getInFactPremise (fp:facts) : facts :=
match fp with
       | f1::fs => match f1 with
                         | IN _ => appendAny [f1](getInFactPremise fs)
                         | OUT _ => (getInFactPremise fs)
                         | K _ => (getInFactPremise fs)
                         | STATE _ _ => (getInFactPremise fs)
                         | FR_P _ => (getInFactPremise fs)
                   end
      | [] => []
end.

Fixpoint getFrFactPremise (fp:facts) : facts :=
match fp with
       | f1::fs => match f1 with
                         | IN _ => (getFrFactPremise fs)
                         | OUT _ => (getFrFactPremise fs)
                         | K _ => (getFrFactPremise fs)
                         | STATE _ _ => (getFrFactPremise fs)
                         | FR_P _ => appendAny [f1](getFrFactPremise fs)
                   end
      | [] => []
end.

Fixpoint getOutFactConclusion (fp:facts) : facts :=
match fp with
       | f1::fs => match f1 with
                         | IN _ => (getOutFactConclusion fs)
                         | OUT _ => appendAny [f1] (getOutFactConclusion fs)
                         | K _ => (getOutFactConclusion fs)
                         | STATE _ _ => (getOutFactConclusion fs)
                         | FR_P _ => (getOutFactConclusion fs)
                   end
      | [] => []
end.

Fixpoint getOutFactProtoRule (rl:rule) : facts :=
  match rl with
  | (RuleProto fp1 lp fp2) => getOutFactConclusion fp2
  | (RuleSetup fp1 lp fp2) => []
  end.

Fixpoint getInFactProtoRule (rl:rule) : facts :=
  match rl with
  | (RuleProto fp1 lp fp2) => getInFactPremise fp1
  | (RuleSetup fp1 lp fp2) => []
  end.

Fixpoint getFrFactProtoRule (rl:rule) : facts :=
  match rl with
  | (RuleProto fp1 lp fp2) => getFrFactPremise fp1
  | (RuleSetup fp1 lp fp2) => []
  end.

Fixpoint removeOutInfromFactList (fs: facts) : facts :=
match fs with
  | [] => []
  | fs1::fss => match fs1 with
                         | IN _ => (removeOutInfromFactList fss)
                         | OUT _ => (removeOutInfromFactList fss)
                         | K _ => appendAny [fs1] (removeOutInfromFactList fss)
                         | STATE _ _ => appendAny [fs1] (removeOutInfromFactList fss)
                         | FR_P _ => appendAny [fs1] (removeOutInfromFactList fss)
                   end
end.


Fixpoint getStateFacts (fp:facts) : facts :=
match fp with
       | f1::fs => match f1 with
                         | IN _ => (getStateFacts fs)
                         | OUT _ => (getStateFacts fs)
                         | K _ => (getStateFacts fs)
                         | STATE _ _ => appendAny [f1](getStateFacts fs)
                         | FR_P _ => (getStateFacts fs)
                   end
      | [] => []
end.

Fixpoint getLogRL (rl: ruleList) : trace :=
  match rl with
    | [] => []
    | rl1::rls => match labelR rl1 with
                    | LoggedLabel lg lb1 => (LoggedLabel lg [])::(getLogRL rls)
                    | _ => getLogRL rls
                   end
  end.

Fixpoint getTermsAL (al:actionLabel) : terms :=
match al with
   | ActLabel NM TRMS => TRMS
end.

Fixpoint getTermsLabel (l1:label) : terms :=
  match l1 with
    | (LoggedSIDLabel t al lb) => (Bterm t):: (getTermsAL al)
    | (LoggedLabel al lb) => []
    | (BasicLabel als) => []
  end.

Fixpoint getFreshProtoNamesinAL (al: list actionLabel) : list freshNameProto :=
 match al with
  | al1::als => match al1 with
                  | ActLabel (Fresh_P fp) t => fp ::(getFreshProtoNamesinAL als)
                  | _ => getFreshProtoNamesinAL als
                 end
  | [] => []
 
 end.

Fixpoint getFreshProtoNamesinLabel (lb: label) : list freshNameProto :=
  match lb with
    | LoggedSIDLabel t al als => match al with
                                  | ActLabel (Fresh_P fp) t => fp :: (getFreshProtoNamesinAL als)
                                  | _ => getFreshProtoNamesinAL als
                                 end
    | BasicLabel al => []
    | LoggedLabel al als => []
   end.

Inductive getSID : label -> baseTerm -> Prop :=
       | validSID : forall t al als, getSID (LoggedSIDLabel t al als) t.

Fixpoint getLogTrace (t:trace) : trace :=
  match t with
    | [] => []
    | h::ts => match h with
                 | LoggedLabel lg lb1 => (LoggedLabel lg [])::(getLogTrace ts)
                 | _ => getLogTrace ts
                end
  end.


Fixpoint getFreshProtoNamesinTrace (tr: trace) : list freshNameProto :=
  match tr with
    | [] => []
    | h::ts => match h with
                 | LoggedLabel al als => match al with
                                                | ActLabel (Fresh_P fp) t => fp :: (getFreshProtoNamesinTrace ts)
                                                | ActLabel _ _ => (getFreshProtoNamesinTrace ts)
                                            end
                 | BasicLabel al => (getFreshProtoNamesinTrace ts)
                 | LoggedSIDLabel t al lb => (getFreshProtoNamesinTrace ts)
                end
   end.

Fixpoint getFreshProtoNamesList (trs: list trace) : list freshNameProto :=
  match trs with
    | [] => []
    | h::ts => appendAny (getFreshProtoNamesinTrace h) (getFreshProtoNamesList ts)
  end.

Fixpoint getFrNamesPremise (fp:facts) : list freshNameProto :=
match fp with
       | f1::fs => match f1 with
                         | IN _ => (getFrNamesPremise fs)
                         | OUT _ => (getFrNamesPremise fs)
                         | K _ => (getFrNamesPremise fs)
                         | STATE _ _ => (getFrNamesPremise fs)
                         | FR_P fp1 =>
                                    match fp1 with
                                      | (Var _) => getFrNamesPremise fs
                                      | (Name nm) => match nm with
                                                        | Fresh_S _ => (getFrNamesPremise fs)
                                                        | Fresh_P fn => fn::(getFrNamesPremise fs)
                                                        | Pub _ => (getFrNamesPremise fs)
                                                        end
                                     end
                   end
      | [] => []
end.

Fixpoint InFresh (fr : freshNameProto) (frlist : list freshNameProto) : bool :=
  match (member fr frlist) with
  | True => true
  end.

Fixpoint commonFreshNames (fr1:list freshNameProto) (fr2:list freshNameProto): list freshNameProto :=
 match fr1 with
  | [] => []
  | fr11 :: fr1s => if (InFresh fr11 fr2) then (fr11::(commonFreshNames fr1s fr2)) else commonFreshNames fr1s fr2
end.



Fixpoint noInputOrOutput (fs:facts) : Prop :=
   match fs with
  | [] => True
  | f::fss => match f with
                | IN ts => False
                | OUT ts => False
                | K ts => noInputOrOutput fss
                | STATE n ts => noInputOrOutput fss
                | FR_P bt => noInputOrOutput fss
               end
  end.

Fixpoint noOutputs (fs:facts) : Prop :=
   match fs with
  | [] => True
  | f::fss => match f with
                | IN ts => noOutputs fss
                | OUT ts => False
                | K ts => noOutputs fss
                | STATE n ts => noOutputs fss
                | FR_P bt => noOutputs fss
               end
  end.

Fixpoint noOutput (f:fact) : Prop :=
  match f with
  | IN t => True
  | OUT t => False
  | K t => True
  | STATE n t => True
  | FR_P fp => True
  end.

Fixpoint noInputs (fs:facts) : Prop :=
   match fs with
  | [] => True
  | f::fss => match f with
                | IN ts => False
                | OUT ts => noInputs fss
                | K ts => noInputs fss
                | STATE n ts => noInputs fss
                | FR_P bt => noInputs fss
               end
  end.

Fixpoint hasInput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => True
                | OUT ts => hasInput fss
                | K ts => hasInput fss
                | STATE n ts => hasInput fss
                | FR_P bt => hasInput fss
               end
  end.
Fixpoint hasOutput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => hasOutput fss
                | OUT ts => True
                | K ts => hasOutput fss
                | STATE n ts => hasOutput fss
                | FR_P bt => hasOutput fss
               end
  end.

Fixpoint oneOutput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => oneOutput fss
                | OUT ts => noOutputs fss
                | K ts => oneOutput fss
                | STATE n ts => oneOutput fss
                | FR_P bt => oneOutput fss
               end
  end.

Fixpoint oneOutputIs (fs:facts) (out:fact) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => oneOutputIs fss out
                | OUT ts1 => match out with
                               | OUT ts2 => ts1=ts2 /\ noOutputs fss
                               | _ => False
                              end
                | K ts => oneOutputIs fss out
                | STATE n ts => oneOutputIs fss out
                | FR_P bt => oneOutputIs fss out
               end
  end.

Fixpoint minOneOutput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => minOneOutput fss
                | OUT ts => True
                | K ts => minOneOutput fss
                | STATE n ts => minOneOutput fss
                | FR_P bt => minOneOutput fss
               end
  end.

Fixpoint moreThanOneOutput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => moreThanOneOutput fss
                | OUT ts => oneOutput fss
                | K ts => moreThanOneOutput fss
                | STATE n ts => moreThanOneOutput fss
                | FR_P bt => moreThanOneOutput fss
               end
  end.

Fixpoint oneInput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => noInputs fss
                | OUT ts => oneInput fss
                | K ts => oneInput fss
                | STATE n ts => oneInput fss
                | FR_P bt => oneInput fss
               end
  end.

Fixpoint oneInputIs (fs:facts) (infact:fact) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts1 => match infact with
                               | IN ts2 => ts1=ts2 /\ noInputs fss
                               | _ => False
                              end
                | OUT ts => oneInputIs fss infact
                | K ts => oneInputIs fss infact
                | STATE n ts => oneInputIs fss infact
                | FR_P bt => oneInputIs fss infact
               end
  end.

Fixpoint minOneInput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => True
                | OUT ts => minOneInput fss
                | K ts => minOneInput fss
                | STATE n ts => minOneInput fss
                | FR_P bt => minOneInput fss
               end
  end.

Fixpoint oneInputAndNoOutputs (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts1 => noInputs fss /\ noOutputs fss
                | OUT ts => False
                | K ts => oneInputAndNoOutputs fss
                | STATE n ts => oneInputAndNoOutputs fss
                | FR_P bt => oneInputAndNoOutputs fss
               end
  end.

Fixpoint oneInputAndNoOutputIs (fs:facts) (infact:fact) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts1 => match infact with
                               | IN ts2 => ts1=ts2 /\ noInputs fss /\ noOutputs fss
                               | _ => False
                              end
                | OUT ts => False
                | K ts => oneInputAndNoOutputIs fss infact
                | STATE n ts => oneInputAndNoOutputIs fss infact
                | FR_P bt => oneInputAndNoOutputIs fss infact
               end
  end.

Fixpoint oneOutputAndNoInput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => False
                | OUT ts1 => noOutputs fss /\ noInputs fss
                | K ts => oneOutputAndNoInput fss
                | STATE n ts => oneOutputAndNoInput fss
                | FR_P bt => oneOutputAndNoInput fss
               end
  end.

Fixpoint oneOutputAndNoInputIs (fs:facts) (out:fact) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => False
                | OUT ts1 => match out with
                               | OUT ts2 => ts1=ts2 /\ noOutputs fss /\ noInputs fss
                               | _ => False
                              end
                | K ts => oneOutputAndNoInputIs fss out
                | STATE n ts => oneOutputAndNoInputIs fss out
                | FR_P bt => oneOutputAndNoInputIs fss out
               end
  end.

Fixpoint oneOutputXorInputIs (fs:facts) (trms:terms) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => ts=trms
                | OUT ts => ts=trms
                | K ts => oneOutputXorInputIs fss trms
                | STATE n ts => oneOutputXorInputIs fss trms
                | FR_P bt => oneOutputXorInputIs fss trms
               end
  end.

Fixpoint oneOrNoOutput (fs:facts) : Prop :=
   match fs with
  | [] => True
  | f::fss => match f with
                | IN ts => oneOrNoOutput fss
                | OUT ts => noOutputs fss
                | K ts => oneOrNoOutput fss
                | STATE n ts => oneOrNoOutput fss
                | FR_P bt => oneOrNoOutput fss
               end
  end.

Fixpoint oneOrNoInput (fs:facts) : Prop :=
   match fs with
  | [] => True
  | f::fss => match f with
                | IN ts => noInputs fss
                | OUT ts => oneOrNoInput fss
                | K ts => oneOrNoInput fss
                | STATE n ts => oneOrNoInput fss
                | FR_P bt => oneOrNoInput fss
               end
  end.

Fixpoint oneInputXorOutput (fs:facts) : Prop :=
   match fs with
  | [] => False
  | f::fss => match f with
                | IN ts => noInputs fss /\ noOutputs fss
                | OUT ts => noInputs fss /\ noOutputs fss
                | K ts => oneInputXorOutput fss
                | STATE n ts => oneInputXorOutput fss
                | FR_P bt => oneInputXorOutput fss
               end
  end.

Fixpoint oneOrNoInputXorOutput (fs:facts) : Prop :=
   match fs with
  | [] => True
  | f::fss => match f with
                | IN ts => noInputs fss /\ noOutputs fss
                | OUT ts => noInputs fss /\ noOutputs fss
                | K ts => oneOrNoInputXorOutput fss
                | STATE n ts => oneOrNoInputXorOutput fss
                | FR_P bt => oneOrNoInputXorOutput fss
               end
  end.

Lemma oneInAndNoOutIsOneInOrOutIs : forall facts trms,
 oneInputAndNoOutputIs facts (IN trms) -> oneOutputXorInputIs facts trms.

Lemma oneOutAndNoInIsOneInOrOutIs : forall facts trms,
 oneOutputAndNoInputIs facts (OUT trms) -> oneOutputXorInputIs facts trms.



Definition constantsInBaseTerm (bt:baseTerm) : variables :=
  match bt with
    | Name (Pub v) => [v]
    | _ => []
  end.

Definition constantsInBaseTerms : (list baseTerm) -> variables := mapListFunction constantsInBaseTerm.

Definition constantsInTerm (t:term) : variables :=
  match t with
    | Func fn bts => constantsInBaseTerms bts
    | Bterm bt => constantsInBaseTerm bt
  end.
Definition constantsInTerms : (list term) -> variables := mapListFunction constantsInTerm.

Definition variablesInBaseTerm (bt:baseTerm) : variables :=
  match bt with
    | Var v => [v]
    | _ => []
  end.

Definition variablesInBaseTerms : (list baseTerm) -> variables := mapListFunction variablesInBaseTerm.

Definition variablesInTerm (t:term) : variables :=
  match t with
    | Func fn bts => variablesInBaseTerms bts
    | Bterm bt => variablesInBaseTerm bt
  end.

Definition variablesInTerms : (list term) -> variables := mapListFunction variablesInTerm.

Definition variablesInFact (f:fact) : variables :=
  match f with
  | IN ts => variablesInTerms ts
  | OUT ts => variablesInTerms ts
  | K ts => variablesInTerms ts
  | STATE n ts => variablesInTerms ts
  | FR_P bt => variablesInBaseTerm bt
  end.

Definition variablesInRule (r:rule) : variables :=
  match r with
    | RuleSetup f1 l f2 => mapListFunction variablesInFact f1
    | RuleProto f1 l f2 => mapListFunction variablesInFact f1
  end.

==================================================================== 3B : Definitions on Variables and Terms for Equivalence proof ====================================================================

Fixpoint baseTermAtSamePosBaseTerms (btm:baseTerm) (bts1: list baseTerm) (bts2:list baseTerm) : Prop :=
  match bts1, bts2 with
    | bt1::btst1, bt2::btst2 => ( bt1=btm /\ bt2=btm ) \/ baseTermAtSamePosBaseTerms btm btst1 btst2
    | _, _ => False
  end.

Definition baseTermAtSamePosTerm (bt:baseTerm) (t1: term) (t2: term) : Prop :=
  match t1, t2 with
    | Bterm bt1, Bterm bt2 => bt1=bt /\ bt2=bt
    | Func n1 bts1, Func n2 bts2 => (n1=n2 /\ baseTermAtSamePosBaseTerms bt bts1 bts2)
    | _, _ => False
  end.

Fixpoint baseTermAtSamePosTerms (bt:baseTerm) (ts1: list term) (ts2:list term) : Prop :=
  match ts1, ts2 with
    | t1::ts1t, t2::ts2t => (baseTermAtSamePosTerm bt t1 t2) \/ (baseTermAtSamePosTerms bt ts1t ts2t)
    | _, _ => False
  end.

Definition variableInInputAndOutputOld (x:variable) (newRule:rule) (pastRules: list rule) : Prop :=
  match pastRules with
    | [] => False
    | prule::prules => exists ts1 ts2, member (IN ts1) (premiseFacts newRule)
                       /\ member (OUT ts2) (conclFacts (lastElement prule prules))
                       /\ baseTermAtSamePosTerms (Var x) ts1 ts2
 end.

Fixpoint termPresentInFirstOutputFound (ts:terms) (pastRules:list rule) : Prop :=
  match pastRules with
    | [] => False
    | prule::prules => if (beq_facts (getOutFactConclusion (conclFacts (lastElement prule prules))) [])
                        then termPresentInFirstOutputFound ts prules
                          else (member (OUT ts) (conclFacts (lastElement prule prules)))
  end.


Definition variableInInputAndOutput (x:variable) (newRule:rule) (pastRules: list rule) : Prop :=
  match pastRules with
    | [] => False
    | prule::prules => exists ts1 ts2, (member (IN ts1) (premiseFacts newRule))
                       /\ termPresentInFirstOutputFound ts2 pastRules
                       /\ baseTermAtSamePosTerms (Var x) ts1 ts2
 end.

Fixpoint NameDoesNotAppearInFacts (n:name) (fs:facts) : Prop :=
   match fs with
    | [] => True
    | fh::fst => match fh with
                   | STATE nm1 ts1 => n <> nm1 /\ (NameDoesNotAppearInFacts n fst)
                   | _ => (NameDoesNotAppearInFacts n fst)
                  end
   end.

Fixpoint stateFactNameDoesNotAppear (f:fact) (fs:facts) : Prop :=
   match f with
    | STATE n ts => NameDoesNotAppearInFacts n fs
    | _ => True
   end.

Fixpoint stateAppearsOnce (f:fact) (fs:facts) : Prop :=
  match fs, f with
    | fh::fst, STATE n1 ts1 => match fh with
                                 | STATE n2 ts2 => (n1=n2 /\ ts1=ts2 /\ NameDoesNotAppearInFacts n1 fst)
                                                   \/ (n1 <> n2 /\ stateAppearsOnce f fst)
                                 | _ => stateAppearsOnce f fst
                               end
    | _, _ => False
  end.

Fixpoint TermsInSamePosition (tm1:terms) (tm2:terms) (t1:term) (t2:term) : Prop :=
  match tm1, tm2 with
   | tm11::tm1s, tm21::tm2s => ((eq_term tm11 t1) /\ (eq_term tm21 t2)) \/ (TermsInSamePosition tm1s tm2s t1 t2)
   | [], [] => False
   | [], _::_ => False
   | _::_, [] => False
  end.

Fixpoint AllTermsEqualPositionWise (tm1:terms) (tm2:terms) : Prop :=
  match tm1, tm2 with
   | tm11::tm1s, tm21::tm2s => (eq_term tm11 tm21 ) /\ (AllTermsEqualPositionWise tm1s tm2s)
   | [], [] => True
   | [], _::_ => False
   | _::_, [] => False
  end.

Fixpoint AllSubTermsEqualPositionWise (bt1:list baseTerm) (bt2:list baseTerm) : Prop :=
  match bt1, bt2 with
   | bt11::bt1s, bt21::bt2s => (eq_baseTerm bt11 bt21 ) /\ (AllSubTermsEqualPositionWise bt1s bt2s)
   | [], [] => True
   | [], _::_ => False
   | _::_, [] => False
  end.

Fixpoint PresentInOutputInputConsecutiveRules (RL:list rule) (t1:term) (t2:term) : Prop :=
match RL with
  | r1::rs => match rs with
                    | rs1::rst => match getOutFactProtoRule r1, getInFactProtoRule rs1 with
                                          | [OUT lt1], [IN lt2] => TermsInSamePosition lt1 lt2 t1 t2
                                          | _,_ => False
                                  end
                    | [] => False
                end
  | [] => False
  end.

Fixpoint comparebaseTerms (t1: baseTerms) (t2: baseTerms) : list tpair :=
match t1, t2 with
      | t11::ts1, t21::ts2 =>
                         (match t11, t21 with
                              | Var v1, Var v2 => if (beq_var v1 v2)
                                                                  then (comparebaseTerms ts1 ts2)
                                                              else (pair (Bterm t11) (Bterm t21))::(comparebaseTerms ts1 ts2)
                              | Name nm1, Name nm2 => if (beq_name nm1 nm2)
                                                           then (comparebaseTerms ts1 ts2)
                                                              else (pair (Bterm t11) (Bterm t21))::(comparebaseTerms ts1 ts2)
                              | _, _ => (comparebaseTerms ts1 ts2)
                          end)
      | _,_ => []
  end.

Fixpoint compareTerms (t1: terms) (t2: terms) : list tpair :=
match t1, t2 with
      | t11::ts1, t21::ts2 =>
                        (match t11, t21 with
                        | Bterm bt1, Bterm bt2 => if (beq_baseTerm bt1 bt2)
                                                          then (compareTerms ts1 ts2)
                                                              else (pair t11 t21)::(compareTerms ts1 ts2)
                        | Func n1 bts1, Func n2 bts2 => if (beq_string n1 n2)
                                                           then (comparebaseTerms bts1 bts2)
                                                              else (pair t11 t21)::(compareTerms ts1 ts2)
                        | _, _ => (compareTerms ts1 ts2)
                        end)
      | _,_ => []
  end.


Fixpoint commonInPairs (p1:tpair) (p2:tpair) : bool :=
  match p1,p2 with
    | pair h1 t1, pair h2 t2 => orb (beq_term h1 h2) ( orb (beq_term h1 t2) (beq_term t1 t2))
    | _,_ => false
  end.

Fixpoint commonInList (ts1:terms) (ts2:terms) : bool :=
  match ts1 with
    | ts11::ts1s => orb (memberWith ts11 ts2 beq_term) (commonInList ts1s ts2)
    | [] => false
  end.

Fixpoint joinPairs (p1:tpair) (p2:tpair) : terms :=
  match p1,p2 with
    | pair h1 t1, pair h2 t2 => t2::(t1::(h2::(h1::[])))
    | _,_ => []
  end.

Fixpoint PairToList (p1:tpair) : terms :=
  match p1 with
    | pair h1 t1 => (t1::(h1::[]))
    | emptypair => []
  end.

Fixpoint uniqueTerms (tm: terms) : terms :=
  match tm with
    | t1::ts => if (memberWith t1 ts beq_term) then (uniqueTerms ts) else t1::(uniqueTerms ts)
    | [] => []
  end.

Fixpoint listIsASublist (t:terms) (lt:terms) : bool :=
  match t with
    | t1::ts => andb (memberWith t1 lt beq_term) (listIsASublist ts lt)
    | [] => true
  end.

Fixpoint listMembersAlreadyPresent (t:terms) (lt:list terms) : bool :=
  match lt with
    | lt1::lts => orb (listIsASublist t lt1) (listMembersAlreadyPresent t lts)
    | [] => false
  end.

Fixpoint finalListWithDuplicatesRemoved (t1:terms) (lt: list terms) : terms :=
 match lt with
   | lt1::lts => if (commonInList lt1 t1)
                        then (t1)
                        else (uniqueTerms (appendAny t1 (finalListWithDuplicatesRemoved t1 lts )))
   | [] => []
  end.

Fixpoint finalListsWithDuplicatesRemoved (lt: list terms) : list terms :=
  match lt with
    | t1::ts => (finalListWithDuplicatesRemoved t1 ts) :: (finalListsWithDuplicatesRemoved ts )
    | [] => []
  end.

Fixpoint collectStateFacts (rlst:ruleList) : facts :=
  match rlst with
  | rl1::rls => appendAny (appendAny (getStateFacts (premiseFacts rl1 )) (getStateFacts (conclFacts rl1 ))) (collectStateFacts rls)
  | [] => []
  end.

Fixpoint CheckTermsUSF (f1:fact) (fs:list fact) (t1:term) (t2:term) : Prop :=
match fs with
  | fs1::fst => match f1, fs1 with
                   | STATE n1 tm1, STATE n2 tm2 => if (beq_name n1 n2) then (TermsInSamePosition tm1 tm2 t1 t2)
                                                    else (CheckTermsUSF f1 fst t1 t2)
                   | _,_ => False
                 end
  | [] => False
end.

Fixpoint CheckFactsInUSF (fls:facts) (t1:term) (t2:term) : Prop :=
match fls with
  | f1::fs => (CheckTermsUSF f1 fs t1 t2) \/ (CheckFactsInUSF fs t1 t2)
  | [] => False
end.

Fixpoint CheckTermsUAF (f1:fact) (fs:list fact) (t1:term) (t2:term) : Prop :=
match fs with
  | fs1::fst => match f1, fs1 with
                   | STATE n1 tm1, STATE n2 tm2 => if (beq_name n1 n2) then (TermsInSamePosition tm1 tm2 t1 t2)
                                                    else (CheckTermsUAF f1 fst t1 t2)
                   | _,_ => False
                 end
  | [] => False
end.

Fixpoint CheckFactsInUAF (fls:facts) (t1:term) (t2:term) : Prop :=
match fls with
  | f1::fs => (CheckTermsUAF f1 fs t1 t2) \/ (CheckFactsInUAF fs t1 t2)
  | [] => False
end.


Fixpoint nameAndConstantDoNotAppear (n:name) (c:publicName) (fs:facts) : Prop :=
  match fs with
    | [] => True
    | fh::fst => match fh with
                  | STATE n2 ts => ((n=n2 /\ NotIn (Bterm (Name (Pub c))) ts) \/ n <> n2 )
                                  /\ (nameAndConstantDoNotAppear n c fst)
                  | _ => nameAndConstantDoNotAppear n c fst
                 end
  end.

Fixpoint termIsOnlyConstant (t:term) (n:name) (rs:(list rule)) : Prop :=
  match t with
    | Bterm (Name (Pub c)) => nameAndConstantDoNotAppear n c (allConclFacts rs)
    
    | _ => False
  end.

Fixpoint termIsFresh (t:term) (r:rule) : Prop :=
  match t with
    | Bterm (Var x) => member (FR_P (Var x)) (premiseFacts r)
    | _ => False
  end.

================================

3C: Well formedness definitions

====================================


Fixpoint wellFormedSetupPremiseFact (f:fact) : Prop :=
  match f with
  | IN t => True
  | OUT t => False
  | K t => False
  | STATE n t => True
  | FR_P n => match n with
                  | Var v => True
                  | _ => False
                 end
  end.

Definition wellFormedSetupPremiseFacts : facts -> Prop := trueForAll wellFormedSetupPremiseFact.

Fixpoint wellFormedConclusionFact (f:fact) : Prop :=
  match f with
  | IN t => False
  | OUT t => True
  | K t => False
  | STATE n t => True
  | FR_P fp => False
  end.

Fixpoint wellFormedConclusionFacts (fs: facts) : Prop :=
  (match fs with
  | f1::fss => wellFormedConclusionFact f1 /\ wellFormedConclusionFacts fss
  | [] => True
  end)
  /\ (oneOrNoOutput fs).

Fixpoint wellFormedSetupLabel (l:label) :=
  match l with
    | BasicLabel l => True
    | LoggedLabel a l => False
    | LoggedSIDLabel t a l => False
  end.

Fixpoint wellFormedSetupRule (r:rule) : Prop :=
  match r with
    | RuleSetup fs1 l fs2 => ((wellFormedSetupPremiseFacts fs1) /\ (wellFormedSetupLabel l)) /\ (wellFormedConclusionFacts fs2)
    | _ => False
  end.

Definition wellFormedSetupRules : ruleList -> Prop := trueForAll wellFormedSetupRule.


Fixpoint wellFormedProtoPremiseFact (f:fact) : Prop :=
  match f with
  | IN t => True
  | OUT t => False
  | K t => False
  | STATE n t => True
  | FR_P n => match n with
                  | Var v => True
                  | _ => False
                 end
  end.

Fixpoint wellFormedProtoPremiseFacts (fs: facts) : Prop :=
(match fs with
  | f1::fss => wellFormedProtoPremiseFact f1 /\ wellFormedProtoPremiseFacts fss
  | [] => True
  end)
  /\ (oneOrNoInput fs).

Fixpoint wellFormedProtoRule (r:rule) : Prop :=
  match r with
    | RuleProto fs1 l fs2 => (wellFormedProtoPremiseFacts fs1) /\ (wellFormedConclusionFacts fs2)
    | _ => False
  end.

Fixpoint inputsOutputsFromRule (r : rule) : facts :=
  appendAny (getInFactProtoRule r) (getOutFactProtoRule r).

Fixpoint inputsOutputsFromRuleList (rl : ruleList) : facts :=
  match rl with
     | r1::rs => appendAny (inputsOutputsFromRule r1) (inputsOutputsFromRuleList rs)
     | [] => []
  end.

Fixpoint alternateInputsOutputs (fs : facts) : Prop :=
  match fs with
     | f1::fs => match fs with
                      | fs1:: fss => match f1,fs1 with
                                       | IN _, IN _ => False
                                       | OUT _, OUT _ => False
                                       | _, _ => alternateInputsOutputs fs
                                     end
                      | [] => True
                  end
    | [] => True
  end.

Fixpoint wellFormedProtoRules (rl: ruleList) : Prop :=
  (match rl with
  | r1::rs => wellFormedProtoRule r1 /\ wellFormedProtoRules rs
  | [] => True
  end)
  /\ (alternateInputsOutputs (inputsOutputsFromRuleList rl)).

Fixpoint wellFormedRule (r:rule) : Prop :=
  match r with
    | RuleSetup fs1 l fs2 => wellFormedSetupRule r
    | RuleProto fs1 l fs2 => wellFormedProtoRule r
  end.

Fixpoint wellFormedAllowedSequences (allowSeq:list ruleList) : Prop :=
  match allowSeq with
  | al1::als => (wellFormedProtoRules al1) /\ (wellFormedAllowedSequences als)
  | [] => True
  end.

Fixpoint wellFormedLoggedLabel (l:label) :=
  match l with
    | BasicLabel l => False
    | LoggedLabel a l => True
    | LoggedSIDLabel t a l => False
  end.

Fixpoint wellFormedLoggedSIDLabel (l:label) :=
  match l with
    | BasicLabel l => False
    | LoggedLabel a l => False
    | LoggedSIDLabel t a l => True
  end.

Lemma wellFormedTail : forall h ts, wellFormedSetupRules (h::ts) -> wellFormedSetupRules(ts).


Fixpoint InputToOutputProtocolRule (r:rule) : Prop :=
 match r with
    | RuleProto fs1 l fs2 => (oneInput fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (oneOutput fs2)
    | _ => False
  end.

Fixpoint InputToStateProtocolRule (r:rule) : Prop :=
 match r with
    | RuleProto fs1 l fs2 => (oneInput fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (noOutputs fs2)
    | _ => False
  end.

Fixpoint StateToOutputProtocolRule (r:rule) : Prop :=
 match r with
    | RuleProto fs1 l fs2 => (noInputs fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (oneOutput fs2)
    | _ => False
  end.

Fixpoint StateToStateProtocolRule (r:rule) : Prop :=
 match r with
    | RuleProto fs1 l fs2 => (noInputs fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (noOutputs fs2)
    | _ => False
  end.

Fixpoint wellFormedProtoRuleInOutState (r:rule) : Prop :=
(InputToOutputProtocolRule r ) \/ (InputToStateProtocolRule r)
\/ (StateToOutputProtocolRule r) \/ (StateToStateProtocolRule r).

Fixpoint wellFormedProtoRuleNoInOut (rs:ruleList) : Prop :=
  match rs with
    | [] => True
    | r::rss => ((StateToOutputProtocolRule r) /\ (wellFormedProtoRuleFromInOut rss))
                  \/ ((StateToStateProtocolRule r) /\ (wellFormedProtoRuleNoInOut rss))
   end
with
  wellFormedProtoRuleFromInOut (rs:ruleList) : Prop :=
  match rs with
    | [] => True
    | r::rss => ((InputToStateProtocolRule r) /\ (wellFormedProtoRuleNoInOut rss))
                  \/ ((StateToStateProtocolRule r) /\ (wellFormedProtoRuleFromInOut rss))
                    \/ ((InputToOutputProtocolRule r) /\ (wellFormedProtoRuleFromInOut rss))
   end.

Definition wellformedRulesFromState (fs:facts) (rs:ruleList) : Prop :=
  (oneInputXorOutput fs /\ wellFormedProtoRuleFromInOut rs)
    \/ ( noInputOrOutput fs /\ wellFormedProtoRuleNoInOut rs).


Fixpoint InputToOutputSetupRule (r:rule) : Prop :=
 match r with
    | RuleSetup fs1 l fs2 => (oneInput fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (oneOutput fs2)
    | _ => False
  end.

Fixpoint InputToStateSetupRule (r:rule) : Prop :=
 match r with
    | RuleSetup fs1 l fs2 => (oneInput fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (noOutputs fs2)
    | _ => False
  end.

Fixpoint StateToOutputSetupRule (r:rule) : Prop :=
 match r with
    | RuleSetup fs1 l fs2 => (noInputs fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (oneOutput fs2)
    | _ => False
  end.

Fixpoint StateToStateSetupRule (r:rule) : Prop :=
 match r with
    | RuleSetup fs1 l fs2 => (noInputs fs1) /\ (noOutputs fs1) /\ (noInputs fs2) /\ (noOutputs fs2)
    | _ => False
  end.

Fixpoint wellFormedSetupRuleNoInOut (rs:ruleList) : Prop :=
  match rs with
    | [] => True
    | r::rss => ((StateToOutputSetupRule r) /\ (wellFormedSetupRuleFromInOut rss))
                  \/ ((StateToStateSetupRule r) /\ (wellFormedSetupRuleNoInOut rss))
   end
with
  wellFormedSetupRuleFromInOut (rs:ruleList) : Prop :=
  match rs with
    | [] => True
    | r::rss => ((InputToStateSetupRule r) /\ (wellFormedSetupRuleNoInOut rss))
                  \/ ((StateToOutputSetupRule r) /\ (wellFormedSetupRuleFromInOut rss))
                    \/ ((InputToOutputSetupRule r) /\ (wellFormedSetupRuleFromInOut rss))
   end.

Definition wellformedRulesFromStateSetup (fs:facts) (rs:ruleList) : Prop :=
  (oneInputXorOutput fs /\ wellFormedSetupRuleFromInOut rs)
    \/ ( noInputOrOutput fs /\ wellFormedSetupRuleNoInOut rs).

Fixpoint outputRule (r:rule) := StateToOutputProtocolRule r /\ InputToOutputProtocolRule r.
Fixpoint noOutputRule (r:rule) := StateToStateProtocolRule r /\ InputToStateProtocolRule r.
Fixpoint inputRule (r:rule) := InputToStateProtocolRule r /\ InputToOutputProtocolRule r.
Fixpoint noInputRule (r:rule) := StateToStateProtocolRule r /\ StateToOutputProtocolRule r.


Lemma noOutputsMeansNoOutputsInAnyFact: forall f fs, noOutputs (f::fs) -> (noOutput f /\ noOutputs fs).


Lemma oneOrNoOutputFactsInConclusion : forall f1 t f2,
   wellFormedProtoRule (RuleProto f1 t f2) -> oneOrNoOutput f2.

Lemma oneOrNoInputFactsInPremise : forall f1 t f2,
   wellFormedProtoRule (RuleProto f1 t f2) -> oneOrNoInput f1.

Lemma noOutputFactsInPremise : forall f1 l f2,
   wellFormedProtoRule (RuleProto f1 l f2) -> noOutputs f1.

Lemma noInputFactsInConclusion : forall f1 l f2,
   wellFormedProtoRule (RuleProto f1 l f2) -> noInputs f2.

=====================

4: Substitution

=====================
This section defines the mechanics of how Substitution works.
based on SOFTWARE FOUNDATIONS: https://softwarefoundations.cis.upenn.edu/lf-current/Maps.html https://softwarefoundations.cis.upenn.edu/lf-current/Imp.html

Definition substitution := variable -> name.

Definition substitutions := list substitution.

Definition null : name := Pub "null".

Definition subs_empty : substitution :=
  (fun _ => null).

Definition update (sigma : substitution)
                   (v : variable ) (n : name) :=
  fun x' => if beq_string v x' then n else sigma x'.

Notation "v '!->' n" := (update subs_empty v n) (at level 100).
Notation "v '!->' n ';' sigma" := (update sigma v n)
                              (at level 100, n at next level, right associativity).

Definition compose (sigma1 : substitution) (sigma2 : substitution) : variable -> name :=
  fun v => if (beq_name (sigma1 v) null) then (sigma2 v) else (sigma1 v).

Definition substsAgree (sigma1 : substitution) (sigma2 : substitution) : Prop :=
  forall x, sigma1 x = null \/ sigma2 x = null \/ sigma1 x=sigma2 x.

Lemma agreeSubstComposeOrder : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall x, compose sigma1 sigma2 x = compose sigma2 sigma1 x.

Definition exampleSubs := "ltkA" !-> Fresh_S "ltkA"; subs_empty.

Fixpoint applySubBaseTerm (sigma:substitution) (t:baseTerm) : baseTerm :=
  match t with
  | Var v => if (beq_name (sigma v) null) then (Var v) else Name (sigma v)
  | Name n => Name n
  end.

Definition applySubBaseTerms (sigma:substitution) (ts:baseTerms) : baseTerms
     := map (applySubBaseTerm sigma) ts.

Fixpoint applySubTerm (sigma:substitution) (t:term) : term :=
  match t with
  | Func f bts => Func f (applySubBaseTerms sigma bts)
  | Bterm bt => Bterm (applySubBaseTerm sigma bt)
  end.

Definition applySubTerms : substitution -> terms -> terms
     := fun sigma => map (applySubTerm sigma).

Fixpoint applySubActionLabel (sigma:substitution) (lb:actionLabel) : actionLabel :=
  match lb with
   | ActLabel n ts => ActLabel n (applySubTerms sigma ts)
  end.

Definition applySubLabel (sigma:substitution) (lb:label) : label :=
  match lb with
    | BasicLabel ll => BasicLabel (map ( applySubActionLabel sigma) ll)
    | LoggedLabel lg ll => LoggedLabel (applySubActionLabel sigma lg) (map (applySubActionLabel sigma) ll)
    | LoggedSIDLabel t lg ll => LoggedSIDLabel (applySubBaseTerm sigma t)(applySubActionLabel sigma lg) (map (applySubActionLabel sigma) ll)
  end.

Fixpoint applySubFact (sigma:substitution) (f:fact) : fact :=
match f with
  | IN terms => IN (applySubTerms sigma terms)
  | OUT terms => OUT (applySubTerms sigma terms)
  | K terms => K (applySubTerms sigma terms)
  | STATE name terms => STATE name (applySubTerms sigma terms)
  | FR_P freshName => FR_P (applySubBaseTerm sigma freshName)
  end.

Definition applySubFacts : substitution -> facts -> facts
     := fun sigma => map (applySubFact sigma).

Fixpoint applySubRule (sigma:substitution) (r:rule) : rule :=
match r with
  | RuleSetup f1 l f2 => RuleSetup (applySubFacts sigma f1) (applySubLabel sigma l) (applySubFacts sigma f2)
  | RuleProto f1 l f2 => RuleProto (applySubFacts sigma f1) (applySubLabel sigma l) (applySubFacts sigma f2)
end.

Definition applySubRuleList : substitution -> ruleList -> ruleList := fun sigma => map (applySubRule sigma).

Definition applySubRuleLists : substitution -> list ruleList -> list ruleList := fun sigma => map (applySubRuleList sigma).

Definition applySubTrace : substitution -> trace -> trace := fun sigma => map (applySubLabel sigma).

Definition applySubTraces : substitution -> list trace -> list trace := fun sigma => map (applySubTrace sigma).

Lemma agreeSubstComposeOrderBaseTerm : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall bt, applySubBaseTerm (compose sigma1 sigma2) bt
                                            = applySubBaseTerm (compose sigma2 sigma1) bt.

Lemma agreeSubstComposeOrderBaseTerms : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall bt, applySubBaseTerms (compose sigma1 sigma2) bt
                                            = applySubBaseTerms (compose sigma2 sigma1) bt.

Lemma agreeSubstComposeOrderTerm : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall tm, applySubTerm (compose sigma1 sigma2) tm
                                            = applySubTerm (compose sigma2 sigma1) tm.

Lemma agreeSubstComposeOrderTerms : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall tm, applySubTerms (compose sigma1 sigma2) tm
                                            = applySubTerms (compose sigma2 sigma1) tm.

Lemma agreeSubstComposeOrderActionLabel : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall al, applySubActionLabel (compose sigma1 sigma2) al
                                            = applySubActionLabel (compose sigma2 sigma1) al.

Lemma agreeSubstComposeOrderLabel : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall l, applySubLabel (compose sigma1 sigma2) l
                                            = applySubLabel (compose sigma2 sigma1) l.

Lemma agreeSubstComposeOrderTrace : forall sigma1 sigma2,
  substsAgree sigma1 sigma2 -> forall t, applySubTrace (compose sigma1 sigma2) t
                                            = applySubTrace (compose sigma2 sigma1) t.


===================================

5: Ground terms and rule instances

===================================


Ground Defs, these might be better as Props, rather than bools I'm not sure at this point, we can always change these to Props later

Fixpoint groundBaseTerm (ts:baseTerm) : Prop :=
  match ts with
    | Var v => False
    | _ => True
  end.

Definition groundBaseTerms : baseTerms -> Prop := trueForAll groundBaseTerm.

Fixpoint groundTerm (t:term) : Prop :=
  match t with
    | Func f ts => groundBaseTerms ts
    | Bterm (Name (Pub n)) => True
    | Bterm (Name (Fresh_S n)) => True
    | Bterm (Name (Fresh_P n)) => True
    | _ => False
  end.

Fixpoint groundTerms (ts:terms) : Prop :=
  match ts with
    | t::ts => groundTerm t /\ groundTerms ts
    | [] => True
  end.

Fixpoint groundFact (f:fact) : Prop :=
 match f with
  | IN ts => groundTerms ts
  | OUT ts => groundTerms ts
  | K ts => groundTerms ts
  | STATE n ts => groundTerms ts
  | FR_P fn => True
 end.

Fixpoint groundFacts (fs:facts) : Prop :=
  match fs with
    | f::fs => groundFact f /\ groundFacts fs
    | [] => True
  end.

Definition groundActionLabel (al:actionLabel) : Prop :=
  match al with
    | ActLabel n ts => groundTerms ts
  end.

Fixpoint groundBasicLabel (lb:list actionLabel) : Prop :=
  match lb with
    | al::als => groundActionLabel al /\ groundBasicLabel als
    | [] => True
  end.

Definition groundLoggedLabel (lg:actionLabel) (lb:list actionLabel) : Prop :=
   groundActionLabel lg /\ groundBasicLabel lb.

Definition groundLoggedSIDLabel (t:baseTerm) (lg:actionLabel) (lb:list actionLabel) : Prop :=
   groundBaseTerm t /\ groundActionLabel lg /\ groundBasicLabel lb.

Definition groundLabel (lb:label) : Prop :=
  match lb with
    | BasicLabel ls => groundBasicLabel ls
    | LoggedLabel lg ls => groundLoggedLabel lg ls
    | LoggedSIDLabel t lg ls => groundLoggedSIDLabel t lg ls
  end.

Definition groundRule (r:rule) : Prop :=
  match r with
    | RuleProto f1 l f2 => groundFacts f1 /\ groundFacts f2 /\ groundLabel l
    | RuleSetup f1 l f2 => groundFacts f1 /\ groundFacts f2 /\ groundLabel l
  end.


Inductive ginst : rule -> rule -> Prop :=
  | Ginst : forall r1 r2, (exists sigma, (applySubRule sigma r2) = r1) /\ (groundRule r1) -> ginst r1 r2.

Inductive ginsts : rule -> ruleList -> Prop :=
  | GinstHead : forall r1 r2 rs, (ginst r1 r2) -> ginsts r1 (r2::rs)
  | GinstTail : forall r1 r2 rs, (ginsts r1 rs) -> ginsts r1 (r2::rs).


Inductive ginstWithSigma : rule -> substitution -> rule -> Prop :=
  | GinstSigma : forall r1 r2 sigma, (applySubRule sigma r2) = r1 /\ groundRule r1 -> ginstWithSigma r1 sigma r2.

Inductive ginstsWithSigma : rule -> substitution -> ruleList -> Prop :=
  | GinstHeadSigma : forall r1 r2 rs sigma,
                                  (ginstWithSigma r1 sigma r2) -> ginstsWithSigma r1 sigma (r2::rs)
  | GinstTailSigma : forall r1 r2 rs sigma,
                                  (ginstsWithSigma r1 sigma rs) -> ginstsWithSigma r1 sigma (r2::rs).

Lemma composeSubstBaseTerm : forall bt (sigma1:substitution) (sigma2:substitution),
        groundBaseTerm (applySubBaseTerm sigma1 bt)
              -> groundBaseTerm (applySubBaseTerm (compose sigma1 sigma2) bt).

Lemma composeSubstBaseTerms : forall bt (sigma1:substitution) (sigma2:substitution),
        groundBaseTerms (applySubBaseTerms sigma1 bt)
              -> groundBaseTerms (applySubBaseTerms (compose sigma1 sigma2) bt).

Lemma composeSubstGroundTerm : forall tm (sigma1:substitution) (sigma2:substitution),
        groundTerm (applySubTerm sigma1 tm)
              -> groundTerm (applySubTerm (compose sigma1 sigma2) tm).

Lemma composeSubstGroundTerms : forall tms (sigma1:substitution) (sigma2:substitution),
        groundTerms (applySubTerms sigma1 tms)
              -> groundTerms (applySubTerms (compose sigma1 sigma2) tms).

Lemma composeSubstGroundAL : forall al (sigma1:substitution) (sigma2:substitution),
        groundActionLabel (applySubActionLabel sigma1 al)
              -> groundActionLabel (applySubActionLabel (compose sigma1 sigma2) al).

Lemma composeSubstGroundBasicLabel : forall l (sigma1:substitution) (sigma2:substitution),
        groundBasicLabel (map ( applySubActionLabel sigma1) l)
              -> groundBasicLabel (map (applySubActionLabel (compose sigma1 sigma2)) l).

Lemma composeSubstGroundLoggedLabel : forall al ls (sigma1:substitution) (sigma2:substitution),
        groundLoggedLabel
               (applySubActionLabel sigma1 al)
               (map (applySubActionLabel sigma1) ls)
              
            -> groundLoggedLabel
               (applySubActionLabel (compose sigma1 sigma2) al)
               (map (applySubActionLabel (compose sigma1 sigma2)) ls).

Lemma composeSubstGroundLoggedSIDLabel : forall al ls t (sigma1:substitution) (sigma2:substitution),
        groundLoggedSIDLabel
               (applySubBaseTerm sigma1 t)
               (applySubActionLabel sigma1 al)
               (map (applySubActionLabel sigma1) ls)
              
            -> groundLoggedSIDLabel
               (applySubBaseTerm (compose sigma1 sigma2) t)
               (applySubActionLabel (compose sigma1 sigma2) al)
               (map (applySubActionLabel (compose sigma1 sigma2)) ls).

Lemma composeSubstGroundLabel : forall l (sigma1:substitution) (sigma2:substitution),
        groundLabel (applySubLabel sigma1 l)
              -> groundLabel (applySubLabel (compose sigma1 sigma2) l).

====================

6: Tamarin Reduction

=======================



"reduceWithRule r f1 l f2" means that the rule "r" can match the facts "f1" and produce the facts "f2" with the label "label"

Inductive reduceWithGroundRule : rule -> facts -> label -> facts -> Prop :=
   | R_match : forall r s1, (subList (premiseFacts r) s1) ->
                       reduceWithGroundRule r s1 (labelR r)
                         (appendAny (conclFacts r) (removeFacts (premiseFacts r) s1)).

Definition reduceWithRule (r1:rule) (f:facts) (l:label) (f2:facts) : Prop :=
    exists r2, (ginst r2 r1) /\ reduceWithGroundRule r2 f l f2.

Definition reduceWithRules (rs:ruleList) (f:facts) (l:label) (f2:facts) : Prop :=
    exists r2, (ginsts r2 rs) /\ reduceWithGroundRule r2 f l f2.

"reduceWithRuleSigma r f1 l f2" means that the rule "r" can match the facts "f1" and produce the facts "f2" with the label "label"

Definition reduceWithRuleSigma (r1:rule) (sigma:substitution) (f:facts) (l:label) (f2:facts) : Prop :=
    exists r2, (ginstWithSigma r2 sigma r1) /\ reduceWithGroundRule r2 f l f2.

Definition reduceWithRulesSigma (rs:ruleList) (sigma:substitution) (f:facts) (l:label) (f2:facts) : Prop :=
    exists r2, (ginstsWithSigma r2 sigma rs) /\ reduceWithGroundRule r2 f l f2.

Definition freshRuleS (n:freshNameSetup) : rule := (RuleSetup [] emptyLabel [FR_P (Name (Fresh_S n))]).

Definition freshRuleP (n:freshNameProto) : rule := (RuleProto [] emptyLabel [FR_P (Name (Fresh_P n))]).


Inductive run : ruleList -> facts -> trace -> facts -> Prop :=
   | Run_Stop : forall rl f1, run rl f1 [] f1
   | Run_Step : forall rl f1 t f2 f3 l, (reduceWithRules rl f1 l f2)
                        -> (run rl f2 t f3) -> run rl f1 (l::t) f3
   | Run_Step_Silent : forall rl f1 t f2 f3, (reduceWithRules rl f1 emptyLabel f2)
                        -> (run rl f2 t f3) -> run rl f1 t f3
   | Run_FreshStepP : forall rl f1 t f2 f3 fn, (reduceWithRule (freshRuleP fn) f1 emptyLabel f2)
                        -> (run rl f2 t f3) -> run rl f1 t f3.


Inductive runSigma : ruleList -> substitutions -> facts -> trace -> facts -> Prop :=
   | SigmaRun_Stop : forall rl f1, runSigma rl [] f1 [] f1
   | SigmaRun_Step : forall rl sigmaPrev f1 t f2 f3 l sigmaNow, (reduceWithRulesSigma rl sigmaNow f1 l f2)
                        -> (runSigma rl sigmaPrev f2 t f3) -> runSigma rl (sigmaNow::sigmaPrev) f1 (l::t) f3
   | SigmaRun_Step_Silent : forall rl sigmaPrev f1 t f2 f3 sigmaNow, (reduceWithRulesSigma rl sigmaNow f1 emptyLabel f2)
                        -> (runSigma rl sigmaPrev f2 t f3) -> runSigma rl (sigmaNow::sigmaPrev) f1 t f3
   | SigmaRun_FreshStepP : forall rl f1 t f2 f3 fn sigmaPrev sigmaNow, (reduceWithRuleSigma (freshRuleP fn) sigmaNow f1 emptyLabel f2)
                        -> (runSigma rl sigmaPrev f2 t f3) -> runSigma rl (sigmaNow::sigmaPrev) f1 t f3.
Some useful Lemmas about traces

Lemma reduceWithFirstRule : forall r rl f1 f2 l, reduceWithRule r f1 l f2 -> reduceWithRules (r::rl) f1 l f2.

Lemma reduceWithSecondRule : forall r1 r2 rl f1 f2 l, reduceWithRule r2 f1 l f2 -> reduceWithRules (r1::r2::rl) f1 l f2.

Lemma FreshRulePIsAGroundRule : forall fn, groundRule (freshRuleP fn).

Lemma ProtoFreshNameStep (fn:freshNameProto) :
           forall fs, reduceWithRule (freshRuleP fn) fs emptyLabel ((FR_P (Name (Fresh_P fn)))::fs).

Lemma FreshRuleSIsAGroundRule : forall fn, groundRule (freshRuleS fn).


Lemma SetupFreshNameStep (fn:freshNameSetup) :
           forall fs, reduceWithRule (freshRuleP fn) fs emptyLabel ((FR_P (Name (Fresh_P fn)))::fs).

Lemma ProtoFreshNameStepEmpty (fn:freshNameProto) :
           reduceWithRule (freshRuleP fn) [] emptyLabel [ FR_P (Name (Fresh_P fn)) ].

Lemma SetupFreshNameStepEmpty (fn:freshNameSetup) :
           reduceWithRule (freshRuleP fn) [] emptyLabel [ FR_P (Name (Fresh_P fn)) ].

Lemma reduceRulesLessImpliesMore : forall r rl f1 l f2, reduceWithRules rl f1 l f2 -> reduceWithRules (r::rl) f1 l f2.

Lemma runRulesLessImpliesMore : forall r rl f1 t f2, run rl f1 t f2 -> run (r::rl) f1 t f2.

Lemma runTransitive : forall rl s1 s2 s3 l1 l2,
     run rl s1 l1 s2 /\ run rl s2 l2 s3 -> run rl s1 (appendAny l1 l2) s3.

The same Lemmas with substitution
Lemma reduceWithFirstRuleSigma : forall r rl f1 f2 l sigma, reduceWithRuleSigma r sigma f1 l f2
                      -> reduceWithRulesSigma (r::rl) sigma f1 l f2.

Lemma reduceWithSecondRuleSigma : forall r1 r2 rl f1 f2 l sigma, reduceWithRuleSigma r2 sigma f1 l f2
                          -> reduceWithRulesSigma (r1::r2::rl) sigma f1 l f2.

Lemma ProtoFreshNameStepSigma (fn:freshNameProto) :
           forall fs sigma, reduceWithRuleSigma (freshRuleP fn) sigma fs emptyLabel ((FR_P (Name (Fresh_P fn)))::fs).

Lemma SetupFreshNameStepSigma (fn:freshNameSetup) :
           forall fs sigma, reduceWithRuleSigma (freshRuleP fn) sigma fs emptyLabel ((FR_P (Name (Fresh_P fn)))::fs).

Lemma ProtoFreshNameStepEmptySigma (fn:freshNameProto) :
           reduceWithRuleSigma (freshRuleP fn) subs_empty [] emptyLabel [ FR_P (Name (Fresh_P fn)) ].

Lemma SetupFreshNameStepEmptySigma (fn:freshNameSetup) :
           reduceWithRuleSigma (freshRuleP fn) subs_empty [] emptyLabel [ FR_P (Name (Fresh_P fn)) ].

Lemma reduceRulesLessImpliesMoreSigma : forall r rl f1 l f2 sigma, reduceWithRulesSigma rl sigma f1 l f2
           -> reduceWithRulesSigma (r::rl) sigma f1 l f2.


Lemma runRulesLessImpliesMoreSigma : forall r rl f1 t f2 sigmas, runSigma rl sigmas f1 t f2
                    -> runSigma (r::rl) sigmas f1 t f2.

Lemma runTransitiveSigma : forall rl f1 f2 f3 l1 l2 sigmas1 sigmas2,
     runSigma rl sigmas1 f1 l1 f2 /\ runSigma rl sigmas2 f2 l2 f3 -> runSigma rl (appendAny sigmas1 sigmas2) f1 (appendAny l1 l2) f3.

=====================

7: Example

=====================

Definition varX : term := Bterm (Var "x") .
Definition varY : term := Bterm (Var "Y") .
Definition AttackerReceive (ts:terms) : rule := RuleProto [ OUT ts ] emptyLabel [ K ts ].
Definition AttackerReceive1 : rule := RuleProto [ OUT [varX] ] emptyLabel [ K [varX] ].
Definition AttackerReceive2 : rule := RuleProto [ OUT [varX;varY] ] emptyLabel [ K [varX]; K [varY] ].
Definition AttackerSend (ts:terms) : rule := RuleProto [ K ts ] emptyLabel [ IN ts ].
Definition AttackerSend1 : rule := RuleProto [ K [varX] ] emptyLabel [ K [varX] ].
Definition AttackerSend2 : rule := RuleProto [ K [varX]; K [varY] ] emptyLabel [ IN [varX; varY] ].
Definition LtkFact : name := Pub "LtkFact".
Definition ltkA_var : baseTerm := (Var "ltkA").
Definition ltkB_var : baseTerm := (Var "ltkB").
Definition PkFact : name := Pub "PkFact".
Definition PkName : string := "Pkname".
Definition Pk : string := "Pkname".
Definition A : term := Bterm (Name (Pub "A")).
Definition B : term := Bterm (Name (Pub "B")).
Definition C : term := Bterm (Name (Pub "C")).



Definition registerPKruleA : rule := RuleSetup [ FR_P ltkA_var ] emptyLabel
                                [STATE LtkFact [A; (Bterm ltkA_var)]; STATE PkFact [A; Func PkName [ltkA_var]];
                                       OUT [Func PkName [ltkA_var]] ].

Definition registerPKruleB : rule := RuleSetup [ FR_P ltkB_var ] emptyLabel
                                [STATE LtkFact [B; (Bterm ltkB_var)]; STATE PkFact [B; Func PkName [ltkB_var]];
                                          OUT [Func PkName [ltkB_var]] ].

Definition St_I_1 : name := Pub "St_I_1".

Definition ni : baseTerm := (Var "ni").


Definition m1 : term := Func "aenc" [ ni; (Name (Pub "A"))].

Definition I_1_A_to_B : rule := RuleProto [(FR_P ni); STATE PkFact [B; Func PkName [ltkB_var]]]
(BasicLabel [ ActLabel (Pub "Out") [m1] ])
                                      [OUT [m1]; STATE St_I_1 [A; B; (Bterm ni)]; STATE PkFact [B; Func PkName [ltkB_var]]].


Definition ProtocolRules : ruleList := [registerPKruleA; registerPKruleB; I_1_A_to_B].

Lemma protocolRun1Step : run ProtocolRules [] [] [FR_P (Name (Fresh_P "ltkA")) ].

Lemma protocolRun2Step : run ProtocolRules [] []
              [FR_P (Name (Fresh_P "ltkB")); FR_P (Name (Fresh_P "ltkA"))].


Definition mapLtkAvarToName := "ltkA" !-> Fresh_P "ltkA"; subs_empty.

Definition registerPKruleAground : rule := RuleSetup [ FR_P (Name (Fresh_P "ltkA")) ]
                                emptyLabel
                                [STATE LtkFact [A; Bterm (Name (Fresh_P "ltkA"))];
                                 STATE PkFact [A; Func PkName [(Name (Fresh_P "ltkA"))]];
                                 OUT [Func PkName [(Name (Fresh_P "ltkA"))]] ].

Lemma protocolRun2to3Step : run ProtocolRules
              [FR_P (Name (Fresh_P "ltkB")); FR_P (Name (Fresh_P "ltkA"))]
              []
              [STATE LtkFact [A; (Bterm (Name (Fresh_P "ltkA")))];
               STATE PkFact [A; Func PkName [(Name (Fresh_P "ltkA"))]];
               OUT [Func PkName [(Name (Fresh_P "ltkA"))]];
               FR_P (Name (Fresh_P "ltkB"))].

Lemma protocolRunToStop3: run ProtocolRules [] []
              [STATE LtkFact [A; (Bterm (Name (Fresh_P "ltkA")))];
               STATE PkFact [A; Func PkName [(Name (Fresh_P "ltkA"))]];
               OUT [Func PkName [(Name (Fresh_P "ltkA"))]];
               FR_P (Name (Fresh_P "ltkB"))].


=====================

8: Definitions from Chapter 5 of the thesis

=====================



Inductive runInOrder : ruleList -> ruleList -> substitution -> facts -> trace -> facts -> Prop :=
     | Run_Stop_O : forall f1 rls sigma, runInOrder [] rls sigma f1 [] f1
     | Run_Step_O : forall r rls rlp sigma f1 t f2 f3 l, (reduceWithGroundRule (applySubRule sigma r) f1 l f2)
                          -> (runInOrder rlp rls sigma f2 t f3) -> runInOrder (r::rlp) rls sigma f1 (l::t) f3
     | Run_Step_Silent_O : forall r rls rlp sigma f1 t f2 f3, (reduceWithGroundRule (applySubRule sigma r) f1 emptyLabel f2)
                          -> (runInOrder rlp rls sigma f2 t f3) -> runInOrder (r::rlp) rls sigma f1 t f3
     | Run_FreshStep_O : forall rls rlp sigma f1 t f2 f3 fn, (reduceWithRule (freshRuleP fn) f1 emptyLabel f2)
                         -> (runInOrder rlp rls sigma f2 t f3) -> runInOrder rlp rls sigma f1 t f3
     | Run_Step_S : forall rls rlp sigma f1 l f2 f3 t, (reduceWithRules rls f1 l f2)
                         -> (runInOrder rlp rls sigma f2 t f3) -> runInOrder rlp rls sigma f1 (l::t) f3
     | Run_Step_Silent_S : forall rls rlp sigma f1 t f2 f3, (reduceWithRules rls f1 emptyLabel f2)
                         -> (runInOrder rlp rls sigma f2 t f3) -> runInOrder rlp rls sigma f1 t f3
     | Run_FreshStep_S : forall rls rlp sigma f1 t f2 f3 fn, (reduceWithRule (freshRuleS fn) f1 emptyLabel f2)
                         -> (runInOrder rlp rls sigma f2 t f3) -> runInOrder rlp rls sigma f1 t f3
     | Run_Comm_O : forall rls rlp sigma f1 t f2 trm, (subList [OUT trm] f1) ->
                            runInOrder rlp rls sigma ((IN trm)::(removeFacts [OUT trm] f1)) t f2 ->
                               runInOrder rlp rls sigma f1 t f2.



Inductive runInOrderSigmaProtocol : ruleList -> substitutions -> facts -> trace -> facts -> Prop :=
     | Sigma_Run_Stop_P : forall f1 sigma, runInOrderSigmaProtocol [] sigma f1 [] f1

     | Sigma_Run_Step_P : forall r rlp sigmaNow sigmaPrev f1 t f2 f3 l,
                                  groundRule (applySubRule sigmaNow r)
                                    -> reduceWithGroundRule (applySubRule sigmaNow r) f1 l f2
                                      -> (runInOrderSigmaProtocol rlp sigmaPrev f2 t f3)
                                        -> runInOrderSigmaProtocol (r::rlp) (sigmaNow::sigmaPrev) f1 (l::t) f3

     | Sigma_Run_Step_Silent_P : forall r rlp sigmaNow sigmaPrev f1 t f2 f3,
                                    groundRule (applySubRule sigmaNow r)
                                      -> reduceWithGroundRule (applySubRule sigmaNow r) f1 emptyLabel f2
                                        -> (runInOrderSigmaProtocol rlp sigmaPrev f2 t f3)
                                          -> runInOrderSigmaProtocol (r::rlp) (sigmaNow::sigmaPrev)f1 t f3

     | Sigma_Run_Comm_P : forall rlp sigmaPrev f1 t f2 trm, (subList [OUT trm] f1) ->
                            runInOrderSigmaProtocol rlp sigmaPrev ((IN trm)::(removeFacts [OUT trm] f1)) t f2 ->
                               runInOrderSigmaProtocol rlp sigmaPrev f1 t f2.


Fixpoint runInOrderSigma (rlProto:ruleList) (rlSetup:ruleList) (sigmaAll:substitutions) (fsInitial:facts) (tr:trace) (fsFinal:facts) : Prop :=
forall fsMid trSetup trProto,
  run rlSetup fsInitial trSetup fsMid
  /\ runInOrderSigmaProtocol rlProto sigmaAll (removeOutInfromFactList fsMid) tr fsFinal
        /\ (eq_trace tr (appendAny trSetup trProto)).

Lemma noOutputsMeansNoOutputs: forall factslist trm, noOutputs factslist -> member (OUT trm) factslist -> False.

Lemma singleOutputEquals : forall trm1 trm2 factsList,
  (member (OUT trm1) factsList) -> (member (OUT trm2) factsList)
       -> oneOutput factsList -> trm1 = trm2.


Lemma memberOneOrOther : forall {T:Type} (e:T) (l1:list T) (l2:list T),
  member e (appendAny l1 l2) -> not (member e l2) -> (member e l1).


Lemma memberAfterRemoveOne: forall fac1 fac2 facs,
  member fac1 (removeFact fac2 facs) -> member fac1 facs.

Lemma memberAfterRemove : forall fac facts1 facts2, member fac (removeFacts facts1 facts2) -> member fac facts2.

Lemma memberSigmaEquals : forall (fac:fact) (sigma:substitution) (factlist:list fact),
  member fac (applySubFacts sigma factlist)
    -> exists (facTemplate:fact), fac = applySubFact sigma facTemplate
                                         /\ member facTemplate factlist.

Lemma factFromReduction : forall sigma redRule f1 f2 l fac,
   reduceWithRuleSigma redRule sigma f1 l f2
     -> member fac f2 -> not (member fac f1)
       -> exists facTemplate, ( member facTemplate (conclFacts redRule)
             /\ applySubFact sigma facTemplate = fac).

Rajiv : Added these lemmas
Lemma noOutputsMeansNoOutputsInFactOrFacts: forall f fs t1,
          noOutputs (f::fs) -> not (eq_fact (OUT t1) f) /\ noOutputs fs.

Lemma emptyRuleCantMakeOutput : forall sigma f1 label f2 ,
         reduceWithRuleSigma (RuleProto [] label []) sigma f1 label f2
               -> noOutputs f1 -> noOutputs f2.


Lemma sigmaNoInputFacts: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> noInputs f2 -> noInputs f1.

Lemma sigmaNoInputFacts2: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> noInputs f1 -> noInputs f2.

Lemma sigmaNoOutputFacts: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> noOutputs f1 -> noOutputs f2.

Lemma sigmaNoOutputFacts2: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> noOutputs f2 -> noOutputs f1.

Lemma sigmaNoInputOrOutputFacts: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> noInputOrOutput f1 -> noInputOrOutput f2.

Lemma sigmaOneInputXorOutputFacts: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> oneInputXorOutput f1 -> oneInputXorOutput f2.


Axiom sigmaoneOutputXorInputIsFacts: forall f1 f2 sigma trms,
 applySubFacts sigma f1 = f2
              -> oneOutputXorInputIs f1 trms -> oneOutputXorInputIs f2 trms.


Lemma sigmaOneInputFact: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> oneInput f2 -> oneInput f1.

Lemma sigmaOneInputFact2: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> oneInput f1 -> oneInput f2.

Lemma sigmaOneOutputFact: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> oneOutput f1 -> oneOutput f2.

Axiom sigmaoneInputXorOutputFact: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> oneInputXorOutput f1 -> oneInputXorOutput f2.

Lemma sigmaMoreThanOneOutputFact: forall f1 f2 sigma,
 applySubFacts sigma f1 = f2 -> moreThanOneOutput f1 -> moreThanOneOutput f2.

Lemma ginstWithSigmaNoInputP: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> noInputs f3 -> noInputs f1.

Lemma ginstWithSigmaOneInputP: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> oneInput f3 -> oneInput f1.

Lemma ginstWithSigmaNoOutputC: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> noOutputs f4 -> noOutputs f2.

Lemma ginstWithSigmaNoOutputP: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> noOutputs f3 -> noOutputs f1.

Lemma ginstWithSigmaOneOutputC: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> oneOutput f4 -> oneOutput f2.

Lemma ginstWithSigmaMoreThanOneOutputC: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> moreThanOneOutput f4 -> moreThanOneOutput f2.

Lemma ginstWithSigmaNoInputOutputC: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> noInputOrOutput f4 -> noInputOrOutput f2.

Lemma ginstWithSigmaNoInputOutputP: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> noInputOrOutput f3 -> noInputOrOutput f1.

Lemma ginstWithSigmaOneInputXorOutputC: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> oneInputXorOutput f4 -> oneInputXorOutput f2.

Lemma ginstWithSigmaOneInputXorOutputP: forall f1 f2 f3 f4 l1 l2 sigma,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> oneInputXorOutput f3 -> oneInputXorOutput f1.

Lemma ginstWithSigmaoneOutputXorInputIsC : forall f1 f2 f3 f4 l1 l2 sigma trms,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> oneOutputXorInputIs f4 trms -> oneOutputXorInputIs f2 trms.

Lemma ginstWithSigmaoneOutputXorInputIsP : forall f1 f2 f3 f4 l1 l2 sigma trms,
  ginstWithSigma (RuleProto f1 l1 f2) sigma (RuleProto f3 l2 f4)
   -> oneOutputXorInputIs f3 trms -> oneOutputXorInputIs f1 trms.

Lemma noOutputsTail : forall f fs,
  noOutputs (f::fs) -> noOutputs fs.

Lemma noInputsTail : forall f fs,
  noInputs (f::fs) -> noInputs fs.

Lemma noInputOrOutputTail : forall f fs,
  noInputOrOutput (f::fs) -> noInputOrOutput fs.

Lemma noOutputsAcrossRemoveFact : forall f fs,
  noOutputs fs -> noOutputs (removeFact f fs).

Lemma noOutputsAcrossRemove : forall f1 f2,
  noOutputs f2 -> noOutputs (removeFacts f1 f2).

Axiom oneOutputsAcrossRemove : forall f1 f2,
  oneOutput f2 -> noOutputs f1 -> oneOutput (removeFacts f1 f2).

Axiom oneInputXorOutputAcrossRemove : forall f1 f2,
  oneInputXorOutput f2 -> noInputOrOutput f1 -> oneInputXorOutput (removeFacts f1 f2).

Lemma noInputsAcrossRemoveFact : forall f fs,
  noInputs fs -> noInputs (removeFact f fs).

Lemma noInputOrOutputAcrossRemoveFact : forall f fs,
  noInputOrOutput fs -> noInputOrOutput (removeFact f fs).

Lemma noInputsAcrossRemove : forall f1 f2,
  noInputs f2 -> noInputs (removeFacts f1 f2).

Lemma noInputOrOutputAcrossRemove : forall f1 f2,
  noInputOrOutput f2 -> noInputOrOutput (removeFacts f1 f2).

Lemma AppendNoOutputs : forall f1 f2,
  noOutputs f1 -> noOutputs f2 -> noOutputs (appendAny f1 f2).

Lemma AppendNoInputs : forall f1 f2,
  noInputs f1 -> noInputs f2 -> noInputs (appendAny f1 f2).

Lemma AppendSingleOutput : forall f1 f2,
  oneOutput f1 -> noOutputs f2 -> oneOutput (appendAny f1 f2).

Lemma AppendSingleOutput2 : forall f1 f2,
  oneOutput f2 -> noOutputs f1 -> oneOutput (appendAny f1 f2).

Lemma AppendMinOneOutput : forall f1 f2,
  minOneOutput f1 -> noOutputs f2 -> minOneOutput (appendAny f1 f2).

Lemma AppendMoreThanOneOutput : forall f1 f2,
  moreThanOneOutput f1 -> noOutputs f2 -> moreThanOneOutput (appendAny f1 f2).

Lemma AppendSingleInput : forall f1 f2,
  oneInput f1 -> noInputs f2 -> oneInput (appendAny f1 f2).

Lemma AppendNoInputOrOutput : forall f1 f2,
  noInputOrOutput f1 -> noInputOrOutput f2 -> noInputOrOutput (appendAny f1 f2).

Lemma SplitNoInputOrOutput : forall f1 f2,
  noInputOrOutput (appendAny f1 f2) -> noInputOrOutput f1 -> noInputOrOutput f2.

Lemma noInputOrOutputMeansNoInputsAndNoOutputs: forall fs,
  noInputOrOutput fs -> noInputs fs -> noOutputs fs.

Lemma noInputOrOutputMeansNoInputsAndNoOutputs2: forall fs,
  noInputs fs -> noOutputs fs -> noInputOrOutput fs.

Lemma noInputOrOutputMeansNoInputsAndNoOutputs3: forall fs,
  noInputs fs /\ noOutputs fs -> noInputOrOutput fs.

Lemma noInputOrOutputMeansNoInputsAndNoOutputs4: forall fs,
  noInputOrOutput fs -> noInputs fs /\ noOutputs fs.

Lemma AppendOneInputXorOutput : forall f1 f2,
  oneInputXorOutput f1 -> noInputOrOutput f2 -> oneInputXorOutput (appendAny f1 f2).

Lemma AppendOneInputXorOutput2 : forall f1 f2,
  noInputOrOutput f1 -> oneInputXorOutput f2 -> oneInputXorOutput (appendAny f1 f2).

Lemma oneInputAndNoOutputsMeaning: forall fs,
  oneInputAndNoOutputs fs -> oneInput fs -> noOutputs fs.

Lemma oneInputAndNoOutputsMeaning2: forall fs,
  oneInputAndNoOutputs fs -> (oneInput fs /\ noOutputs fs).

Lemma oneInputAndNoOutputsMeaning3: forall fs,
  (oneInput fs /\ noOutputs fs) -> oneInputAndNoOutputs fs.

Lemma noOutputsInputMeansNoInputs: forall fs,
  noInputOrOutput fs -> noInputs fs.


Lemma noOutputsInputMeansNoOutputs: forall fs,
  noInputOrOutput fs -> noOutputs fs.

Lemma noInputDoesNotMeanOneInput : forall fs,
     noInputs fs /\ oneInput fs -> False.

Lemma noOutputDoesNotMeanOneOutput : forall fs,
     noOutputs fs /\ oneOutput fs -> False.

Lemma noInputDoesNotMeanOneInput1 : forall fs,
     noInputs fs -> oneInput fs -> False.

Lemma oneOrOtherXorIn : forall fs,
  oneInputXorOutput fs -> oneInput fs -> noOutputs fs.

Lemma oneOrOtherXorOut : forall fs,
  oneInputXorOutput fs -> oneOutput fs -> noInputs fs.


Lemma noOutOneInIsOneInXorOut : forall fs,
      oneInput fs /\ noOutputs fs -> oneInputXorOutput fs.

Lemma noInImpliesHasInIsFalse : forall fs,
     noInputs fs -> hasInput fs -> False.

Lemma noOutImpliesHasOutIsFalse : forall fs,
     noOutputs fs -> hasOutput fs -> False.

Lemma maxOneInputXor : forall fs,
  oneInputXorOutput fs -> hasInput fs -> oneInput fs.

Lemma noInAndHasInIsFalse : forall fs,
     noInputs fs /\ hasInput fs -> False.

Lemma maxOneInputIfNoOutput : forall fs,
  oneInputXorOutput fs -> hasInput fs -> oneInputAndNoOutputs fs.

Lemma maxOneOutputXor : forall fs,
  oneInputXorOutput fs -> hasOutput fs -> oneOutput fs.

Lemma noOutputsMeansOneOrNo: forall fs,
   noOutputs fs -> oneOrNoOutput fs.

Lemma oneOutputsInputMeansOneOrNo: forall fs,
  oneInputXorOutput fs -> oneOrNoInputXorOutput fs.

Lemma noOutputsInputMeansOneOrNo: forall fs,
  noInputOrOutput fs -> oneOrNoInputXorOutput fs.

Lemma oneOutputsMeansOneOrNo: forall fs,
   oneOutput fs -> oneOrNoOutput fs.

Axiom outIsNotIn: forall trm t, IN t = OUT trm -> False.

Lemma outIsNotAsubListOfIn: forall trm t, subList [OUT trm] [IN t] -> False.


Axiom subListSimplifiedIn: forall trm t fs, subList [OUT trm] (IN t :: fs) -> subList [OUT trm] fs.

Axiom subListSimplifiedK: forall trm t fs, subList [OUT trm] (K t :: fs) -> subList [OUT trm] fs.

Axiom subListSimplifiedFr: forall trm t fs, subList [OUT trm] (FR_P t :: fs) -> subList [OUT trm] fs.

Axiom subListSimplifiedState: forall trm n t fs, subList [OUT trm] (STATE n t :: fs) -> subList [OUT trm] fs.

Axiom noOutputsSimplified : forall f t trm fs,
noOutputs (removeFact (OUT trm) (f :: fs)) /\ not (eq_fact f (OUT t)) ->
noOutputs (removeFact (OUT trm) fs).


Axiom removeOneOutputOut : forall fs trm,
  oneInputXorOutput fs -> (subList [OUT trm] fs) -> noOutputs (removeFact (OUT trm) fs).

Axiom removeOneOutputIn : forall fs trm,
  oneInputXorOutput fs -> (subList [OUT trm] fs) -> noInputs (removeFact (OUT trm) fs).


Axiom InputInSublist : forall f1 f2,
  subList f1 f2 -> oneInput f1 -> oneInput f2.

Lemma oneInputHasInput : forall f1,
  oneInput f1 -> hasInput f1.

Lemma noInputSubst : forall f sigma,
 noInputs f -> noInputs (applySubFacts sigma f).

Lemma oneInputSubst : forall f sigma,
 oneInput f -> oneInput (applySubFacts sigma f).


Lemma oneOutIsOneXorNo : forall fs,
  oneOutput fs -> noInputs fs -> oneInputXorOutput fs.

Lemma subListToHasOutput : forall trm fs,
   subList [OUT trm] fs -> hasOutput fs.

Axiom destructReduceSigma : forall r f1 l f2 sigma,
  groundRule (applySubRule sigma r) ->
    reduceWithGroundRule (applySubRule sigma r) f1 l f2 ->
      reduceWithRuleSigma r sigma f1 l f2.

Axiom subListOneOrOther : forall f1 f fs,
  subList [f1] (f::fs) -> not (eq_fact f1 f) -> subList [f1] fs.

Lemma noOutMeansNoOutSubList : forall f1 trm,
 subList [OUT trm] f1 -> noInputOrOutput f1 -> False.



Lemma InputToOutputMustHaveInput : forall f1 f2 sigma r l,
  reduceWithGroundRule (applySubRule sigma r) f1 l f2
  -> InputToOutputProtocolRule r -> hasInput f1.

Lemma StateToOutputNoOutputRule : forall r sigma f1 l f2,
  noOutputs f1 -> StateToOutputProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> oneOutput f2.

Axiom StateToStateoneOutputXorInputIs : forall r sigma f1 l f2 trms,
  oneOutputXorInputIs f1 trms -> StateToStateProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> oneOutputXorInputIs f2 trms.

Lemma StateToStateNoOutputRule : forall r sigma f1 l f2,
  noInputOrOutput f1 -> StateToStateProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> noInputOrOutput f2.

Lemma noInputOutputImpliesOneOutputIsTrue: forall fs,
      noInputOrOutput fs -> oneOutput fs -> True.

Lemma oneOutputImpliesnoInputOutputIsFalse: forall fs,
      oneOutput fs -> noInputOrOutput fs -> False.

Lemma StateToStateOneOutRule : forall r sigma f1 l f2,
  oneOutput f1 -> StateToStateProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> oneOutput f2.

Lemma StateToStateXorOutRule : forall r sigma f1 l f2,
   oneInputXorOutput f1 -> StateToStateProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> oneInputXorOutput f2.


Lemma InputToOutputOneOutRule : forall r sigma f1 l f2,
  oneInputAndNoOutputs f1 -> InputToOutputProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> oneOutput f2.


Axiom InputToOutputRemovesInput : forall r sigma f1 l f2,
  oneInputXorOutput f1 -> InputToOutputProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> noInputs f2.


Axiom StateToOutputDoesNotAddInput : forall r sigma f1 l f2,
  noInputOrOutput f1 -> StateToOutputProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> noInputs f2.


Axiom InputToStateOneOutRule : forall r sigma f1 l f2,
  oneInput f1 -> noOutputs f1 -> InputToStateProtocolRule r ->
    reduceWithRuleSigma r sigma f1 l f2
      -> noInputOrOutput f2.

Lemma InputToStateMustHaveInput : forall f1 f2 sigma r l,
  reduceWithGroundRule (applySubRule sigma r) f1 l f2
  -> InputToStateProtocolRule r -> hasInput f1.

Axiom FreshRuleNoOutputToNoOutput : forall f1 f2 fn sigma,
  reduceWithRuleSigma (freshRuleP fn) sigma f1 emptyLabel f2
    -> noInputOrOutput f1 -> noInputOrOutput f2.

Axiom FreshRuleOneOutputToOneOutput : forall f1 f2 fn sigma,
  reduceWithRuleSigma (freshRuleP fn) sigma f1 emptyLabel f2
    -> oneInputXorOutput f1 -> oneInputXorOutput f2.

Axiom FreshRuleDoesNotChangeOutputs : forall f1 f2 fn sigma,
  reduceWithRuleSigma (freshRuleP fn) sigma f1 emptyLabel f2
    -> oneOrNoOutput f1 -> oneOrNoOutput f2.

Lemma OneOrNoOutputsFromOutState : forall rlProto sigmas fs1 l fs2,
  runInOrderSigmaProtocol rlProto sigmas fs1 l fs2
    -> (oneInputXorOutput fs1 -> wellFormedProtoRuleFromInOut rlProto -> oneOrNoInputXorOutput fs2)
       /\ (noInputOrOutput fs1 -> wellFormedProtoRuleNoInOut rlProto -> oneOrNoInputXorOutput fs2).

Axiom SetupRuleNoInOutDoesNotAddInOut : forall r f1 l f2,
  noInputOrOutput f1 -> wellFormedSetupRuleNoInOut r ->
    reduceWithRules r f1 l f2
      -> noInputOrOutput f2.

Axiom SetupRuleFromInOutDoesNotChangeInOut : forall r f1 l f2,
  oneInputXorOutput f1 -> wellFormedSetupRuleFromInOut r ->
    reduceWithRules r f1 l f2
      -> oneInputXorOutput f2.

Axiom FreshRuleNoOutputToNoOutput1 : forall f1 f2 fn ,
  reduceWithRule (freshRuleP fn) f1 emptyLabel f2
    -> noInputOrOutput f1 -> noInputOrOutput f2.

Axiom FreshRuleOneOutputToOneOutput1 : forall f1 f2 fn ,
  reduceWithRule (freshRuleP fn) f1 emptyLabel f2
    -> oneInputXorOutput f1 -> oneInputXorOutput f2.

Axiom FreshRuleDoesNotChangeOutputs1 : forall f1 f2 fn ,
  reduceWithRule (freshRuleP fn) f1 emptyLabel f2
    -> oneOrNoOutput f1 -> oneOrNoOutput f2.

Lemma OneOrNoOutputsFromOutStateSetup : forall rlSetup fs1 l fs2,
  run rlSetup fs1 l fs2
    -> (oneInputXorOutput fs1 -> wellFormedSetupRuleFromInOut rlSetup -> oneOrNoInputXorOutput fs2)
       /\ (noInputOrOutput fs1 -> wellFormedSetupRuleNoInOut rlSetup -> oneOrNoInputXorOutput fs2).


Axiom OneOrNoOutputsFromOutStateStdRun : forall rlProto rlSetup sigmas fs1 l fs2,
  runInOrderSigma rlProto rlSetup sigmas fs1 l fs2
    -> (oneInputXorOutput fs1 -> wellFormedProtoRuleFromInOut rlProto -> oneOrNoInputXorOutput fs2)
       /\ (noInputOrOutput fs1 -> wellFormedProtoRuleNoInOut rlProto -> oneOrNoInputXorOutput fs2).

Axiom OneOrNoOutputsFromOutStateSingle : forall sigma r1 rs f1 l f2,
  groundRule (applySubRule sigma r1)
    -> reduceWithGroundRule (applySubRule sigma r1) f1 l f2
      -> wellformedRulesFromState f1 (r1::rs)
        -> oneInputXorOutput f2.




Axiom ruleCanMakeOutput : forall rule sigma f1 label f2 , reduceWithRuleSigma rule sigma f1 label f2
-> noOutputs f1 -> (oneOutput (conclFacts rule)) -> oneOutput f2.


Axiom outputInRuleWillMatchRule : forall rule1 rules sigma f1 l f2 vars,
  reduceWithGroundRule (applySubRule sigma rule1) f1 l f2
    -> groundRule (applySubRule sigma rule1)
      -> wellformedRulesFromState f1 (rule1::rules)
        -> oneOutputAndNoInputIs (conclFacts rule1) (OUT vars)
          -> member (OUT (applySubTerms sigma vars)) f2.


Axiom inputsWillMatch : forall rule1 rules sigma f1 l f2 vars,
  reduceWithGroundRule (applySubRule sigma rule1) f1 l f2
    -> groundRule (applySubRule sigma rule1)
      -> wellformedRulesFromState f1 (rule1::rules)
        -> oneInputAndNoOutputIs (premiseFacts rule1) (IN vars)
          -> member (IN (applySubTerms sigma vars)) f1.


Axiom outputWillMatchFollowingInput : forall rule rs sigma sigmas f1 l f2 vars trms,
runInOrderSigmaProtocol (rule::rs) (sigma::sigmas) f1 l f2
 -> oneInputXorOutput f1 -> member (OUT trms) f1
   -> oneInputAndNoOutputIs (premiseFacts rule) (IN vars)
-> eq_terms trms (applySubTerms sigma vars).

Axiom outputIOruleWillMatchRule : forall f1 l f2 rule sigma,
  oneInputXorOutput f1 -> InputToOutputProtocolRule rule
    -> reduceWithGroundRule (applySubRule sigma rule) f1 l f2
      -> exists var, member (OUT var) (conclFacts rule) /\ member (OUT (applySubTerms sigma var)) f2.

Axiom OutputInRuleWillMatch : forall r sigma f1 t f2 trms,
  runInOrderSigmaProtocol [r] [sigma] f1 t f2
    -> wellformedRulesFromState f1 [r]
      -> oneOutputAndNoInputIs (conclFacts r) (OUT trms)
        -> oneOutputAndNoInputIs f2 (OUT (applySubTerms sigma trms)).

Axiom outputMatchesNextInput : forall r1 r2 sigma1 sigma2 trms1 trms2 f1 trace f3 ,
    runInOrderSigmaProtocol [r1;r2] [sigma1;sigma2] f1 trace f3
      -> oneOutputAndNoInputIs (conclFacts r1) (OUT trms1)
        -> oneOutputAndNoInputIs (premiseFacts r2) (IN trms2)
          -> eq_terms (applySubTerms sigma1 trms1) (applySubTerms sigma2 trms2).

Axiom outputMatchesNextInputEnd : forall r1 r2 sigma1 sigma2 trms1 trms2 f1 trace f3 sigmaList rulesList setuprules,
    runInOrderSigma (appendAny rulesList [r1;r2]) setuprules (appendAny sigmaList [sigma1;sigma2]) f1 trace f3
      -> oneOutputAndNoInputIs (conclFacts r1) (OUT trms1)
        -> oneOutputAndNoInputIs (premiseFacts r2) (IN trms2)
          -> eq_terms (applySubTerms sigma1 trms1) (applySubTerms sigma2 trms2).




Lemma outputMatchesNextInputEndProtocol : forall r1 r2 sigma1 sigma2 trms1 trms2 f1 trace f3 ,
    runInOrderSigmaProtocol ( [r1;r2]) ([sigma1;sigma2]) f1 trace f3
      -> wellformedRulesFromState f1 [r1;r2]
      -> oneOutputAndNoInputIs (conclFacts r1) (OUT trms1) -> oneInputAndNoOutputIs (premiseFacts r2) (IN trms2)
          -> eq_terms (applySubTerms sigma1 trms1) (applySubTerms sigma2 trms2).

Axiom InputMatchesFactsProtocol : forall r1 r2 sigma1 sigma2 trms1 trms2 f1 trace f2 ,
  runInOrderSigmaProtocol [r1] [sigma1] f1 trace f2
    -> wellformedRulesFromState f1 [r1]
      -> oneOutputXorInputIs f1 trms1 -> oneInputAndNoOutputIs (premiseFacts r2) (IN trms2)
        -> eq_terms trms1 (applySubTerms sigma2 trms2).

Fixpoint StateToStateRules (rs:list rule) : Prop :=
  match rs with
    | [] => True
    | r::rs => StateToStateProtocolRule r /\ StateToStateRules rs
  end.

Fixpoint lastOutputNoInput (trms:terms) (rules:list rule) : Prop :=
match rules with
  | r::rs => (oneOutputAndNoInputIs (conclFacts r) (OUT trms) /\ StateToStateRules rs)
                           \/ lastOutputNoInput trms rs
  | [] => False
 end.

Fixpoint lastOutputNoInputAndSigma (trms:terms) (sigma:substitution) (rules:list rule) (sigmas:substitutions) : Prop :=
match rules, sigmas with
  | r::rs, sig::sigs => (oneOutputAndNoInputIs (conclFacts r) (OUT trms) /\ StateToStateRules rs /\ sig=sigma)
                           \/ lastOutputNoInputAndSigma trms sigma rs sigs
  | _,_ => False
 end.

Axiom lastOutputNoInputHasSigma: forall trms (rules:list rule) (f1:facts) rules sigmas f1 trace f2,
  lastOutputNoInput trms rules
    -> runInOrderSigmaProtocol rules sigmas f1 trace f2
      -> exists sigma, member sigma sigmas /\ lastOutputNoInputAndSigma trms sigma rules sigmas.

Axiom lastOutputNoInputStdRunHasSigma: forall trms (rlProto:list rule) (rlSetup:list rule) (f1:facts) rlProto rlSetup sigmas f1 trace f2,
  lastOutputNoInput trms rlProto
    -> runInOrderSigma rlProto rlSetup sigmas f1 trace f2
      -> exists sigma, member sigma sigmas /\ lastOutputNoInputAndSigma trms sigma rlProto sigmas.

Axiom wellformednessPreserved : forall f1 r rs sigma l f2,
  wellformedRulesFromState f1 (r :: rs)
    -> reduceWithGroundRule (applySubRule sigma r) f1 l f2
      -> wellformedRulesFromState f2 rs.

Axiom OutputInputUnchangedByStoSrule : forall f1 r sigma l f2 trms,
  reduceWithGroundRule (applySubRule sigma r) f1 l f2
    -> StateToStateProtocolRule r -> oneOutputXorInputIs f1 trms
      -> oneOutputXorInputIs f2 trms.

Axiom OutXorInAndOutMeansNoIn : forall trms f1,
subList [OUT trms] f1 -> oneOutputXorInputIs f1 trms -> noInputs f1.

Axiom OneOutRemovedMeansNone : forall trms f1,
subList [OUT trms] f1 -> oneOutputXorInputIs f1 trms -> noOutputs (removeFacts [OUT trms] f1).

Axiom OnlyOneOutputInOxI : forall f1 trms1 trms2,
  oneOutputXorInputIs f1 trms1 -> subList [OUT trms2] f1 -> trms1=trms2.

Lemma OutputInputUnchangedByStoSrules : forall rules sigmas f1 trace f2 trms,
  runInOrderSigmaProtocol rules sigmas f1 trace f2
    -> wellformedRulesFromState f1 rules -> StateToStateRules rules
      -> oneOutputXorInputIs f1 trms -> oneOutputXorInputIs f2 trms.

Axiom runInOrderSigmaProtocolTail: forall r rules sigma sigmas f1 trace1 f3,
  runInOrderSigmaProtocol (r :: rules) (sigma :: sigmas) f1 trace1 f3
    -> wellformedRulesFromState f1 (r :: rules)
      -> exists f2 trace2 trace3, (runInOrderSigmaProtocol [r] [sigma] f1 trace2 f2
                              /\ runInOrderSigmaProtocol rules sigmas f2 trace3 f3
                                 /\ wellformedRulesFromState f2 rules).

Axiom wellformedHead : forall f1 r rules,
  wellformedRulesFromState f1 (r :: rules) -> wellformedRulesFromState f1 [r].

Lemma lastOutputInFacts : forall rules sigmas f1 trace f2 trms sigma,
 runInOrderSigmaProtocol rules sigmas f1 trace f2
    -> wellformedRulesFromState f1 rules
      -> lastOutputNoInputAndSigma trms sigma rules sigmas
        -> oneOutputXorInputIs f2 (applySubTerms sigma trms).

Lemma outputMatchesNextInputProtocol : forall rules sigmas f1 trace1 f2 ruleLast sigmaLast trace2 f3 trms1 trms2 outSigma,
  runInOrderSigmaProtocol rules sigmas f1 trace1 f2
    -> runInOrderSigmaProtocol [ruleLast] [sigmaLast] f2 trace2 f3
      -> wellformedRulesFromState f1 rules -> wellformedRulesFromState f2 [ruleLast]
        -> lastOutputNoInputAndSigma trms1 outSigma rules sigmas -> oneInputAndNoOutputIs (premiseFacts ruleLast) (IN trms2)
          -> eq_terms (applySubTerms outSigma trms1) (applySubTerms sigmaLast trms2).


Axiom OutputInRuleWillMatchStdRun : forall r rlSetup sigma f1 t f2 trms,
  runInOrderSigma [r] rlSetup [sigma] f1 t f2
    -> wellformedRulesFromState f1 [r]
      -> oneOutputAndNoInputIs (conclFacts r) (OUT trms)
        -> oneOutputAndNoInputIs f2 (OUT (applySubTerms sigma trms)).

Axiom OutputInputUnchangedByStoSrulesStdRun : forall protocolRules setupRules sigmas f1 trace f2 trms,
  runInOrderSigma protocolRules setupRules sigmas f1 trace f2
    -> wellformedRulesFromState f1 protocolRules -> StateToStateRules protocolRules
      -> oneOutputXorInputIs f1 trms -> oneOutputXorInputIs f2 trms.

Axiom runInOrderSigmaTail: forall r rlProto rlSetup sigma sigmas f1 trace1 f3,
  runInOrderSigma (r :: rlProto) rlSetup (sigma :: sigmas) f1 trace1 f3
    -> wellformedRulesFromState f1 (r :: rlProto)
      -> exists f2 trace2 trace3, (runInOrderSigma [r] rlSetup [sigma] f1 trace2 f2
                              /\ runInOrderSigma rlProto rlSetup sigmas f2 trace3 f3
                                 /\ wellformedRulesFromState f2 rlProto).

Lemma lastOutputInFactsStdRun : forall protocolRules setupRules sigmas f1 trace f2 trms sigma,
 runInOrderSigma protocolRules setupRules sigmas f1 trace f2
    -> wellformedRulesFromState f1 protocolRules
      -> lastOutputNoInputAndSigma trms sigma protocolRules sigmas
        -> oneOutputXorInputIs f2 (applySubTerms sigma trms).

Axiom InputMatchesFactsStdRun : forall r1 r2 setupRules sigma1 sigma2 trms1 trms2 f1 trace f2 ,
  runInOrderSigma [r1] setupRules [sigma1] f1 trace f2
    -> wellformedRulesFromState f1 [r1]
      -> oneOutputXorInputIs f1 trms1 -> oneInputAndNoOutputIs (premiseFacts r2) (IN trms2)
        -> eq_terms trms1 (applySubTerms sigma2 trms2).

Lemma outputMatchesNextInputStdRun : forall protocolRules setupRules sigmas f1 trace1 f2 ruleLast sigmaLast trace2 f3 trms1 trms2 outSigma,
  runInOrderSigma protocolRules setupRules sigmas f1 trace1 f2
    -> runInOrderSigma [ruleLast] setupRules [sigmaLast] f2 trace2 f3
      -> wellformedRulesFromState f1 protocolRules -> wellformedRulesFromState f2 [ruleLast]
        -> lastOutputNoInputAndSigma trms1 outSigma protocolRules sigmas -> oneInputAndNoOutputIs (premiseFacts ruleLast) (IN trms2)
          -> eq_terms (applySubTerms outSigma trms1) (applySubTerms sigmaLast trms2).

Definition variableDirectlyLinkedInputOutput (x:variable) (newRule:rule) (pastRules: list rule) : Prop :=
  exists trms1 trms2, (member (IN trms1) (premiseFacts newRule))
    /\ lastOutputNoInput trms2 pastRules
    /\ baseTermAtSamePosTerms (Var x) trms1 trms2.


Axiom equalTermsIfbaseTermAtSamePosFunc: forall sigma1 sigma2 trms1 trms2 f l x0,
baseTermAtSamePosTerms (Var x0) (Func f l :: trms2)
       trms1
-> eq_terms (applySubTerms sigma1 trms1)
      (applySubTerms sigma2 (Func f l :: trms2))
-> eq_terms (applySubTerms sigma1 trms1)
  (applySubTerms sigma2 trms2).

Axiom baseTermAtSamePosTermsFunc: forall f l x0 trms1 trms2,
baseTermAtSamePosTerms (Var x0) (Func f l :: trms2)
       trms1
-> baseTermAtSamePosTerms (Var x0) trms2 trms1.

Axiom equalTermsIfbaseTermAtSamePosBTerm: forall sigma1 sigma2 trms1 trms2 b x0,
baseTermAtSamePosTerms (Var x0) (Bterm b :: trms2)
       trms1
-> eq_terms (applySubTerms sigma1 trms1)
      (applySubTerms sigma2 (Bterm b :: trms2))
-> eq_terms (applySubTerms sigma1 trms1)
  (applySubTerms sigma2 trms2).

Axiom baseTermAtSamePosTermsBTerm: forall b x0 trms1 trms2,
baseTermAtSamePosTerms (Var x0) (Bterm b :: trms2)
       trms1
-> baseTermAtSamePosTerms (Var x0) trms2 trms1.

Lemma equalTermsMeansEqualVars : forall trms1 sigma1 trms2 sigma2 x,
 eq_terms (applySubTerms sigma1 trms1) (applySubTerms sigma2 trms2)
-> baseTermAtSamePosTerms (Var x) trms2 trms1
 -> sigma1 x = sigma2 x.

Axiom InputFactsEqualMeansEqualTerms: forall t1 t2,
  IN t1 = IN t2 -> t1 = t2.

Axiom oneInputInFactsMeansEqualTerms: forall fs t trms,
member (IN trms) fs -> oneInput (IN t :: fs) -> t = trms.

Lemma InputInFactIsoneInput1 : forall fs trms,
  member (IN trms) fs -> oneInput fs -> noOutputs fs -> oneInputAndNoOutputIs fs (IN trms).

Axiom InputInFactIsoneInputAndNoOutput : forall fs,
  member (IN []) fs -> oneInput fs -> noOutputs fs -> oneInputAndNoOutputIs fs (IN []).

Axiom InputInFactIsoneInputAndNoOutputTerms : forall fs trms,
  member (IN trms) fs -> oneInput fs -> noOutputs fs -> oneInputAndNoOutputIs fs (IN trms).

Axiom InputInFactIsoneInput : forall fs,
  member (IN []) fs -> noOutputs fs -> oneInputIs fs (IN []).

Axiom inputAsMemberIsTheInput : forall f t,
    member (IN t) f -> oneInput f -> oneInputIs f (IN t).

Axiom InputToStateProtoRuleDoesNotAddOut: forall f1 l f2 trms,
member (IN trms) f1 -> InputToStateProtocolRule (RuleProto f1 l f2) -> oneInputAndNoOutputIs f1 (IN trms).


Axiom noInputsMeanNoInFacts : forall trms f,
  member (IN trms) f -> noInputs f -> False.

Lemma oneInputOnlyWellFormedRule : forall trms rule fs rs,
member (IN trms) (premiseFacts rule)
 -> wellformedRulesFromState fs (rule::rs)
 -> oneInputAndNoOutputIs (premiseFacts rule) (IN trms).

Lemma DirectlyLinkedInOutVarsMatchProtocolRules : forall rules sigmas f1 trace1 f2 ruleLast sigmaLast trace2 f3 x,
  runInOrderSigmaProtocol rules sigmas f1 trace1 f2
    -> runInOrderSigmaProtocol [ruleLast] [sigmaLast] f2 trace2 f3
      -> wellformedRulesFromState f1 rules -> wellformedRulesFromState f2 [ruleLast]
        -> variableDirectlyLinkedInputOutput x ruleLast rules
          -> exists sigma, member sigma sigmas /\ (sigma x) = (sigmaLast x).

Lemma DirectlyLinkedInOutVarsMatchStdRun : forall rlProto rlSetup sigmas f1 trace1 f2 ruleLast sigmaLast trace2 f3 x,
  runInOrderSigma rlProto rlSetup sigmas f1 trace1 f2
    -> runInOrderSigma [ruleLast] rlSetup [sigmaLast] f2 trace2 f3
      -> wellformedRulesFromState f1 rlProto -> wellformedRulesFromState f2 [ruleLast]
        -> variableDirectlyLinkedInputOutput x ruleLast rlProto
          -> exists sigma, member sigma sigmas /\ (sigma x) = (sigmaLast x).


Fixpoint memberAtSamePos {T1:Type} {T2:Type} (e1:T1) (e2:T2) (list1: list T1) (list2: list T2) : Prop :=
  match list1 with
    | [] => False
    | h1::ts1 => match list2 with
                   | [] => False
                   | h2::ts2 => (e1=h1 /\ e2=h2) \/ memberAtSamePos e1 e2 ts1 ts2
                  end
   end.

Lemma factFromRule : forall fac (f1:facts) protocolRules sigmas f1 t f2,
 runInOrderSigmaProtocol protocolRules sigmas f1 t f2 -> member fac f2 -> not(member fac f1)
      -> exists r sigma facTemplate, memberAtSamePos r sigma protocolRules sigmas
             /\ member facTemplate (conclFacts r) /\ applySubFact sigma facTemplate = fac.
Lemma reverseHeadList : forall (h:rule) (ts:list rule), exists listPart last, (h::ts) = appendAny listPart [last].

Lemma appendAnyAppendAny: forall {T:Type} (x1:T) x0 r,
(appendAny (appendAny x0 [x1]) [r]) = (appendAny x0 [x1;r]).



Inductive Def2_1_Valid_AllowSequences : (list ruleList) -> ruleList -> Prop :=
  | Empty_AS : forall rs, Def2_1_Valid_AllowSequences [] rs
  | Step_AllowSeq : forall rl rlsHead rlsTail,
              orderedSubList rlsHead rl /\ Def2_1_Valid_AllowSequences rlsTail rl
                              -> Def2_1_Valid_AllowSequences (rlsHead::rlsTail) rl.

Lemma canExtendAllowSeq : forall rl rls r, Def2_1_Valid_AllowSequences rls rl
                                                   -> Def2_1_Valid_AllowSequences rls (r::rl).

Lemma idIsAllowSeq : forall rl, Def2_1_Valid_AllowSequences [rl] rl.

Fixpoint allPrefixs (rl:ruleList) : list ruleList :=
  match rl with
    | [] => []
    | h::ts => (h::ts):: (allPrefixs ts)
  end.

Lemma prefixIsAllowSeq : forall rl:ruleList, Def2_1_Valid_AllowSequences (allPrefixs rl) rl.


Lemma allListsAllowedSeq : forall rll:(list ruleList), exists rl:ruleList, Def2_1_Valid_AllowSequences rll rl.

Lemma ginstSplit : forall rl1 rl2 r, ginsts r rl2 -> ginsts r (appendAny rl1 rl2).

Inductive Def_Standard_Trace : list ruleList -> ruleList -> substitutions-> trace -> Prop :=
  | StandRun_Head : forall rl rls t f2 setupRules sigmas, (runInOrderSigma rl setupRules sigmas [] t f2 ) -> Def_Standard_Trace (rl::rls) setupRules sigmas t
  | StandRun_Tail : forall rl rls t setupRules sigmas, Def_Standard_Trace rls setupRules sigmas t -> Def_Standard_Trace (rl::rls) setupRules sigmas t.


Definition Def5_7_Standard_Trace(allowSeq:list ruleList) (setupRules: ruleList) (sigmas : substitutions) (thisTr:trace) : Prop :=
                      (Def_Standard_Trace allowSeq setupRules sigmas thisTr).

Inductive Subset_of_Standard_Traces : list ruleList -> ruleList -> substitutions -> list trace -> Prop :=
  | StandTraces_Empty : forall rlp setupRules sigmas, Subset_of_Standard_Traces rlp setupRules sigmas []
  | StandTraces_Next : forall rlp setupRules t ts sigmas, Def5_7_Standard_Trace rlp setupRules sigmas t /\ Subset_of_Standard_Traces rlp setupRules sigmas ts -> Subset_of_Standard_Traces rlp setupRules sigmas (t::ts).

Inductive mergeTrace : trace -> trace -> trace -> Prop :=
  | PMerge_nil : mergeTrace [] [] []
  | PMerge_left : forall x l l1 l2 , mergeTrace l1 l2 l -> mergeTrace (x::l1) l2 (x::l)
  | PMerge_right : forall x l l1 l2, mergeTrace l1 l2 l -> mergeTrace l1 (x::l2) (x::l).

Inductive merge : list trace -> trace -> Prop :=
  | PMerge_Base : forall lstTR TR, In TR lstTR -> merge lstTR TR
  | PMerge_Step : forall lst1 tr1 tr2 trnew, (merge lst1 tr1 /\ In tr2 lst1 /\ mergeTrace tr1 tr2 trnew)
                                                                              -> merge lst1 trnew.

Fixpoint applySubRuleListWise (sigmas : list substitution) (rl:ruleList) : ruleList :=
match sigmas, rl with
  | sig1::sigs, r1::rs => (applySubRule sig1 r1)::(applySubRuleListWise sigs rs)
  | _, _ => []
end.

Fixpoint Def5_5_freshInRL (rl: ruleList) : list freshNameProto :=
  match rl with
    | [] => []
    | rl1::rls => appendAny (getFrNamesPremise (getFrFactProtoRule rl1)) (Def5_5_freshInRL rls)
  end.

Definition Def5_6_FreshFromRL_In_Trace (sigmas:substitutions) (rl:ruleList) (tr: trace) : list freshNameProto :=
          commonFreshNames (Def5_5_freshInRL (applySubRuleListWise sigmas rl)) (getFreshProtoNamesinTrace tr).

Definition ConditionOnFreshNames (sigmas:substitutions) (allowSeq:list ruleList) (logFromTraces:list trace) : Prop :=
forall tr_i tr_j rl_i rl_j, noCommonElements (Def5_6_FreshFromRL_In_Trace sigmas rl_i tr_i)
                                              (Def5_6_FreshFromRL_In_Trace sigmas rl_j tr_j)
                                     /\ (member rl_i allowSeq)
                                      /\ (member rl_j allowSeq)
                                       /\ (member tr_i logFromTraces)
                                         /\ (member tr_j logFromTraces)
                                          /\ not (eq tr_i tr_j).

Definition Def5_7_Standard_Looking_Trace (allowSeq:list ruleList) (setupRules:ruleList) (testTrace:trace) : Prop :=
 exists sigmas sometraces, (Subset_of_Standard_Traces allowSeq setupRules sigmas sometraces)
                       /\ (merge (map getLogTrace sometraces) (getLogTrace testTrace))
                         /\ ConditionOnFreshNames sigmas allowSeq (map getLogTrace sometraces).

Definition Def5_8_Attack_Trace (attackTrace:trace) : Prop := True.

Definition Def5_9_Stealth_Attack (allowSeq:list ruleList) (setupRules:ruleList) (testTrace:trace) : Prop :=
            Def5_7_Standard_Looking_Trace allowSeq setupRules testTrace /\ Def5_8_Attack_Trace testTrace.

============================================

9: Definitions from Chapter 6 of the thesis

===============================================

Definition StdTemplateForRuleList : ruleList -> trace := getLogRL.

Definition Def_StdTemplates : (list ruleList) -> (list trace) := map getLogRL.

Definition Def6_10_StdTemplate (allowSeq:list ruleList) (thisTemp:trace) : Prop :=
                   (In thisTemp (Def_StdTemplates allowSeq)).

Fixpoint StdTracesfromTemplates (sigma:substitution) (allowSeq: list ruleList) : list trace :=
         applySubTraces sigma (Def_StdTemplates allowSeq).

Definition StdTracefromTemplate (sigma:substitution) (allRules:list ruleList) (thisTrace:trace) : Prop :=
           (In thisTrace (StdTracesfromTemplates sigma allRules)).

Definition SID : baseTerm := (Var "sid").


Fixpoint updateLabel (l1 : label ) : label :=
  match l1 with
    | (LoggedSIDLabel t al lb) => (LoggedSIDLabel t al lb)
    | (LoggedLabel al lb) => (LoggedSIDLabel SID al lb)
    | (BasicLabel als) => (BasicLabel als)
  end.

While annotating rules, annotation of first rule modifies all three parts of a rule while with other rules only the premise and labels are modified

Fixpoint annotateFirstRule (firstRule : rule) : rule :=
  match firstRule with
  | RuleProto f1 lbl f2 => RuleProto (FR_P SID::f1) (updateLabel lbl) ((OUT [Bterm SID])::f2)
  | RuleSetup f1 lbl f2 => RuleSetup f1 lbl f2
  end.

Fixpoint annotateOtherRules (rl : ruleList) : ruleList :=
  match rl with
  | (RuleSetup f1 lbl f2)::rls => (RuleSetup f1 lbl f2) :: (annotateOtherRules rls)
  | (RuleProto ppat lbl cpat)::t => (RuleProto ((IN [(Bterm SID)])::ppat)
                                               (updateLabel lbl) ((OUT [(Bterm SID)])::cpat))::(annotateOtherRules t)
  | [] => []
  end.

"annotateRules rl " add the session IDs to the ruleList rl

Fixpoint annotateRules (rl : ruleList) : ruleList :=
  match rl with
  | [] => []
  | r::t => (annotateFirstRule r) ::(annotateOtherRules t)
  end.

Definition AddSID :(list ruleList) -> (list ruleList) := map annotateRules.

Definition Def6_11_SessionsRL (allowSeq:list ruleList) : (list trace) :=
           Def_StdTemplates (AddSID allowSeq).

Definition Def6_12_StdSessionTemplate (allowSeq:list ruleList) (thisTemp:trace) : Prop :=
                   (In thisTemp (Def6_11_SessionsRL allowSeq)).

Fixpoint subTrace_genFrom_Template (sigma:substitution) (tr:trace) (StdTmp:trace) : Prop :=
  match tr, StdTmp with
  | [],[] => True
  | t1::ts, o1::os => eq_label t1 (applySubLabel sigma o1)
                       /\
                       (subTrace_genFrom_Template sigma ts os)
  | _,_ => False
  end.

Remove the session IDs from a trace

Fixpoint RemoveSIDfromLabel (l1 : label) : label :=
  match l1 with
    | (LoggedSIDLabel t al lb) => (LoggedLabel al lb)
    | (LoggedLabel al lb) => (LoggedLabel al lb)
    | (BasicLabel als) => (BasicLabel als)
  end.

Definition RemoveSID : trace -> trace := map RemoveSIDfromLabel.
"sameSID t1 t2" verifies if terms "t1" and "t2" contain the same SID

Fixpoint sameSID (tm1:terms) (tm2:terms): Prop :=
  match tm1, tm2 with
     | sid1::pars1, sid2::pars2 => eq_term sid1 sid2
     | _,_ => False
  end.

"al_Only_OnceNMAL al Tstd" verifies if every "al" present in template "tm", is present only once.

Fixpoint al_Only_OnceNMAL (al:actionLabel) (Tstd:trace) : Prop :=
 match Tstd with
    | nil => False
    | lbl1:: lbls => ((inLabelwithName al lbl1) /\ not (ALinTemplatewithName al lbls))
                      \/
                      (not (inLabelwithName al lbl1) /\ al_Only_OnceNMAL al lbls)
  end.

"everyLogUniqueinTemplate Tstd" holds only if every "al" present in template is present only once.

Definition everyLogUniqueinTemplate (Tstd:trace) : Prop :=
  forall al, (al_in_Trace al Tstd) ->
                    al_Only_OnceNMAL al Tstd.

Fixpoint WellFormedTemplate (Tstd:list trace) : Prop:=
  match Tstd with
  | tm1::tmRestList => (everyLogUniqueinTemplate tm1)
                          /\
                         (WellFormedTemplate tmRestList)
  | [] => True
  end.

Lemma emptyLabelsLemma : forall sigma l, applySubLabel sigma l = emptyLabel -> l = emptyLabel.

Lemma emptyReduceGround : forall r f1 f2, reduceWithGroundRule r f1 emptyLabel f2
                                    -> (labelR r) = emptyLabel.

Lemma emptyReduce : forall r f1 f2, reduceWithRule r f1 emptyLabel f2
                                    -> (labelR r) = emptyLabel.

Lemma LoggedLabelGroundReduce : forall r f1 f2 lg1 l1, reduceWithGroundRule r f1 (LoggedLabel lg1 l1) f2
                                    -> exists lg2 l2, (labelR r) = (LoggedLabel lg2 l2).

Lemma LoggedSIDLabelGroundReduce : forall r f1 f2 lg1 l1 t, reduceWithGroundRule r f1 (LoggedSIDLabel t lg1 l1) f2
                                    -> exists lg2 l2 t, (labelR r) = (LoggedSIDLabel t lg2 l2).

Lemma LoggedLabelReduce : forall r f1 f2 lg1 l1, reduceWithRule r f1 (LoggedLabel lg1 l1) f2
                                    -> exists lg2 l2, (labelR r) = (LoggedLabel lg2 l2).

Lemma emptyLabelSigmaEq : forall sigma l, ((applySubLabel sigma l) = emptyLabel) -> (l = emptyLabel).

Lemma setupRulesBasicLabels : forall rls f1 l f2,
wellFormedSetupRules rls -> reduceWithRules rls f1 l f2 -> exists al, l = BasicLabel al.

Lemma StdTracesHaveTemplates : forall t allowSequence sigma setupRules f1 f2,
        wellFormedSetupRules setupRules
          -> runInOrder allowSequence setupRules sigma f1 t f2
            -> (getLogTrace t) =
                       (applySubTrace sigma (StdTemplateForRuleList allowSequence)).








Fixpoint uniqueStateFact (f:fact) (rl:list rule) : Prop :=
  match rl, f with
    | r::rlt, STATE n ts => ( stateAppearsOnce f (conclFacts r) /\ NameDoesNotAppearInFacts n (allConclFacts rlt) )
                            \/ ( NameDoesNotAppearInFacts n (conclFacts r) /\ uniqueStateFact f rlt )
    | _ , _ => False
  end.


Fixpoint variableInUniqueStateFact (v:variable) (newRule:rule) (pastRules: list rule) : Prop :=
  exists n ts, (uniqueStateFact (STATE n ts) pastRules) /\ (member (STATE n ts) (premiseFacts newRule))
                    /\ member v (variablesInTerms ts).


Fixpoint uniqueTermsForRule (ts:terms) (n:name) (r:rule) (rs:list rule) : Prop :=
  match ts with
    | [] => True
    | th::tst => ( termIsOnlyConstant th n rs \/ termIsFresh th r ) /\ (uniqueTermsForRule tst n r rs)
  end.

Fixpoint uniqueArgumentsFact (f:fact) (r: rule) (rs:list rule) : Prop :=
  match f with
   | STATE n ts => (uniqueTermsForRule ts n r rs)
   | _ => False
  end.

Fixpoint collectUniqueStateFacts (fls:facts) (rlst:ruleList) : facts :=
  match fls with
  | f1::fs => match (uniqueStateFact f1 rlst) with
                | True => (f1 :: (collectUniqueStateFacts fs rlst))
                end
  | [] => []
  end.

Fixpoint collectUniqueArgFacts (fls:facts) (r:rule) (rls:ruleList) : facts :=
  match fls with
  | f1::fs => match (uniqueArgumentsFact f1 r rls) with
                | True => (f1 :: (collectUniqueArgFacts fs r rls))
                end
  | [] => []
  end.

Fixpoint PresentInSamePositionUniqueStateFact (RL:list rule) (t1:term) (t2:term) : Prop :=
    CheckFactsInUSF (collectUniqueStateFacts (collectStateFacts RL) RL) t1 t2.

Fixpoint PresentInSamePositionUAF (RL:list rule) (t1:term) (t2:term) : Prop :=
  match RL with
  | r::rs => ((CheckFactsInUAF (collectUniqueArgFacts (collectStateFacts RL) r rs) t1 t2)
                  /\
                    PresentInSamePositionUAF rs t1 t2)
  | [] => True
  end.

Fixpoint varMatchInLastOutput (x:variable) (ts:terms) (revRules: list rule) : Prop :=
  match revRules with
    | [] => False
    | r::rs => member (OUT ts) (conclFacts r)
                 \/ ((noOutputRule r) /\ varMatchInLastOutput x ts rs)
   end.

Fixpoint variableLinkedInputOutput (x:variable) (newRule:rule) (pastRules: list rule) : Prop :=
  exists ts, (member (IN ts) (premiseFacts newRule))
    /\ varMatchInLastOutput x ts (rev pastRules).

Definition Def6_4_allowedFactType (f:fact) (r: rule) (rs:list rule) : Prop :=
  (exists t, (member (FR_P t) (premiseFacts r)) /\ (eq_fact f (FR_P t)))
    \/
     (exists ts, (member (IN ts) (premiseFacts r) /\ (eq_fact f (IN ts))
        \/
           (member (OUT ts) (conclFacts r)) /\ (eq_fact f (OUT ts))))
             \/
               (uniqueStateFact f (r::rs))
                 \/
                   (uniqueArgumentsFact f r rs).

Definition Def6_5_variableDirectlyLinked (var: variable) (newRule:rule) (pastRules: list rule) : Prop :=
   (variableLinkedInputOutput var newRule pastRules)
       \/ (variableInUniqueStateFact var newRule pastRules).

Fixpoint Def6_6_variableIndirectlyLinked (v:variable) (newRule:rule) (pastRules: list rule) : Prop :=
  exists n ts, uniqueArgumentsFact (STATE n ts) newRule pastRules
                /\ member (STATE n ts) (premiseFacts newRule)
                  /\ (exists RuleA, member (STATE n ts) (conclFacts RuleA) /\ (member RuleA pastRules))
                   /\ member v (variablesInTerms ts)
                      /\ (exists t, member t (variablesInTerms ts)
                              /\ Def6_5_variableDirectlyLinked t newRule pastRules)
                                /\ (exists c, member c (constantsInTerms ts)).

Definition variableIsNew (var:variable) (pastRules: list rule) : Prop :=
   trueForAll (fun x => (NotIn var (variablesInRule x))) pastRules.

Definition Def6_7_validVariable (newRule:rule) (pastRules: list rule) (var: variable) : Prop :=
   (variableIsNew var pastRules) \/ (Def6_5_variableDirectlyLinked var newRule pastRules)
        \/ (Def6_6_variableIndirectlyLinked var newRule pastRules).

Fixpoint Def6_7_validVariables (newRule:rule) (pastRules: list rule) (vs:variables) : Prop :=
  trueForAll (Def6_7_validVariable newRule pastRules) vs.

Definition Def6_8_validRule (newRule:rule) (pastRules: list rule): Prop :=
    (forall f, (member f (allFactsRL (appendAny pastRules [newRule])))
               /\ (Def6_4_allowedFactType f newRule pastRules))
                  /\ (forall vs, trueForAll (Def6_7_validVariable newRule pastRules) vs).

Fixpoint Def6_9_validRuleList (rs : list rule) : Prop :=
  match rs with
    | [] => True
    | r::rst => (Def6_9_validRuleList rst) /\ (Def6_7_validVariables r rst (variablesInRule r))
  end.

Fixpoint Def6_9_validRuleLists (allowSeq : list ruleList) : Prop := trueForAll Def6_9_validRuleList allowSeq.


Lemma Prop1_DirectlyLinkedVariablesHaveSameValues : forall fs1 fs2 sigma_j tr v r rlProto rlSetup SigmaList,
        ((Def6_9_validRuleList (appendAny rlProto [r])
              /\ runInOrderSigma (appendAny rlProto [r]) rlSetup (appendAny SigmaList [sigma_j]) fs1 tr fs2))

          -> ((Def6_5_variableDirectlyLinked v r rlProto)
                -> (variableIsNew v rlProto)
                        \/
                         (exists sigma_i, (eq_name (sigma_i v) (sigma_j v))
                                   /\ ((member sigma_i SigmaList)))
                          ).
Lemma Prop2_IndirectlyLinkedVariablesHaveSameValues : forall fs1 fs2 sigma_j tr v r rlProto rlSetup SigmaList,
        ((Def6_9_validRuleList (appendAny rlProto [r])
              /\ runInOrderSigma (appendAny rlProto [r]) rlSetup (appendAny SigmaList [sigma_j]) fs1 tr fs2))
          -> ((Def6_6_variableIndirectlyLinked v r rlProto)
                -> (variableIsNew v rlProto)
                        \/
                         (exists sigma_i, (eq_name (sigma_i v) (sigma_j v))
                                   /\ ((member sigma_i SigmaList)))
                          ).
Lemma Prop3_AllSigmasCanBeReplacedbyASingleSigma : forall fs1 fs2 tr r rlProto rlSetup SigmaList,
        (Def6_9_validRuleList (appendAny rlProto [r])
               /\ runInOrderSigma (appendAny rlProto [r]) rlSetup SigmaList fs1 tr fs2)
                   -> (exists sigma, forall v sigma_i, (Def6_7_validVariable r rlProto v)
                          /\ (member sigma_i SigmaList)
                        -> (eq_name (sigma_i v) (sigma v))
                        ).
Lemma Prop5_ExistsTraceAndSigmaForTemplate : forall allowSeq rlSetup rlp tr_temp,
        (Def6_9_validRuleList rlp /\ Def2_1_Valid_AllowSequences allowSeq rlp)
          -> exists tr_log sigma SigmaList, Def5_7_Standard_Trace allowSeq rlSetup SigmaList tr_log
                -> (Def6_10_StdTemplate allowSeq [tr_temp])
                                  /\ (eq (applySubTrace sigma [tr_temp]) tr_log)
                                      /\ (member sigma SigmaList).
Theorem Thm_7_1_ExistsTemplateAndSigmaForTrace : forall allowSeq rlSetup rlp tr_log,
        (Def6_9_validRuleList rlp /\ Def2_1_Valid_AllowSequences allowSeq rlp)
          -> exists tr_template sigma SigmaList, Def5_7_Standard_Trace allowSeq rlSetup SigmaList tr_log
                -> (Def6_10_StdTemplate allowSeq tr_template)
                                  /\ (eq (applySubTrace sigma tr_template) tr_log)
                                      /\ (member sigma SigmaList).
Def 8 Equivalent (n1,n2)
Inductive Def6_13_Equivalent : ruleList -> term -> term -> Prop :=
     | Def613_IO : forall newRule pastRules ts1 ts2 t1 t2,
                           (member (IN ts1) (premiseFacts newRule))
                              /\ lastOutputNoInput ts2 pastRules
                                /\ TermsInSamePosition ts1 ts2 t1 t2 ->
                                      Def6_13_Equivalent (newRule::pastRules) t1 t2
     | Def613_SamePosUSF : forall RL t1 t2,
                            (PresentInSamePositionUniqueStateFact RL t1 t2) ->
                                      Def6_13_Equivalent RL t1 t2
     | Def613_SamePosUAF : forall RL t1 t2,
                            ((PresentInSamePositionUAF RL t1 t2)
                             /\
                             ((exists t3 t4, (Def6_13_Equivalent RL t3 t4)
                              /\
                               (not ((eq_term t1 t3) \/ (eq_term t1 t4)
                                        \/ (eq_term t2 t3)\/ (eq_term t2 t4)))))) ->
                                       Def6_13_Equivalent RL t1 t2
     | Def613_EmptyFunc : forall RL fn ,
                          (Def6_13_Equivalent RL (Func fn []) (Func fn []))

     | Def613_FuncList : forall RL fn t1 t2 t3 t4,
                          (Def6_13_Equivalent RL (Func fn (t1::t3)) (Func fn (t2::t4))) ->
                            Def6_13_Equivalent RL (Bterm t1) (Bterm t2) ->
                              Def6_13_Equivalent RL (Func fn t3) (Func fn t4).

Fixpoint isEquivalent (rl:ruleList) (t1:term) (t2:term) : bool :=
  match (Def6_13_Equivalent rl t1 t2) with
      | True => true
  end.

Fixpoint DefequivalentTerm (rl:ruleList) (t1:term) (t2:term) : term :=
  match (isEquivalent rl t1 t2) with
    | true => t2
    | false => t1
  end.

Inductive Def6_15_EquivalenceClass: ruleList -> term -> terms -> Prop :=
  | Eqv_base : forall rl t1, Def6_15_EquivalenceClass rl t1 [t1]
  | Eqv_step : forall rl t1 t2 ts, Def6_13_Equivalent rl t1 t2 -> Def6_15_EquivalenceClass rl t1 ts
                                -> not (member t2 ts) -> Def6_15_EquivalenceClass rl t1 (t2::ts).

Fixpoint isEquivalenceClass (rl:ruleList) (t1:term) (ts:terms) : bool :=
  match (Def6_15_EquivalenceClass rl t1 ts) with
      | True => true
  end.

Lemma equivalentClassProperty : forall rl t ts t1 t2 f1 f2 l1 l2,
    Def6_9_validRuleList rl ->
        Def6_15_EquivalenceClass rl t ts ->
          (member t1 ts) /\ (member t2 ts) ->
            ((eq_term t1 (Bterm (Name (Pub n))) -> ((eq_term t1 t2) \/ (eq_term t2 (Bterm (Var x)))))
            \/ ((eq_term t1 (Func f1 l1 )) -> ((eq_term t2 (Func f2 l2 )) \/ (eq_term t2 (Bterm (Var x)))))).
Lemma Lemma_sigmaOfTermsSameForEquivalenceClass : forall rl rlSetup fs1 tr fs2 sigmaList sigma t t1 t2 ts,
    Def6_9_validRuleList rl ->
          runInOrderSigma rl rlSetup sigmaList fs1 tr fs2 ->
              Def6_15_EquivalenceClass rl t ts ->
                (member t1 ts) /\ (member t2 ts) /\ (member sigma sigmaList) ->
                          (eq_term (applySubTerm sigma t1) (applySubTerm sigma t2)).
Fixpoint termAppearsInFacts (fs: facts) (tm:term) : Prop :=
  match fs with
    | f1::fss => (match f1 with
                        | IN ts => member tm ts
                        | OUT ts => member tm ts
                        | K ts => member tm ts
                        | STATE n ts => member tm ts
                        | FR_P bt => eq_term (Bterm bt) tm
                  end ) \/ termAppearsInFacts fss tm
    | [] => False
  end.

Fixpoint termAppearsInRuleList (rl: ruleList) (tm:term) : Prop :=
  termAppearsInFacts (appendAny (allPremiseFacts rl) (allConclFacts rl)) tm.

Fixpoint termsFromFacts (fs: facts): list term :=
  match fs with
    | f1::fss => appendAny (match f1 with
                        | IN ts => ts
                        | OUT ts => ts
                        | K ts => ts
                        | STATE n ts => ts
                        | FR_P bt => [Bterm bt]
                  end ) (termsFromFacts fss)
    | [] => []
  end.

Fixpoint AllTermsFromRuleList (rl: ruleList) : list term :=
  uniqueTerms (termsFromFacts (appendAny (allPremiseFacts rl) (allConclFacts rl))).

Fixpoint Def_ListArgs (uaf:fact) (r:rule) : terms :=
match (Def6_8_validRule r []) /\ (uniqueArgumentsFact uaf r []) with
    | True => match uaf with
                   | STATE n ts => ts
                   | _ => []
                   end
end.

Definition Def6_16_LinkedEqClasses (rl:ruleList) (e1:terms) (e2:terms) : Prop :=
    forall t1 t2,
        Def6_9_validRuleList rl /\
           Def6_15_EquivalenceClass rl t1 e1 /\
              Def6_15_EquivalenceClass rl t2 e2
                ->
                  exists uaf a1 a2 r,
                            (member a1 e1) /\
                            (member a2 e2) /\
                            (uniqueArgumentsFact uaf r rl) /\
                            (member a1 (Def_ListArgs uaf r)) /\
                            (member a2 (Def_ListArgs uaf r)) /\
                            (member r rl).

Definition termEqTogether (rl:ruleList) (t:term) (t1:term) : terms :=
    if (isEquivalent rl t t1) then uniqueTerms (appendAny [t] [t1]) else [t1].

Fixpoint termsEqTogether (rl:ruleList) (t:term) (ts:terms) : terms :=
 match ts with
    | ts1::tss => uniqueTerms (appendAny (termEqTogether rl t ts1) ( termsEqTogether rl t tss))
    | [] => []
  end.

Fixpoint singleEqClass (rl:ruleList) (t:term) : terms :=
      termsEqTogether rl t (AllTermsFromRuleList rl) .

Fixpoint EqClassesTogether (rl:ruleList) (ts:terms) : list terms :=
 match ts with
    | ts1::tss => (singleEqClass rl ts1)::( EqClassesTogether rl tss)
    | [] => []
  end.

Fixpoint SetofEqClasses (rl:ruleList) : list terms :=
    EqClassesTogether rl (AllTermsFromRuleList rl).

Definition Def_MinEqSet (rl:ruleList) (EqOfEq:list terms) : Prop :=
    forall EqSet eq1 eq2,
        Def6_9_validRuleList rl /\
           eq EqSet (SetofEqClasses rl)
                ->
                 member eq1 (SetofEqClasses rl) /\
                    member eq2 EqOfEq /\
                      Def6_16_LinkedEqClasses rl eq1 eq2.

Definition Def6_18_ProtocolUAFs (rl:ruleList) (EqOfEq:list terms) (uafList:facts): Prop :=
    forall r uaf eqClass,
                Def6_9_validRuleList rl /\
                  Def_MinEqSet rl EqOfEq /\
                    (someCommonElements (Def_ListArgs uaf r) eqClass) /\
                      (member r rl) /\ (member eqClass EqOfEq) /\ (member uaf uafList).

Fixpoint UAFfromSetup (uaf1:fact) (uaf2:fact) : fact :=
 match uaf1, uaf2 with
  | STATE n1 ts, STATE n2 tr => if (beq_name n1 n2) then STATE n2 tr else STATE n1 ts
  | _,_ => uaf1
  end.

Definition UAFsFromSetup (uafListProto:facts) (uafListSetup:facts) (matchedSetupUAFs:list facts) := True.

Definition Def6_19_MatchingSetupUAFs (rl:ruleList) (EqOfEq:list terms) (SetupUAFList:list facts): Prop :=
    forall uafList r rlSetup rlProto uafListSetup,
                Def6_9_validRuleList rl /\
                  eq rl (appendAny [r] (appendAny rlSetup rlProto)) /\
                  eq rl (appendAny rlSetup rlProto) /\
                  Def_MinEqSet rl EqOfEq /\
                    Def6_18_ProtocolUAFs rl EqOfEq uafList /\
                    eq (collectUniqueArgFacts (collectStateFacts (r::rlSetup)) r rlSetup) uafListSetup /\
                      
                    (UAFsFromSetup uafList uafListSetup SetupUAFList).

Global Index A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ other (1 entry)
Library Index A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ other (1 entry)

Global Index

S

stealth [library]



Library Index

S

stealth



Global Index A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ other (1 entry)
Library Index A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ other (1 entry)

This page has been generated by coqdoc