lol-apps-0.1.0.0: examples/SymmSHE/SimpleSHE.hs
{-# LANGUAGE
DataKinds, -- so we can use GHC.TypeLits
NoImplicitPrelude, -- an alternate Prelude is imported from Crypto.Lol
PolyKinds,
RebindableSyntax, -- since we use an alternate Prelude, this lets GHC read literals, etc
ScopedTypeVariables,
TemplateHaskell -- provides a simple way to construct cyclotomic indices and prime-power moduli
#-}
import Crypto.Lol hiding ((^),CT)
import qualified Crypto.Lol as Lol
import Crypto.Lol.Applications.SymmSHE
import Algebra.Ring ((^)) -- easier to use with the TH commands below
import Math.NumberTheory.Primes.Testing (isPrime) -- used to generate "good" moduli
import Control.Monad.Random (getRandom)
-- an infinite list of primes greater than `lower` and congruent to 1 mod m
-- useful for generating moduli for CTZq below
goodQs :: (IntegralDomain i, ToInteger i) => i -> i -> [i]
goodQs m lower = checkVal (lower + ((m-lower) `mod` m) + 1)
where checkVal v = if (isPrime (fromIntegral v :: Integer))
then v : checkVal (v+m)
else checkVal (v+m)
-- PTIndex must divide CTIndex
type PTIndex = F128
-- Crypto.Lol includes Factored types F1..F512
-- for cyclotomic indices outside this range,
-- we provide a TH wrapper.
-- TH to constuct the cyclotomic index 11648
type CTIndex = $(fType $ 2^7 * 7 * 13)
-- to use crtSet (for example, when ring switching), the plaintext modulus must be a PrimePower (ZPP constraint)
-- Crypto.Lol exports PP2,PP4,...,PP128 as well as some prime powers for 3,5,7, and 11.
-- See Crypto.Lol.Factored. Alternately, an arbitrary prime power p^e can be constructed with
-- the TH $(ppType (p,e))
-- for applications that don't use crtSet, PT modulus can be a TypeLit.
type PTZq = ZqBasic PP8 Int64
-- uses GHC.TypeLits as modulus, and Int64 as repr (needed to use with CT backend)
-- modulus doesn't have to be "good", but "good" moduli are much faster
type Zq q = ZqBasic q Int64 -- uses PolyKinds
type CTZq1 = Zq 536937857
type CTZq2 = (CTZq1, Zq 536972801)
type CTZq3 = (CTZq2, Zq 537054337)
-- Tensor backend, either Repa (RT) or C (CT)
type T = Lol.CT -- can also use RT
type KSGad = TrivGad -- can also use (BaseBGad 2), for example
type PTRing = Cyc T PTIndex PTZq
type CTRing1 = CT PTIndex PTZq (Cyc T CTIndex CTZq1)
type CTRing2 = CT PTIndex PTZq (Cyc T CTIndex CTZq2)
type SKRing = Cyc T CTIndex (LiftOf PTZq)
main :: IO ()
main = do
plaintext <- getRandom
sk :: SK SKRing <- genSK (1 :: Double)
-- encrypt with a single modulus
ciphertext :: CTRing1 <- encrypt sk plaintext
let ct1 = 2*ciphertext
pt1 = decrypt sk ct1
print $ "Test1: " ++ (show $ 2*plaintext == pt1)
kswq <- proxyT (keySwitchQuadCirc sk) (Proxy::Proxy (KSGad, CTZq2))
let ct2 = kswq $ ciphertext*ciphertext
pt2 = decrypt sk ct2
-- note: this requires a *LARGE* CT modulus to succeed
print $ "Test2: " ++ (show $ plaintext*plaintext == pt2)
-- so we support using *several* small moduli:
kswq' <- proxyT (keySwitchQuadCirc sk) (Proxy::Proxy (KSGad, CTZq3))
ciphertext' :: CTRing2 <- encrypt sk plaintext
let ct3 = kswq' $ ciphertext' * ciphertext'
-- the CT modulus of ct3 is a ring product, which can't be lifted to a fixed size repr
-- so use decryptUnrestricted instead
pt3 = decryptUnrestricted sk ct3
ct3' = rescaleLinearCT ct3 :: CTRing1
-- after rescaling, ct3' has a single modulus, so we can use normal decrypt
pt3' = decrypt sk ct3'
print $ "Test3: " ++ (show $ (plaintext*plaintext == pt3) && (pt3' == pt3))