lol-apps-0.2.0.0: tests/SHETests.hs
{-|
Module : SHETests
Description : Tests for SymmSHE.
Copyright : (c) Eric Crockett, 2011-2017
Chris Peikert, 2011-2017
License : GPL-2
Maintainer : ecrockett0@email.com
Stability : experimental
Portability : POSIX
Tests for SymmSHE.
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-}
module SHETests (sheTests, decTest, modSwPTTest, ksTests, twemTests, tunnelTests) where
import Control.Applicative
import Control.Monad
import Control.Monad.Random
import Crypto.Lol
import Crypto.Lol.Applications.SymmSHE
import Crypto.Lol.Tests
import Crypto.Lol.Utils.ShowType
import qualified Test.Framework as TF
sheTests :: forall t m m' zp zq . (_)
=> Proxy '(m,m',zp,zq) -> Proxy t -> TF.Test
sheTests _ _ =
let ptmr = Proxy::Proxy '(t,m,m',zp,zq)
in testGroup (showType ptmr) $ ($ ptmr) <$> [
genTestArgs "DecU . Enc" prop_encDecU,
genTestArgs "AddPub" prop_addPub,
genTestArgs "MulScal" prop_mulScal,
genTestArgs "MulPub" prop_mulPub,
genTestArgs "ScalarPub" prop_addScalar,
genTestArgs "CTAdd" prop_ctadd,
genTestArgs "CTAdd2" prop_ctadd2,
genTestArgs "CTMul" prop_ctmul,
genTestArgs "CT zero" prop_ctzero,
genTestArgs "CT one" prop_ctone]
-- zq must be liftable
decTest :: forall t m m' zp zq . (_)
=> Proxy '(m,m',zp,zq) -> Proxy t -> TF.Test
decTest _ _ =
let ptmr = Proxy::Proxy '(t,m,m',zp,zq)
in testGroup (showType ptmr)
[genTestArgs "Dec . Enc" prop_encDec ptmr]
modSwPTTest :: forall t m m' zp zp' zq . (_)
=> Proxy '(m,m',zp,zp',zq) -> Proxy t -> TF.Test
modSwPTTest _ _ =
let ptmr = Proxy::Proxy '(t,m,m',zp,zp',zq)
in testGroup (showType ptmr)
[genTestArgs "ModSwitch PT" prop_modSwPT ptmr]
ksTests :: forall t m m' zp zq zq' gad . (_)
=> Proxy '(m,m',zp,zq,zq') -> Proxy gad -> Proxy t -> TF.Test
ksTests _ _ _ =
let ptmr = Proxy::Proxy '(t,m,m',zp,zq,zq',gad)
in testGroup (showType ptmr) $ ($ ptmr) <$> [
genTestArgs "KSLin" prop_ksLin,
genTestArgs "KSQuad" prop_ksQuad]
twemTests :: forall t r r' s s' zp zq . (_)
=> Proxy '(r,r',s,s',zp,zq) -> Proxy t -> TF.Test
twemTests _ _ =
let ptmr = Proxy::Proxy '(t,r,r',s,s',zp,zq)
in testGroup (showType ptmr) [
genTestArgs "Embed" prop_ctembed ptmr,
genTestArgs "Twace" prop_cttwace ptmr]
tunnelTests :: forall t r r' s s' zp zq gad . (_)
=> Proxy '(r,r',s,s',zp,zq) -> Proxy gad -> Proxy t -> TF.Test
tunnelTests _ _ _ =
let ptmr = Proxy::Proxy '(t,r,r',s,s',zp,zq,gad)
in testGroup (showType ptmr)
[genTestArgs "Tunnel" prop_ringTunnel ptmr]
prop_encDecU :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> PT (Cyc t m zp) -> SK (Cyc t m' z) -> Test '(t,m,m',zp,zq)
prop_encDecU x sk = testIO $ do
y :: CT m zp (Cyc t m' zq) <- encrypt sk x
let x' = decryptUnrestricted sk $ y
return $ x == x'
prop_addPub :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> Cyc t m zp
-> PT (Cyc t m zp)
-> SK (Cyc t m' z)
-> Test '(t,m,m',zp,zq)
prop_addPub a pt sk = testIO $ do
ct :: CT m zp (Cyc t m' zq) <- encrypt sk pt
let ct' = addPublic a ct
pt' = decryptUnrestricted sk ct'
return $ pt' == (a+pt)
prop_mulScal :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> zp
-> PT (Cyc t m zp)
-> SK (Cyc t m' z)
-> Test '(t,m,m',zp,zq)
prop_mulScal a pt sk = testIO $ do
ct :: CT m zp (Cyc t m' zq) <- encrypt sk pt
let ct' = mulScalar a ct
pt' = decryptUnrestricted sk ct'
return $ pt' == ((scalarCyc a) * pt)
prop_mulPub :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> Cyc t m zp
-> PT (Cyc t m zp)
-> SK (Cyc t m' z)
-> Test '(t,m,m',zp,zq)
prop_mulPub a pt sk = testIO $ do
ct :: CT m zp (Cyc t m' zq) <- encrypt sk pt
let ct' = mulPublic a ct
pt' = decryptUnrestricted sk ct'
return $ pt' == (a*pt)
prop_addScalar :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> zp -> PT (Cyc t m zp) -> SK (Cyc t m' z) -> Test '(t,m,m',zp,zq)
prop_addScalar c pt sk = testIO $ do
ct :: CT m zp (Cyc t m' zq) <- encrypt sk pt
let ct' = addScalar c ct
pt' = decryptUnrestricted sk ct'
return $ pt' == ((scalarCyc c)+pt)
prop_ctadd :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> PT (Cyc t m zp)
-> PT (Cyc t m zp)
-> SK (Cyc t m' z)
-> Test '(t,m,m',zp,zq)
prop_ctadd pt1 pt2 sk = testIO $ do
ct1 :: CT m zp (Cyc t m' zq) <- encrypt sk pt1
ct2 :: CT m zp (Cyc t m' zq) <- encrypt sk pt2
let ct' = ct1 + ct2
pt' = decryptUnrestricted sk ct'
return $ pt1+pt2 == pt'
-- tests adding with different scale values
prop_ctadd2 :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> PT (Cyc t m zp)
-> PT (Cyc t m zp)
-> SK (Cyc t m' z)
-> Test '(t,m,m',zp,zq)
prop_ctadd2 pt1 pt2 sk = testIO $ do
ct1 :: CT m zp (Cyc t m' zq) <- encrypt sk pt1
ct2 :: CT m zp (Cyc t m' zq) <- encrypt sk pt2
-- no-op to induce unequal scale values
let ct' = ct1 + (modSwitchPT ct2)
pt' = decryptUnrestricted sk ct'
return $ pt1+pt2 == pt'
prop_ctmul :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> PT (Cyc t m zp)
-> PT (Cyc t m zp)
-> SK (Cyc t m' z)
-> Test '(t,m,m',zp,zq)
prop_ctmul pt1 pt2 sk = testIO $ do
ct1 :: CT m zp (Cyc t m' zq) <- encrypt sk pt1
ct2 :: CT m zp (Cyc t m' zq) <- encrypt sk pt2
let ct' = ct1 * ct2
pt' = decryptUnrestricted sk ct'
return $ pt1*pt2 == pt'
prop_ctzero :: forall t m m' z zp (zq :: *) . (z ~ LiftOf zp, Fact m, _)
=> SK (Cyc t m' z) -> Test '(t,m,m',zp,zq)
prop_ctzero sk =
let z = decryptUnrestricted sk (zero :: CT m zp (Cyc t m' zq))
in test $ zero == z
prop_ctone :: forall t m m' z zp (zq :: *) . (z ~ LiftOf zp, Fact m, _)
=> SK (Cyc t m' z) -> Test '(t,m,m',zp,zq)
prop_ctone sk =
let z = decryptUnrestricted sk (one :: CT m zp (Cyc t m' zq)) :: Cyc t m zp
in test $ one == z
prop_encDec :: forall t m m' z zp zq . (z ~ LiftOf zp, _)
=> SK (Cyc t m' z) -> Cyc t m zp -> Test '(t,m,m',zp,zq)
prop_encDec sk x = testIO $ do
y :: CT m zp (Cyc t m' zq) <- encrypt sk x
let x' = decrypt sk $ y
return $ x == x'
prop_modSwPT :: forall t m m' z zp (zp' :: *) (zq :: *) . (z ~ LiftOf zp, _)
=> PT (Cyc t m zp) -> SK (Cyc t m' z) -> Test '(t,m,m',zp,zp',zq)
prop_modSwPT pt sk = testIO $ do
y :: CT m zp (Cyc t m' zq) <- encrypt sk pt
let p = proxy modulus (Proxy::Proxy zp)
p' = proxy modulus (Proxy::Proxy zp')
z = (fromIntegral $ p `div` p')*y
x = decryptUnrestricted sk z
y' = modSwitchPT z :: CT m zp' (Cyc t m' zq)
x'' = decryptUnrestricted sk y'
return $ x'' == rescaleCyc Dec x
prop_ksLin :: forall t m m' z zp (zq :: *) (zq' :: *) (gad :: *) . (z ~ LiftOf zp, _)
=> PT (Cyc t m zp) -> SK (Cyc t m' z) -> SK (Cyc t m' z) -> Test '(t,m,m',zp,zq,zq',gad)
prop_ksLin pt skin skout = testIO $ do
ct <- encrypt skin pt
kslHint :: KSLinearHint gad (Cyc t m' zq') <- ksLinearHint skout skin
let ct' = keySwitchLinear kslHint ct :: CT m zp (Cyc t m' zq)
pt' = decryptUnrestricted skout ct'
return $ pt == pt'
prop_ksQuad :: forall t m m' z zp zq (zq' :: *) (gad :: *) . (z ~ LiftOf zp, _)
=> PT (Cyc t m zp) -> PT (Cyc t m zp) -> SK (Cyc t m' z) -> Test '(t,m,m',zp,zq,zq',gad)
prop_ksQuad pt1 pt2 sk = testIO $ do
ct1 :: CT m zp (Cyc t m' zq) <- encrypt sk pt1
ct2 <- encrypt sk pt2
ksqHint :: KSQuadCircHint gad (Cyc t m' zq') <- ksQuadCircHint sk
let ct' = keySwitchQuadCirc ksqHint $ ct1*ct2
ptProd = pt1*pt2
pt' = decryptUnrestricted sk ct'
return $ ptProd == pt'
prop_ctembed :: forall t r r' s s' z zp (zq :: *) . (z ~ LiftOf zp, Fact s', Fact s, _)
=> PT (Cyc t r zp) -> SK (Cyc t r' z) -> Test '(t,r,r',s,s',zp,zq)
prop_ctembed pt sk =testIO $ do
ct :: CT r zp (Cyc t r' zq) <- encrypt sk pt
let ct' = embedCT ct :: CT s zp (Cyc t s' zq)
pt' = decryptUnrestricted (embedSK sk) ct'
return $ embed pt == pt'
-- CT must be encrypted with key from small ring
prop_cttwace :: forall t r r' s s' z zp (zq :: *) . (z ~ LiftOf zp, Fact r, _)
=> PT (Cyc t s zp) -> SK (Cyc t r' z) -> Test '(t,r,r',s,s',zp,zq)
prop_cttwace pt sk = testIO $ do
ct :: CT s zp (Cyc t s' zq) <- encrypt (embedSK sk) pt
let ct' = twaceCT ct :: CT r zp (Cyc t r' zq)
pt' = decryptUnrestricted sk ct'
return $ twace pt == pt'
prop_ringTunnel :: forall t e r s e' r' s' z zp zq gad .
(GenTunnelInfoCtx t e r s e' r' s' z zp zq gad,
TunnelCtx t r s e' r' s' zp zq gad,
EncryptCtx t r r' z zp zq,
DecryptUCtx t s s' z zp zq,
Random zp, Eq zp,
e ~ FGCD r s, Fact e)
=> PT (Cyc t r zp) -> SK (Cyc t r' z) -> SK (Cyc t s' z) -> Test '(t,r,r',s,s',zp,zq,gad)
prop_ringTunnel x skin skout = testIO $ do
let totr = proxy totientFact (Proxy::Proxy r)
tote = proxy totientFact (Proxy::Proxy e)
basisSize = totr `div` tote
-- choose a random linear function of the appropriate size
bs :: [Cyc t s zp] <- replicateM basisSize getRandom
let f = linearDec bs \\ (gcdDivides (Proxy::Proxy r) (Proxy::Proxy s)) :: Linear t zp e r s
expected = evalLin f x \\ (gcdDivides (Proxy::Proxy r) (Proxy::Proxy s))
y :: CT r zp (Cyc t r' zq) <- encrypt skin x
hints :: TunnelInfo gad t e r s e' r' s' zp zq <- tunnelInfo f skout skin
let y' = tunnelCT hints y :: CT s zp (Cyc t s' zq)
actual = decryptUnrestricted skout y' :: Cyc t s zp
return $ expected == actual