From a2e3a80c61bdd1aa9ef4f63029bd032a8b3345aa Mon Sep 17 00:00:00 2001 From: Yuri Tatishchev Date: Wed, 25 Feb 2026 11:19:26 -0800 Subject: [PATCH] lab07: init --- lab07/facetedValues.lhs | 87 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 lab07/facetedValues.lhs diff --git a/lab07/facetedValues.lhs b/lab07/facetedValues.lhs new file mode 100644 index 0000000..6a7815b --- /dev/null +++ b/lab07/facetedValues.lhs @@ -0,0 +1,87 @@ +> import Control.Applicative +> import qualified Data.Set as Set + +Faceted values are an **information flow mechanism**. Specifically, they are +designed to store differing views of data. For more technical details, see +"Multiple Facets for Dynamic Information Flow", available at +https://users.soe.ucsc.edu/~cormac/papers/popl12b.pdf. + +Authorized viewers should see the real value, and other viewers should see +dummy data instead. To do this, we need to represent the security level +of a piece of data. We'll define labels to encapsulate this information, +represented as strings. + +> type Label = String + +A user may have many security privileges, so a "view" of a faceted value can +be represented as a set of labels. + +> type View = Set.Set Label + +A faceted value can be either a raw (that is, unfaceted) value, or it can +be node containing two nested faceted values, with a label tracking who is +allowed to view the contents. + +> data FacetedValue a = Raw a +> | Facet Label (FacetedValue a) (FacetedValue a) + +Note that we do **not** derive Show. Instead, code must pass its +authorizations to a view function, which will return a non-faceted value. +If any label is not in the set, it is assumed that the view is not authorized. + +> view :: View -> FacetedValue a -> a +> view _ (Raw x) = x +> view labels (Facet k auth unauth) = +> if Set.member k labels then +> view labels auth +> else +> view labels unauth + +We can apply operations to a faceted value, in which case the action should +be applied to every element of the tree. As a review of the last lab, define +fmap for FacetedValues. + +> instance Functor FacetedValue where +> fmap f v = error "Your code here" + + +The following function gives an example of how a FacetedValue can be used. +In this case, a customer's Visa credit card is hidden from other viewers. +If someone with other permissions, say with the ability to view details +about the customer's Mastercard, they will instead be presented with the +default view of 0. Even if someone tries to do some calculations on the +credit card in the hope of revealing information, a consistent view will be +presented to the observer. + +> testFmap = do +> let creditCard = Facet "visa" (Raw 4111111111111111) (Raw 0) +> ccPlusOne = fmap (+1) creditCard +> putStrLn "Credit card views:" +> print $ view (Set.fromList ["visa"]) ccPlusOne -- Should print 4111111111111112 +> print $ view (Set.fromList ["mastercard"]) ccPlusOne -- Should print 1 + + + +While this works, what happens if we want two faceted values to be combined? +In order to make that work, we need need to add support for Applicative Functors. +Define the behavior of the Functor below + +> instance Applicative FacetedValue where +> pure = error "Your code here" +> fv1 <*> fv2 = error "Your code here" + + +The code below gives an example of how this might come up. If code authorized +to read your Bank of America account details runs on the same machine as code +to read your Wells Fargo details, **neither** will be allowed to read your +combined balance. However, you as the customer can see the true values. + +> testApplicative = do +> let bofaBalance = Facet "Bank of America" (Raw 44) (Raw 0) +> wellsFargoBalance = Facet "Wells Fargo" (Raw 122) (Raw 0) +> combinedBalance = (+) <$> bofaBalance <*> wellsFargoBalance +> print $ view (Set.fromList []) combinedBalance -- Should print 0 +> print $ view (Set.fromList ["Bank of America"]) combinedBalance -- Should print 44 +> print $ view (Set.fromList ["Wells Fargo"]) combinedBalance -- Should print 122 +> print $ view (Set.fromList ["Bank of America", "Wells Fargo"]) combinedBalance -- Should print 166 +