521 lines
20 KiB
Coq
521 lines
20 KiB
Coq
(** printing -> #→# *)
|
||
(** printing (policy a b) #a ⇝ b# *)
|
||
|
||
(** Formalisation of "Noninterference, Transitivity, and Channel-Control Security Policies" by J. Rushby
|
||
www.csl.sri.com/papers/csl-92-2/
|
||
*)
|
||
|
||
|
||
(** We use Robbert Krebbers' prelude, see https://github.com/robbertkrebbers/ch2o/tree/master/prelude **)
|
||
Require Import list relations collections fin_collections.
|
||
Parameter FinSet : Type -> Type.
|
||
(** begin hide **)
|
||
Context `{forall A, ElemOf A (FinSet A)}.
|
||
Context `{forall A, Empty (FinSet A)}.
|
||
Context `{forall A, Singleton A (FinSet A)}.
|
||
Context `{forall A, Union (FinSet A)}.
|
||
Context `{forall A, Intersection (FinSet A)}.
|
||
Context `{forall A, Difference (FinSet A)}.
|
||
Context `{forall A, Elements A (FinSet A)}.
|
||
Context `{forall A, Collection A (FinSet A)}. (* TODO: i wrote this line down so that there is a Collection -> SimpleCollection -> JoinSemiLattice instance for FinSet; how come this is not automatically picked up by the next assumption? *)
|
||
Context `{forall A (H : (forall (a b :A), Decision (a = b))), FinCollection A (FinSet A)}.
|
||
(** end hide **)
|
||
|
||
(** * Mealy machines *)
|
||
|
||
(** A Mealy machine is a state machine with labels and outputs on arrows *)
|
||
|
||
Class Mealy (state action out : Type) := {
|
||
initial : state;
|
||
step : state -> action -> state;
|
||
output : state -> action -> out
|
||
}.
|
||
|
||
(** ** Auxiliary functions
|
||
|
||
We define a [run] of a machine [M], which is an extension of
|
||
the [step] function to lists of actions. We use a shortcut
|
||
[do_actions] for running the machine from the [initial] state. *)
|
||
|
||
|
||
Fixpoint run `{Mealy state action out} (s : state) (ls : list action) : state :=
|
||
match ls with
|
||
| nil => s
|
||
| a::tl => run (step s a) tl
|
||
end.
|
||
|
||
Definition do_actions `{Mealy state action out} : list action -> state := run initial.
|
||
|
||
(** The [test] function runs the required list of actions and examines the output of the resulting state on a specified action. *)
|
||
Definition test `{Mealy state action out} (ls : list action) : action -> out := output (do_actions ls).
|
||
|
||
Section Rushby.
|
||
|
||
(** We assume for the rest of the formalisation that we have a Mealy
|
||
machine [M]. Thus, we parameterize our main development module by a machine [M]. *)
|
||
|
||
|
||
Context `{MM : Mealy state action out}.
|
||
|
||
|
||
(** * Security policies *)
|
||
Section Policy.
|
||
|
||
(** In order to define the notion of security, we assume a type [domain] of security domains. Those can be, e.g. clearance levels. For each action [a] we assign a domain [dom a] of that action. For instance, if we interpret domains as clearance levels, the domain of an action can signify the clearance level required to observe/preform the action.
|
||
|
||
A *security policy* is defined to be a reflexive decidable relation on the type of domains. For instance, the policy relation can state that the clearance level [u] is below the clearance level [v]. *)
|
||
Class Policy (domain : Type) := {
|
||
dom : action -> domain;
|
||
|
||
(** Sidenote: I had a lot of issues with Coq not finding relevant
|
||
typeclass instances because the next field was declared as
|
||
[domain_dec : TYPE] instead of [domain_dec :> TYPE]. So we actually
|
||
do need implicit coercions to get automatic resolution of typeclass
|
||
instances. *)
|
||
|
||
domain_dec :> forall (x y : domain), Decision (x = y);
|
||
policy :> relation domain;
|
||
policy_dec :> (forall v w, Decision (policy v w));
|
||
policy_refl :> Reflexive policy
|
||
}.
|
||
|
||
(** TODO: Make this notation span over different sections? *)
|
||
Delimit Scope policy_scope with P.
|
||
Open Scope policy_scope.
|
||
Infix "⇝" := policy (at level 70) : policy_scope.
|
||
|
||
(** Quoting Rushby:
|
||
|
||
<<
|
||
We wish to define security in terms of information flow, so the
|
||
next step is to capture the idea of the "flow of information"
|
||
formally. The key observation is that information can be said to
|
||
flow from a domain [u] to a domain [v] exactly when the acions
|
||
submitted by domain [u] cause the behavior of the system
|
||
percieved by domain [v] to be different from that perceived when
|
||
those actions are not present.
|
||
>>
|
||
|
||
Hence, we define a function [purge] that removes from the given list
|
||
all the actions that are not supposed to "influence" the domain [v].
|
||
*)
|
||
|
||
Fixpoint purge `{Policy domain} (ls : list action) (v : domain) : list action :=
|
||
match ls with
|
||
| [] => []
|
||
| a::tl => if (decide (dom a ⇝ v)) then a::(purge tl v)
|
||
else purge tl v
|
||
end.
|
||
|
||
|
||
(** Then, the system is _secure_ w.r.t. a given policy if for any set
|
||
of actions that can be performed, the system cannot tell the
|
||
difference between preforming the given actions and only performing
|
||
the actions that are supposed to influence the outcome *)
|
||
|
||
Definition security `{Policy domain} := forall (ls : list action) (a : action),
|
||
test ls a = test (purge ls (dom a)) a.
|
||
|
||
|
||
End Policy.
|
||
|
||
(** * View partitions
|
||
|
||
As we have seen, the non-interference notion of security is defined by
|
||
quantifying over all the possible paths of the system. We wish to
|
||
develop techniques for establishing the security property by putting
|
||
conditions on individual state transformations.
|
||
|
||
As a first step, we define a notion of a "view partition", which is an
|
||
equivalence relation on the type of states of the system, siginfying
|
||
that two states are "identitcal" or indistinguishable for a given
|
||
domain.
|
||
|
||
*)
|
||
|
||
Section view_partitions.
|
||
|
||
(** Formally, a view partition is an assignment of an equivalence
|
||
relation [≈{u}] for every domain [u] *)
|
||
|
||
Class ViewPartition (domain : Type) := {
|
||
view_partition :> domain -> relation state;
|
||
view_partition_is_equiv :> forall v, Equivalence (view_partition v)
|
||
}.
|
||
|
||
Notation "S ≈{ U } T" := (view_partition U S T)
|
||
(at level 70, format "S ≈{ U } T") : policy_scope.
|
||
Open Scope policy_scope.
|
||
(** We say that a system is _output consistent_ if for every two
|
||
states [s, t] that are indistinguishable w.r.t. the domain [dom a],
|
||
the output of the system [output s a] is the same as [output t a] *)
|
||
|
||
Class OutputConsistent `{P : Policy domain} `(ViewPartition domain) :=
|
||
output_consistent : (forall a s t, s ≈{dom a} t -> output s a = output t a).
|
||
|
||
(** Our first lemma states that if we have a view partitioned system
|
||
that is output consistent and satisfies
|
||
|
||
[[(do_actions ls) ≈{u} (do_actions (purge ls u))]]
|
||
|
||
then the system is secure. *)
|
||
|
||
(* Lemma 1 *)
|
||
Lemma output_consist_security `{P : Policy domain} `{VP : ViewPartition domain} {OC : @OutputConsistent domain P VP} : (forall ls u,
|
||
(do_actions ls) ≈{u} (do_actions (purge ls u)))
|
||
-> security.
|
||
Proof.
|
||
intros L ls a. apply output_consistent.
|
||
apply (L _ (dom a)).
|
||
Qed.
|
||
|
||
(** Note that the conditions of Lemma [output_consist_security] still
|
||
require us to quantify over all possible paths of the system. We wish
|
||
to replace this condition with the following two "local" conditions.
|
||
|
||
The first condition, stating that the view partitioned system _locally
|
||
respects policy_: if the domain [dom a] is not suppose to interfere
|
||
with the domain [u], then, from the point of view of [u], the states
|
||
[s] and [step s a] are indistinguishable.
|
||
*)
|
||
|
||
Definition locally_respects_policy `{Policy domain} `{ViewPartition domain} := forall a u s,
|
||
¬(policy (dom a) u) -> s ≈{u} (step s a).
|
||
|
||
(** We say that the system is *step consistent*, if the view partition
|
||
is closed under the [step] function. *)
|
||
|
||
Definition step_consistent `{Policy domain} `{ViewPartition domain} := forall a s t u,
|
||
s ≈{u} t -> (step s a) ≈{u} (step t a).
|
||
|
||
(** Given those two conditions we can prove that the system is secure,
|
||
by applying the previous lemma *)
|
||
|
||
(* Theorem 1 *)
|
||
Theorem unwinding `{P: Policy domain} `{VP: ViewPartition domain} `{@OutputConsistent domain P VP} : locally_respects_policy -> step_consistent -> security.
|
||
Proof.
|
||
intros LRP SC. apply output_consist_security.
|
||
assert (forall ls u s t, view_partition u s t -> view_partition u (run s ls) (run t (purge ls u))) as General. (* TODO: a simple generalize would not suffice, because we actually need the s ≈ t assumption *)
|
||
induction ls; simpl; auto.
|
||
intros u s t HI.
|
||
destruct (decide (policy (dom a) u)).
|
||
(* DOESNT WORK (Lexer) : destruct (decide ((dom a) ⇝ u)). *)
|
||
(** Case [(dom a) ~> u] *)
|
||
apply IHls. apply SC; assumption.
|
||
(** Case [(dom a) ~/> u] *)
|
||
apply IHls.
|
||
transitivity s. symmetry. unfold locally_respects_policy in LRP. apply LRP; assumption. assumption.
|
||
unfold do_actions. intros ls u. apply General. reflexivity.
|
||
Qed.
|
||
|
||
End view_partitions.
|
||
|
||
(** * Access control interpretation of the view partition. *)
|
||
|
||
Section ACI.
|
||
|
||
(** In this section we consider a formalisation of the access control mechansisms.
|
||
|
||
We say that the machine has _structured state_ if we have a collection
|
||
of [name]s and [value]s (the latter being decidable), and some sort of
|
||
the memory assigned to each state, which is formally given by the
|
||
[contents] function. For each domain [u] we assign sets [observe u]
|
||
and [alter u] of names that are allowed to be observed and altered,
|
||
respectively, by the domain [u]. *)
|
||
|
||
Class StructuredState (domain : Type) := {
|
||
name : Type;
|
||
value : Type;
|
||
contents : state -> name -> value;
|
||
value_dec :> forall (v1 v2 : value), Decision (v1 = v2);
|
||
observe : domain -> FinSet name;
|
||
alter : domain -> FinSet name
|
||
}.
|
||
|
||
(** This induces the view partition relation as follows: two state [s]
|
||
and [t] are indistinguishable for the given domain, if all the
|
||
observable contents at [s] is the same as the observable content at
|
||
[t] *)
|
||
|
||
Definition RMA_partition `{@StructuredState domain} (u : domain) s t := (forall n, (n ∈ observe u) -> contents s n = contents t n).
|
||
|
||
Transparent RMA_partition.
|
||
|
||
Instance RMA `{@StructuredState domain} : ViewPartition domain := { view_partition := RMA_partition }.
|
||
(* begin hide *)
|
||
intro u. split; unfold RMA_partition.
|
||
(* Reflexivity *) unfold Reflexive. auto.
|
||
(* Symmetry *) unfold Symmetric. intros x y Sy.
|
||
symmetry. apply Sy. assumption.
|
||
(* Transitivity *) unfold Transitive. intros x y z T1 T2 n.
|
||
transitivity (contents y n); [apply T1 | apply T2]; assumption.
|
||
Defined. (* We have to use 'Defined' here instead of 'Qed' so that we can unfold 'RMA' later on *)
|
||
(* end hide *)
|
||
|
||
Hint Resolve RMA.
|
||
|
||
(** ** Reference monitor assumptions *)
|
||
(* TODO: explain those assumptions *)
|
||
Class RefMonAssumptions `{Policy domain} `{StructuredState domain} :=
|
||
{ rma1 : forall (a : action) s t,
|
||
view_partition (dom a) s t -> output s a = output t a
|
||
; rma2 : forall a s t n,
|
||
view_partition (dom a) s t ->
|
||
((contents (step s a) n) ≠ (contents s n)
|
||
∨ (contents (step t a) n) ≠ (contents t n))
|
||
-> contents (step s a) n = contents (step t a) n
|
||
; rma3 : forall a s n,
|
||
contents (step s a) n ≠ contents s n -> n ∈ alter (dom a)
|
||
}.
|
||
|
||
(** If the reference monitor assumptions are satisfied, then the system is output-consistent *)
|
||
Global Instance OC `{RefMonAssumptions}: OutputConsistent RMA.
|
||
exact rma1. Defined.
|
||
|
||
(** The reference mointor assumptions provide the security for the system, if, furthermore, two additional requirements are satisfied:
|
||
|
||
- [u ~> v] implies [observe u ⊆ observe v]; that is, if [u] is supposed to interfere with [v], then [v] can observe at least as much as [u]
|
||
- if [n ∈ alter u] and [n ∈ observe v], then [u ~> v]; that is, if [u] is allowed to alter a location that is observable by [v], then [u] is allowed to interfere with [v]
|
||
*)
|
||
|
||
(* Theorem 2 *)
|
||
Theorem RMA_secutity `{RefMonAssumptions} :
|
||
(forall u v, (policy u v) → observe u ⊆ observe v)
|
||
-> (forall u v n, (n ∈ alter u) → (n ∈ observe v) → (policy u v))
|
||
-> security.
|
||
Proof.
|
||
intros Cond1 Cond2. apply unwinding.
|
||
(** We apply the unwinding theorem, so we have to verify that
|
||
we locally respect policy and that we have step-consistency *)
|
||
unfold locally_respects_policy.
|
||
intros a u s.
|
||
|
||
(** In order to prove that the system locally respects the policy
|
||
relation, we first state the contrapositive, which we can prove
|
||
because the policy relation and type of values are decidable *)
|
||
|
||
assert ((exists n, (n ∈ observe u ∧ (contents s n ≠ contents (step s a) n))) -> policy (dom a) u) as CP.
|
||
intros opH. destruct opH as [n [??]].
|
||
eapply Cond2. eapply rma3. eauto. assumption.
|
||
intros NPolicy.
|
||
unfold view_partition, RMA, RMA_partition.
|
||
(* TODO: why can't decide automatically pick the instance value_dec? *)
|
||
intros. destruct (decide (contents s n = contents (step s a) n)) as [e|Ne]. assumption. exfalso. apply NPolicy. apply CP.
|
||
exists n; split; assumption.
|
||
|
||
(** In order to prove step-consistency we wish to apply the second
|
||
reference monitor assumption. For that we must distinguish three
|
||
cases: (contents (step s a) n ≠ contents s n), (contents (step t a)
|
||
n ≠ contents t n), or if both of the equalities hold *)
|
||
intros a s t u A.
|
||
unfold view_partition, RMA, RMA_partition in *.
|
||
intros n nO.
|
||
destruct (decide (contents (step s a) n = contents s n)) as [E1 | NE1].
|
||
destruct (decide (contents (step t a) n = contents t n)) as [E2 | NE2].
|
||
(* Both equalities hold *)
|
||
rewrite E1, E2. apply A; assumption.
|
||
(* NE2 *)
|
||
(* We use the Second RM assmption to deal with this case *)
|
||
apply rma2. (* for this we have to show that s ~_(dom a) t *)
|
||
unfold view_partition, RMA, RMA_partition.
|
||
intros m L. apply A.
|
||
apply Cond1 with (u:=dom a).
|
||
apply Cond2 with (n:=n); [eapply rma3 | ]; eassumption.
|
||
assumption.
|
||
right. auto.
|
||
(* NE1 case is similar *)
|
||
(* TODO: repetition *)
|
||
apply rma2. (* for this we have to show that s ~_(dom a) t *)
|
||
unfold view_partition, RMA, RMA_partition.
|
||
intros m L. apply A.
|
||
apply Cond1 with (u:=dom a).
|
||
apply Cond2 with (n:=n); [eapply rma3| ]; eassumption.
|
||
assumption.
|
||
left. auto.
|
||
Qed.
|
||
|
||
End ACI.
|
||
|
||
(** * Intransitive security policy *)
|
||
Section Intransitive.
|
||
|
||
(** Auxiliary definitions *)
|
||
Fixpoint sources `{Policy domain} (ls : list action) (d : domain) : FinSet domain :=
|
||
match ls with
|
||
| [] => {[ d ]}
|
||
| a::tl => let src := sources tl d in
|
||
if (decide (exists (v: domain), ((v ∈ src) ∧ (policy (dom a) v))))
|
||
then src ∪ {[ dom a ]} else src
|
||
end.
|
||
|
||
(** The two properties of the [sources] function: it is monotone and [d \in sources ls d] *)
|
||
Lemma sources_mon `{Policy} : forall a ls d, sources ls d ⊆ sources (a::ls) d.
|
||
Proof.
|
||
intros. simpl.
|
||
destruct (decide _); [apply union_subseteq_l |]; auto.
|
||
Qed.
|
||
|
||
Hint Resolve sources_mon.
|
||
|
||
Lemma sources_monotone `{Policy} : forall ls js d, ls `sublist` js → sources ls d ⊆ sources js d.
|
||
Proof.
|
||
intros ls js d M.
|
||
induction M. simpl. reflexivity.
|
||
simpl. destruct (decide (∃ v : domain, v ∈ sources l1 d ∧ policy (dom x) v)); destruct (decide (∃ v : domain, v ∈ sources l2 d ∧ policy (dom x) v)).
|
||
apply union_preserving_r. assumption.
|
||
exfalso. apply n. destruct e as [v [e1 e2]]. exists v; split; try (apply (IHM v)); assumption.
|
||
transitivity (sources l2 d). assumption. apply union_subseteq_l.
|
||
assumption.
|
||
transitivity (sources l2 d); auto.
|
||
Qed.
|
||
|
||
Lemma sources_in `{Policy} : forall ls d, d ∈ sources ls d.
|
||
Proof.
|
||
intros. induction ls; simpl. apply elem_of_singleton_2; auto.
|
||
destruct (decide (∃ v : domain, v ∈ sources ls d ∧ policy (dom a) v)); simpl.
|
||
apply elem_of_union_l. assumption. assumption.
|
||
Qed.
|
||
|
||
Hint Resolve sources_in.
|
||
|
||
Fixpoint ipurge `{Policy} (ls : list action) (d : domain) :=
|
||
match ls with
|
||
| [] => []
|
||
| a::tl => if (decide ((dom a) ∈ sources ls d))
|
||
then a::(ipurge tl d)
|
||
else ipurge tl d
|
||
end.
|
||
|
||
(** The non-interference notion of security for intransitive policies
|
||
is very similar to the transitive case, bu uses the [ipurge] function
|
||
instead of [purge] *)
|
||
|
||
Definition isecurity `{Policy} := forall ls a,
|
||
test ls a = test (ipurge ls (dom a)) a.
|
||
|
||
(** We can prove lemmas similar to the transitive case *)
|
||
|
||
Lemma output_consist_isecurity `{P : Policy domain} `{VP : ViewPartition domain} {OC : @OutputConsistent domain P VP} : (forall ls u,
|
||
view_partition u (do_actions ls) (do_actions (ipurge ls u)))
|
||
-> isecurity.
|
||
Proof.
|
||
unfold isecurity. intros H ls a.
|
||
unfold test.
|
||
apply output_consistent.
|
||
apply (H ls (dom a)).
|
||
Qed.
|
||
|
||
Definition view_partition_general `{ViewPartition domain} (C : FinSet domain) s t := forall (u: domain), u ∈ C -> view_partition u s t.
|
||
|
||
Global Instance view_partition_general_equiv `{ViewPartition domain}:
|
||
forall V, Equivalence (view_partition_general V).
|
||
Proof.
|
||
intro V. split.
|
||
intros x v A. reflexivity.
|
||
intros x y A1 v A2. symmetry. apply (A1 v); assumption.
|
||
intros x y z A1 A2 v A3. transitivity y. apply (A1 v); assumption. apply (A2 v); assumption.
|
||
Qed.
|
||
|
||
Definition weakly_step_consistent `{Policy domain} `{ViewPartition domain} :=
|
||
forall s t u a, view_partition u s t -> view_partition (dom a) s t -> view_partition u (step s a) (step t a).
|
||
|
||
Ltac exists_inside v :=
|
||
let H := fresh "Holds" in
|
||
let nH := fresh "notHolds" in
|
||
destruct (decide _) as [H | []];
|
||
[ try reflexivity | exists v; try auto].
|
||
|
||
Local Hint Resolve sources_mon.
|
||
Local Hint Extern 1 (_ ∈ sources (_::_) _) => eapply sources_mon.
|
||
Local Hint Immediate elem_of_singleton.
|
||
(* Local Hint Extern 1 (_ ∈ {[ _ ]}) => apply elem_of_singleton; trivial. *)
|
||
Local Hint Resolve elem_of_union.
|
||
|
||
(* Lemma 3 *)
|
||
Lemma weakly_step_consistent_general `{Policy domain} `{ViewPartition domain} (s t : state) (a : action) ls (u: domain) : weakly_step_consistent -> locally_respects_policy ->
|
||
view_partition_general (sources (a::ls) u) s t
|
||
-> view_partition_general (sources ls u) (step s a) (step t a).
|
||
Proof.
|
||
intros WSC LRP P v vIn.
|
||
unfold view_partition_general in P.
|
||
unfold locally_respects_policy in LRP.
|
||
destruct (decide (policy (dom a) v)).
|
||
(* Case [dom a ~> v] *)
|
||
apply WSC; apply P. auto.
|
||
(* we need to show that [dom a ∈ sources (a::ls) v] *)
|
||
simpl. exists_inside v. apply elem_of_union. right. auto. apply elem_of_singleton; trivial.
|
||
(* Case [dom a ~/> v] *)
|
||
transitivity s. symmetry. apply LRP; assumption.
|
||
transitivity t. apply P. auto.
|
||
apply LRP; assumption.
|
||
Qed.
|
||
|
||
(* Lemma 4 *)
|
||
Lemma locally_respects_gen `{Policy domain} `{ViewPartition domain} (WSC: weakly_step_consistent) (LRP : locally_respects_policy) s a ls u :
|
||
¬ ((dom a) ∈ sources (a::ls) u) ->
|
||
view_partition_general (sources ls u) s (step s a).
|
||
Proof.
|
||
intros domN v vIn.
|
||
apply LRP. intro.
|
||
(* If [dom a ~> v], then [dom a ∈ sources (a::ls) u], because [v ∈ sources ls u] *) (* again, a clusterfuck *)
|
||
apply domN. simpl.
|
||
exists_inside v; auto. apply elem_of_union; right; apply elem_of_singleton; reflexivity.
|
||
Qed.
|
||
|
||
|
||
(* Lemma 5 *)
|
||
Lemma unwinding_gen `{Policy domain} `{ViewPartition domain} (WSC: weakly_step_consistent) (LRP : locally_respects_policy) s t ls u :
|
||
view_partition_general (sources ls u) s t
|
||
-> view_partition u (run s ls) (run t (ipurge ls u)).
|
||
Proof.
|
||
generalize dependent s.
|
||
generalize dependent t.
|
||
induction ls; intros s t.
|
||
simpl. intro A. apply (A u). apply elem_of_singleton; reflexivity.
|
||
intro VPG. simpl. unfold sources. fold (sources (a::ls) u).
|
||
|
||
destruct (decide _).
|
||
(** Case [dom a ∈ sources (a::ls) u] *)
|
||
simpl. apply IHls. apply weakly_step_consistent_general; auto.
|
||
(** Case [dom a ∉ sources (a::ls) u] *)
|
||
apply IHls. symmetry. transitivity t.
|
||
- intros v vIn. symmetry. apply VPG. apply sources_mon; exact vIn.
|
||
- apply locally_respects_gen; try(assumption).
|
||
Qed.
|
||
|
||
|
||
Theorem unwinding_intrans `{P : Policy domain} `{VP : ViewPartition domain}
|
||
`{OC : @OutputConsistent domain P VP} (WSC : weakly_step_consistent) (LRP : locally_respects_policy) : isecurity.
|
||
Proof.
|
||
apply output_consist_isecurity.
|
||
intros.
|
||
apply unwinding_gen; try assumption.
|
||
reflexivity.
|
||
Qed.
|
||
|
||
Theorem rma_secure_intransitive `{RefMonAssumptions} : (forall u v n, n ∈ alter u -> n ∈ observe v -> policy u v) -> isecurity.
|
||
Proof. intro policyA.
|
||
apply @unwinding_intrans with (VP:=RMA). exact rma1.
|
||
intros s t u a A1 A2.
|
||
unfold view_partition. unfold RMA_partition; simpl. intros n L.
|
||
destruct (decide (contents (step s a) n = contents s n)) as [E1 | NE1].
|
||
destruct (decide (contents (step t a) n = contents t n)) as [E2 | NE2].
|
||
(* Case [contents (step s a) n = contents s n /\ contents (step t a) n = contents t n] *)
|
||
rewrite E1, E2. apply A1; assumption.
|
||
(* Case [contents (step t a) n ≠ contents t n] *)
|
||
apply rma2; [ | right]; assumption.
|
||
(* Case [contents (step s a) n ≠ contents s n] *)
|
||
apply rma2; [ | left]; assumption.
|
||
|
||
intros a u s A.
|
||
assert ((exists n, (n ∈ observe u ∧ (contents s n ≠ contents (step s a) n))) -> policy (dom a) u) as CP.
|
||
intros opH. destruct opH as [n [??]].
|
||
eapply policyA. eapply rma3. eauto. assumption.
|
||
intros n L. destruct (decide (contents s n = contents (step s a) n)). assumption. exfalso. apply A.
|
||
apply CP. exists n. auto.
|
||
Qed.
|
||
|
||
End Intransitive.
|
||
|
||
End Rushby.
|