lmonad-0.1.0.0: src/LMonad/Label/DisjunctionCategory.hs
-- Some work derived from [LIO](http://hackage.haskell.org/package/lio-eci11), copyrighted under GPL.
--
-- Modifications by James Parker in 2014.
module LMonad.Label.DisjunctionCategory where
import Data.Set (Set)
import qualified Data.Set as Set
import Prelude
import LMonad
-- TODO: Add bloom filter?? It's probably not worth it with principals usually on the order of 10.
-- data Ord p => Disjunction p = Disjunction (Set p)
type Disjunction p = Set p
type Conjunction p = Set (Disjunction p)
-- | Disjunction category label of principals in conjunction normal form.
data Ord p => DCLabel p = DCLabel {
dcConfidentiality :: Conjunction p
, dcIntegrity :: Conjunction p
}
deriving (Eq, Show)
-- | Convenience function to convert a principal to confidentiality and integrity DCLabel.
dcSingleton :: Ord p => p -> DCLabel p
dcSingleton p =
let conj = Set.singleton (Set.singleton p) in
DCLabel conj conj
-- | Convenience function to convert a principal to confidentiality DCLabel.
dcConfidentialitySingleton :: Ord p => p -> DCLabel p
dcConfidentialitySingleton p = DCLabel (Set.singleton (Set.singleton p)) $ Set.singleton Set.empty
-- | Convenience function to convert a principal to integrity DCLabel.
dcIntegritySingleton :: Ord p => p -> DCLabel p
dcIntegritySingleton p = DCLabel Set.empty (Set.singleton (Set.singleton p))
-- O(n)
forall :: (a -> Bool) -> Set a -> Bool
forall pred = Set.foldl' (\acc el -> acc && (pred el)) True
-- O(n)
exists :: (a -> Bool) -> Set a -> Bool
exists pred = Set.foldl' (\acc el -> acc || (pred el)) False
-- Equivalent to implies for disjunctions. O(n + m)
-- TODO: Add bloom filters here??? Would reduce to O(1) for most lookups.
subset :: Ord p => Disjunction p -> Disjunction p -> Bool
subset = Set.isSubsetOf
-- | Computes logical implies. Assumes CNF. O(n * m * (n' + m'))
implies :: Ord p => Conjunction p -> Conjunction p -> Bool
implies a b =
-- forall b. exists a. a is a subset of b
forall (\elB -> exists (\elA -> subset elA elB) a) b
-- O(n * (n' + m))
conjunctionInsertDisjunction :: Ord p => Conjunction p -> Disjunction p -> Conjunction p
conjunctionInsertDisjunction conj disj =
-- Check if any element in acc implies disjunction.
if exists (`subset` disj) conj then
conj
else
-- Remove any elements in acc where that element is implied by the disjunction, and insert disjunction.
Set.insert disj $ Set.filter (\el -> not (disj `subset` el)) conj
-- O(m * n * (n' + m')) ??
conjunctionAnd :: Ord p => Conjunction p -> Conjunction p -> Conjunction p
conjunctionAnd = Set.foldl' conjunctionInsertDisjunction
-- O(m * n * ()) ???
-- TODO: Optimize this more??? XXX
conjunctionOr :: Ord p => Conjunction p -> Conjunction p -> Conjunction p
conjunctionOr conj1 = Set.foldl' (\acc disj2 -> Set.foldl' (\acc disj1 ->
conjunctionInsertDisjunction acc (Set.union disj1 disj2)
) acc conj1) Set.empty
instance Ord p => Label (DCLabel p) where
-- Meet
glb (DCLabel c1 i1) (DCLabel c2 i2) =
DCLabel (c1 `conjunctionOr` c2) (i1 `conjunctionAnd` i2)
-- Join
lub (DCLabel c1 i1) (DCLabel c2 i2) =
DCLabel (c1 `conjunctionAnd` c2) (i1 `conjunctionOr` i2)
-- Flow to
canFlowTo (DCLabel c1 i1) (DCLabel c2 i2) =
c2 `implies` c1 && i1 `implies` i2
-- Bottom
bottom = DCLabel Set.empty $ Set.singleton Set.empty