Implementation for third year project, Differential Privacy in Haskell. Robert Murray, 1608035.
HFuzz implements an EDSL that creates a deep embedding for expressions which have their function sensitivity inferred at the type-level. This is then used to apply the Laplace mechanism to provide a differential privacy guarantee. See the project report "Differential Privacy in Haskell" for a full discussion of the project.
Example: importing HFuzz, sum of a list using xsum, guaranteeing
>> run1 xsum [1,2,3,4,5] 0.1
16.311819406922847You can use various exported functions to construct your own programs which you can then use the evaluation functions on to evaluate in a differentially-private manner.
-- requires deferred type errors
cswp = abs (Var @"p" @(PrimTens _ _)) (ifelse (xlet (Var @"a") (Var @"b") (ref (Var @"p")) (xlt (ref (Var @"a")) (ref (Var @"b")))) (ref (Var @"p")) (swapT (XVar (Var @"p"))))cswp is a PrimTens you must import HFuzz.Internal. The above definition requires deferred type erorrs to be enabled as it cannot be determined whether certain type constraints hold at compile time. At runtime we can use helper function checkType to enforce a starting context, and can determine its type by giving it a starting context to build from.
You can access non-differentially private evaluation functions by importing HFuzz.Unsafe.
Our EDSL implements a useful set of functions across the types that we allow. If this is not sufficient to express a desired function, it is possible to extend the functionality of our EDSL by following the same pattern used to implement existing functionality. We can fork the existing library, add a constructor for some function that we want to perform (with appropriate context handling) and add an evaluation case for this. We will look at the toy example of creating a list from a value. Obviously we could define this as the cons of a value to the empty list, but we want to demonstrate how to extend the EDSL's functionality. First we add the corresponding constructor in the Expr data type:
data Expr (xs :: Context) (ys :: Context) (t :: Ty) where
...
XListOfElem :: Expr xs ys (TPrim pt) ->
Expr xs ys (TPrim (PrimList 1 pt))We leave the existing contexts unchanged in the resultant Expr, but change the type to be a list of the type of the value given, with length 1. We must next add a corresponding constructor in UExpr:
data UExpr where
...
UXListOfElem :: UExpr -> UExprNext we add a case to the untype function:
untype :: Expr xs ys t -> UExpr
...
untype (XListOfElem e) = UXListOfElem (untype e)Finally we add a case for the interpretation of UXListOfElem in the evaluate' function:
evaluate' :: RuntimeContext -> UExpr -> Value
...
evaluate' c (UXListOfElem e) = VList ((evaluate' c e) : [])We can follow these four steps to extend the functionality of our EDSL.