packages feed

lol-0.0.1.0: test-suite/SHETests.hs

{-# LANGUAGE ScopedTypeVariables, NoImplicitPrelude, RebindableSyntax, 
             DataKinds, TypeOperators, NoMonomorphismRestriction, NoMonoLocalBinds,
             ConstraintKinds, TypeFamilies, FlexibleContexts, PartialTypeSignatures, 
             RankNTypes, MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, 
             RebindableSyntax, GADTs, PolyKinds, KindSignatures #-}

module SHETests (sheTests) where

import TestTypes

import Control.Applicative hiding ((<$$>))
import Control.Monad
import Control.Monad.Random

import Crypto.Lol.LatticePrelude hiding (lift)
import Crypto.Lol.Cyclotomic.Cyc
import Crypto.Lol.Applications.SymmSHE
import Crypto.Lol.CRTrans
import Crypto.Lol.Gadget
import Crypto.Lol.Cyclotomic.Linear

import Crypto.Lol.Cyclotomic.Tensor.RepaTensor
import qualified Crypto.Lol.Cyclotomic.Tensor.CTensor as CT
import Crypto.Lol.Cyclotomic.Tensor.CTensor hiding (CT)
import Crypto.Lol.Types.ZqBasic

import Data.Array.Repa.Eval (Elt)
import Data.Type.Natural hiding (zero,one)
import Data.Typeable
import Data.Vector.Unboxed (Unbox)
import Data.Vector.Storable (Storable)

import Test.Framework
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck hiding (generate,output)
import Test.QuickCheck.Monadic (monadicIO, assert)

v = 1 :: Double

sheTests = 
  [testGroup "Tunnel" $ tunnelTests,
   testGroup "Dec . Enc (Unrestricted)" $ groupCEnc $ wrapEnc prop_encDec,
   testGroup "Dec . Enc (MSD)" $ groupCEnc $ wrapEnc prop_encDec_MSD,
   testGroup "AddPub" $ groupCEnc $ wrapEnc prop_addPub,
   testGroup "MulPub" $ groupCEnc $ wrapEnc prop_mulPub,
   testGroup "ScalarPub" $ groupCEnc $ wrapScalar prop_addScalar,
   testGroup "CTAdd" $ groupCEnc $ wrapMath prop_ctadd,
   testGroup "CTMul" $ groupCEnc $ wrapMath prop_ctmul,
   testGroup "CT zero" $ groupCEnc $ wrapConst prop_ctzero,
   testGroup "CT one" $ groupCEnc $ wrapConst prop_ctone,
   testGroup "ModSwPT" modSwPTTests,
   testGroup "KSLin" $ groupCKS $ wrapKSLin prop_ksLin,
   testGroup "KSQuad" $ groupCKS $ wrapKSQuad prop_ksQuad,
   testGroup "Embed" $ groupCTwEm $ wrapEm prop_ctembed,
   testGroup "Twace" $ groupCTwEm $ wrapTw prop_cttwace
  ]

type EncDecCtx c m m' zp zq =
  (GenSKCtx c m (LiftOf zp) Double,
   EncryptCtx c m m' (LiftOf zp) zp zq,
   -- constraints from decryptUnrestricted
   ToSDCtx c m' zp zq, Lift' zq, Reduce (LiftOf zq) zp)

prop_encDec :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq) 
  => Proxy '(m', zq) -> Cyc c m zp -> Property
prop_encDec _ x = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk x
  let x' = decryptUnrestricted sk $ y
  assert $ x == x'

prop_encDec_MSD :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq) 
  => Proxy '(m', zq) -> Cyc c m zp -> Property
prop_encDec_MSD _ x = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk x
  let x' = decryptUnrestricted sk $ toMSD y
  assert $ x == x'

prop_addPub :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq)
  => Proxy '(m', zq) -> Cyc c m zp -> Property
prop_addPub _ x = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk x
  let y' = addPublic x y
      x' = decryptUnrestricted sk y'
  assert $ x' == (x+x)

prop_mulPub :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq)
  => Proxy '(m', zq) -> Cyc c m zp -> Property
prop_mulPub _ x = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk x
  let y' = mulPublic x y
      x' = decryptUnrestricted sk y'
  assert $ x' == (x*x)

prop_addScalar :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq)
  => Proxy '(m', zq) -> zp -> Cyc c m zp -> Property
prop_addScalar _ s x = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk x
  let y' = addScalar s y
      x' = decryptUnrestricted sk y'
  assert $ x' == ((scalarCyc s)+x)

prop_ctadd :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq) 
  => Proxy '(m', zq) -> Cyc c m zp -> Cyc c m zp -> Property
prop_ctadd _ x1 x2 = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y1 :: CT m zp (Cyc c m' zq) <- encrypt sk x1
  y2 :: CT m zp (Cyc c m' zq) <- encrypt sk x2
  let y' = y1+y2
      x' = decryptUnrestricted sk y'
  assert $ x1+x2 == x'

prop_ctmul :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq)
  => Proxy '(m', zq) -> Cyc c m zp -> Cyc c m zp -> Property
prop_ctmul _ x1 x2 = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y1 :: CT m zp (Cyc c m' zq) <- encrypt sk x1
  y2 :: CT m zp (Cyc c m' zq) <- encrypt sk x2
  let y' = y1*y2
      x' = decryptUnrestricted sk y'
  assert $ x1*x2 == x'

prop_ctzero :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq) 
  => Proxy '(m', zq) -> Proxy (Cyc c m zp) -> Property
prop_ctzero _ _ = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  let z = decryptUnrestricted sk (zero :: CT m zp (Cyc c m' zq))
  assert $ zero == z

prop_ctone :: forall m zp c m' zq . 
  (EncDecCtx c m m' zp zq)
  => Proxy '(m', zq) -> Proxy (Cyc c m zp) -> Property
prop_ctone _ _ = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  let z = decryptUnrestricted sk (one :: CT m zp (Cyc c m' zq))
  assert $ one == z

type EncDecWrapCtx c m m' zp zq =
  (EncDecCtx c m m' zp zq, Show (Cyc c m zp), Arbitrary (c m zp), Show zp, Arbitrary zp)

wrapEnc :: (EncDecWrapCtx c m m' zp zq)
  => (Proxy '(m', zq) -> Cyc c m zp -> Property) 
     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property
wrapEnc f _ _ = property $ f Proxy

wrapScalar :: (EncDecWrapCtx c m m' zp zq)
  => (Proxy '(m', zq) -> zp -> Cyc c m zp -> Property)
     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property
wrapScalar f _ _ = property $ f Proxy

wrapMath :: (EncDecWrapCtx c m m' zp zq)
  => (Proxy '(m', zq) -> Cyc c m zp -> Cyc c m zp -> Property) 
     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property
wrapMath f _ _ = property $ f Proxy

wrapConst :: (EncDecWrapCtx c m m' zp zq)
  => (Proxy '(m', zq) -> Proxy (Cyc c m zp) -> Property) 
     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property
wrapConst f _ _ = property $ f Proxy Proxy

groupCEnc :: 
  (forall c m m' zp zq . (EncDecWrapCtx c m m' zp zq)
     => Proxy (Cyc c)
     -> Proxy '(m, m', zp, zq)
     -> Property) 
  -> [Test]
groupCEnc f =
  [testGroup "CT" $ groupTypesEnc (f (Proxy::Proxy (Cyc CT.CT))),
   testGroup "RT" $ groupTypesEnc (f (Proxy::Proxy (Cyc RT)))]

type EncDecWrapCCtx m m' zp zq =
  (EncDecWrapCtx RT m m' zp zq,
   EncDecWrapCtx CT.CT m m' zp zq)

groupTypesEnc :: 
  (forall m m' zp zq . (EncDecWrapCCtx m m' zp zq)
    => Proxy '(m, m', zp, zq)
    -> Property)
  -> [Test]
groupTypesEnc f = [testProperty "F7/F7 /ZP2/ZQ2" $ f (Proxy::Proxy '(F7, F7,  ZP2, ZQ2)),
                   testProperty "F7/F21/ZP2/ZQ2" $ f (Proxy::Proxy '(F7, F21, ZP2, ZQ2)),
                   testProperty "F2/F8 /ZP2/Q536871001" $ f (Proxy::Proxy '(F2,F8,ZP2,Zq Q536871001)),
                   testProperty "F1/F8 /ZP2/Q536871001" $ f (Proxy::Proxy '(F1,F8,ZP2,Zq Q536871001)),
                   testProperty "F4/F12/ZP2/SmoothZQ1" $ f (Proxy::Proxy '(F4,F12,ZP2,SmoothZQ1)),
                   testProperty "F4/F8/ZP3/SmoothQ1" $ f (Proxy::Proxy '(F4,F8,ZP3, Zq SmoothQ1)),
                   testProperty "F7/F7 /ZP4/ZQ2" $ f (Proxy::Proxy '(F7, F7,  ZP4, ZQ2)),
                   testProperty "F7/F21/ZP4/ZQ2" $ f (Proxy::Proxy '(F7, F21, ZP4, ZQ2)),
                   testProperty "F1/F4/ZP4/ZQ1" $ f (Proxy::Proxy '(F1,F4,ZP4,ZQ1)),
                   testProperty "F4/F4/ZP4/ZQ1" $ f (Proxy::Proxy '(F4,F4,ZP4,ZQ1)),
                   testProperty "F14/F14/ZP4/ZQ1" $ f (Proxy::Proxy '(F14,F14,ZP4,ZQ1)),
                   testProperty "F28/F28/ZP4/ZQ1" $ f (Proxy::Proxy '(F28,F28,ZP4,ZQ1)),
                   testProperty "F28/F28/ZP4/Q80221" $ f (Proxy::Proxy '(F28,F28,ZP4,Zq Q80221)),
                   testProperty "F1/F8 /ZP4/Q536871001" $ f (Proxy::Proxy '(F1,F8,ZP4,Zq Q536871001)),
                   testProperty "F2/F8 /ZP4/Q536871001" $ f (Proxy::Proxy '(F2,F8,ZP4,Zq Q536871001)),
                   testProperty "F4/F12/ZP8/SmoothZQ1" $ f (Proxy::Proxy '(F4,F12,ZP8,SmoothZQ1))
                  ]

-- one-off tests, no wrapper

prop_modSwPT :: forall m zp c m' zq z v zp' .
  (EncryptCtx c m m' z zp zq,
   GenSKCtx c m z v,
   DecryptCtx c m m' z zp' zq,
   ModSwitchPTCtx c m' zp zp' zq,
   RescaleCyc (Cyc c) zp zp', Mod zp',
   CElt c Int64, CElt c zq,
   z ~ LiftOf zp', v ~ Double, ModRep zp' ~ ModRep zp) 
  => Proxy '(m', zq, zp') -> Cyc c m zp -> Property
prop_modSwPT _ x = monadicIO $ do
  let p = proxy modulus (Proxy::Proxy zp)
      p' = proxy modulus (Proxy::Proxy zp')
      x' = (fromIntegral $ p `div` p') * x
  sk :: SK (Cyc c m' z) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk x'
  let y' = modSwitchPT y :: CT m zp' (Cyc c m' zq)
      x'' = decrypt sk y'
  assert $ x'' == rescaleCyc Dec x'

modSwPTTests = 
  [testProperty "RT/F7/F21/ZQ1/ZP4/ZP8" (prop_modSwPT (Proxy::Proxy '(F21, ZQ1, ZP4)) :: Cyc RT F7 ZP8 -> Property),
   testProperty "RT/F7/F42/ZQ1/ZP2/ZP4" (prop_modSwPT (Proxy::Proxy '(F42, ZQ1, ZP2)) :: Cyc RT F7 ZP4 -> Property),
   testProperty "CT/F7/F21/ZQ1/ZP4/ZP8" (prop_modSwPT (Proxy::Proxy '(F21, ZQ1, ZP4)) :: Cyc CT.CT F7 ZP8 -> Property),
   testProperty "CT/F7/F42/ZQ1/ZP2/ZP4" (prop_modSwPT (Proxy::Proxy '(F42, ZQ1, ZP2)) :: Cyc CT.CT F7 ZP4 -> Property)]


tunnelTests = 
  [testProperty "RT/F7/F21/ZQ1/ZP4/ZP8" 
    (prop_ringTunnel (Proxy::Proxy '(F40,ZQ1,F20,F60,TrivGad,ZQ2)) :: Cyc RT F8 ZP4 -> Property)]

prop_ringTunnel :: forall c e r s e' r' s' z zp zq zq' gad . 
  (TunnelCtx c e r s e' r' s' z zp zq zq' gad, 
   EncryptCtx c r r' z zp zq,
   GenSKCtx c r' z Double,
   GenSKCtx c s' z Double,
   DecryptCtx c s s' z zp zq,
   Random (Cyc c s zp),
   e ~ FGCD r s, Fact e) 
  => Proxy '(r', zq, s, s', gad, zq') -> Cyc c r zp -> Property
prop_ringTunnel _ x = monadicIO $ 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 c s zp] <- replicateM basisSize getRandom
  let f = (linearDec bs) \\ (gcdDivides (Proxy::Proxy r) (Proxy::Proxy s)) :: Linear c zp e r s 
      expected = evalLin f x \\ (gcdDivides (Proxy::Proxy r) (Proxy::Proxy s))
  skin :: SK (Cyc c r' (LiftOf zp)) <- genSK v
  skout :: SK (Cyc c s' (LiftOf zp)) <- genSK v
  y :: CT r zp (Cyc c r' zq) <- encrypt skin x
  tunn <- proxyT (tunnelCT f skout skin) (Proxy::Proxy (gad,zq'))
  let y' = tunn y
      actual = decrypt skout y' :: Cyc c s zp
  assert $ expected == actual












type KsCtx m zp z c m' zq gad zq' deczq = 
  (GenSKCtx c m' z Double,
   z ~ LiftOf zp, 
   EncryptCtx c m m' z zp zq,
   KeySwitchCtx gad c m' zp zq zq', 
   KSHintCtx gad c m' z zq',
   RescaleCyc (Cyc c) zq deczq,
   DecryptCtx c m m' z zp deczq)

prop_ksLin :: forall m zp z c m' zq gad zq' deczq . (KsCtx m zp z c m' zq gad zq' deczq) 
  => Proxy '(m', zq, gad, zq', deczq) -> Cyc c m zp -> Property
prop_ksLin (_ :: Proxy '(m', zq, gad, zq', deczq)) x = monadicIO $ do
  sk1 :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  sk2 :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk1 x
  ks <- proxyT (keySwitchLinear sk2 sk1) (Proxy::Proxy (gad,zq'))
  let y' :: CT m zp (Cyc c m' zq) = ks y
      x' = decrypt sk2 (rescaleLinearCT y' :: CT m zp (Cyc c m' deczq))
  assert $ x == x'

prop_ksQuad :: forall m zp z c m' zq gad zq' deczq . (KsCtx m zp z c m' zq gad zq' deczq) 
  => Proxy '(m', zq, gad, zq', deczq) -> Cyc c m zp -> Cyc c m zp -> Property
prop_ksQuad (_ :: Proxy '(m', zq, gad, zq', deczq)) x1 x2 = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y1 :: CT m zp (Cyc c m' zq) <- encrypt sk x1
  y2 :: CT m zp (Cyc c m' zq) <- encrypt sk x2
  ks <- proxyT (keySwitchQuadCirc sk) (Proxy::Proxy (gad,zq'))
  let y' = ks (y1*y2)
      x' = decrypt sk (rescaleLinearCT y' :: CT m zp (Cyc c m' deczq))
  assert $ x1*x2 == x'

type KsWrapCtx m zp z c m' zq gad zq' deczq = 
  (KsCtx m zp z c m' zq gad zq' deczq, Show (Cyc c m zp), Arbitrary (c m zp))

wrapKSLin :: forall m zp z c m' zq gad zq' deczq . (KsWrapCtx m zp z c m' zq gad zq' deczq)
  => (Proxy '(m', zq, gad, zq', deczq) -> Cyc c m zp -> Property) 
     -> Proxy (Cyc c) -> Proxy gad -> Proxy '(m, m', zp, zq, zq', deczq) -> Property
wrapKSLin f _ _ _ = property $ f Proxy

wrapKSQuad :: forall m zp z c m' zq gad zq' deczq . (KsWrapCtx m zp z c m' zq gad zq' deczq)
  => (Proxy '(m', zq, gad, zq',deczq) -> Cyc c m zp -> Cyc c m zp -> Property) 
     -> Proxy (Cyc c) -> Proxy gad -> Proxy '(m, m', zp, zq, zq', deczq) -> Property
wrapKSQuad f _ _ _ = property $ f Proxy

groupCKS :: 
  (forall c m m' zp z zq zq' gad deczq . (KsWrapCtx m zp z c m' zq gad zq' deczq)
     => Proxy (Cyc c)
     -> Proxy gad
     -> Proxy '(m, m', zp, zq, zq', deczq)
     -> Property)
  -> [Test]
groupCKS f =
  [testGroup "CT" $ groupGadKS $ f (Proxy::Proxy (Cyc CT.CT)),
   testGroup "RT" $ groupGadKS $ f (Proxy::Proxy (Cyc RT))]

type KsWrapCCtx m zp z m' zq gad zq' deczq = 
  (KsWrapCtx m zp z RT m' zq gad zq' deczq,
   KsWrapCtx m zp z CT.CT m' zq gad zq' deczq)

groupGadKS :: 
  (forall m m' zp z zq zq' gad deczq . (KsWrapCCtx m zp z m' zq gad zq' deczq)
     => Proxy gad
     -> Proxy '(m, m', zp, zq, zq', deczq)
     -> Property) 
  -> [Test]
groupGadKS f =
  [testGroup "TrivGad" $ groupTypesKS (f (Proxy::Proxy TrivGad))]
   --testGroup "Base16" $ groupTypesKS (f (Proxy::Proxy (BaseBGad N16)))]

type KsWrapCGadCtx m zp z m' zq zq' deczq = 
  (KsWrapCCtx m zp z m' zq TrivGad zq' deczq)

groupTypesKS :: 
  (forall m m' zp z zq zq' deczq . (KsWrapCGadCtx m zp z m' zq zq' deczq)
    => Proxy '(m, m', zp, zq, zq', deczq) 
    -> Property) 
  -> [Test]
groupTypesKS f = 
  [testProperty "F1/F7/ZP2/ZQ1/ZQ2" $ f (Proxy::Proxy '(F1, F7, ZP2, ZQ1, ZQ2, ZQ1)),
   testProperty "F2/F4/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F2, F4, ZP8, SmoothZQ1, SmoothZQ2, SmoothZQ1)),
   testProperty "F4/F12/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F4, F12, ZP2, SmoothZQ1, SmoothZQ2, SmoothZQ1)),
   testProperty "F8/F64/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F8, F64, ZP2, SmoothZQ1, SmoothZQ2, SmoothZQ1)),
   testProperty "F3/F27/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F3, F27, ZP2, SmoothZQ1, SmoothZQ2, SmoothZQ1)),
   testProperty "F2/F4/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F2, F4, ZP8, SmoothZQ2, SmoothZQ3, SmoothZQ1)),
   testProperty "F4/F12/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F4, F12, ZP2, SmoothZQ2, SmoothZQ3, SmoothZQ1)),
   testProperty "F8/F64/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F8, F64, ZP2, SmoothZQ2, SmoothZQ3, SmoothZQ1)),
   testProperty "F3/F27/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F3, F27, ZP2, SmoothZQ2, SmoothZQ3, SmoothZQ1))]


















type TwEmCtx c m m' t t' zp zq =
  (EncryptCtx c m m' (LiftOf zp) zp zq,
   GenSKCtx c m (LiftOf zp) Double, 
   DecryptCtx c m m' (LiftOf zp) zp zq, 
   t `Divides` t', m `Divides` t, m' `Divides` t', m ~ FGCD m' t)

prop_ctembed :: forall c m m' t t' zp zq . 
  (TwEmCtx c m m' t t' zp zq)
  => Proxy '(m', zq, t, t') -> Cyc c m zp -> Property
prop_ctembed _ x = monadicIO $ do
  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt sk x
  let y' = embedCT y :: CT t zp (Cyc c t' zq)
      x' = decrypt (embedSK sk) y'
  assert $ (embed x :: Cyc c t zp) == x'

prop_cttwace :: forall c m m' t t' zp zq . 
  (TwEmCtx c t t' m m' zp zq)
  => Proxy '(m', zq, t, t') -> Cyc c m zp -> Property
prop_cttwace _ x = monadicIO $ do
  sk :: SK (Cyc c t' (LiftOf zp)) <- genSK v
  y :: CT m zp (Cyc c m' zq) <- encrypt (embedSK sk) x
  let y' = twaceCT y :: CT t zp (Cyc c t' zq)
      x' = decrypt sk y'
  assert $ (twace x :: Cyc c t zp) == x'

type TwEmWrapCtx c m m' t t' zp zq = 
  (TwEmCtx c m m' t t' zp zq, Show (Cyc c m zp), Show (Cyc c t zp), Arbitrary (c m zp), Arbitrary (c t zp))

wrapEm :: (TwEmWrapCtx c m m' t t' zp zq)
  => (Proxy '(m', zq, t, t') -> Cyc c m zp -> Property) 
     -> Proxy (Cyc c) -> Proxy '(m, m', t, t', zp, zq) -> Property
wrapEm f _ _ = property $ f Proxy

wrapTw :: (TwEmWrapCtx c t t' m m' zp zq)
  => (Proxy '(m', zq, t, t') -> Cyc c m zp -> Property) 
     -> Proxy (Cyc c) -> Proxy '(t, t', m, m', zp, zq) -> Property
wrapTw f _ _ = property $ f Proxy

groupCTwEm :: 
  (forall c m m' t t' zp zq . (TwEmWrapCtx c m m' t t' zp zq)
     => Proxy (Cyc c)
     -> Proxy '(m, m', t, t', zp, zq)
     -> Property) 
  -> [Test]
groupCTwEm f =
  [testGroup "CT" $ groupTypesTwEm (f (Proxy::Proxy (Cyc CT.CT))),
   testGroup "RT" $ groupTypesTwEm (f (Proxy::Proxy (Cyc RT)))]

type TwEmWrapCCtx m m' t t' zp zq =
  (TwEmWrapCtx RT m m' t t' zp zq,
   TwEmWrapCtx CT.CT m m' t t' zp zq)

groupTypesTwEm :: 
  (forall m m' t t' zp zq . (TwEmWrapCCtx m m' t t' zp zq)
    => Proxy '(m, m', t, t', zp, zq) 
    -> Property) 
  -> [Test]
groupTypesTwEm f = 
  [testProperty "F1/F7/F3/F21/ZP2/ZQ1" $ f (Proxy::Proxy '(F1, F7, F3, F21, ZP2, ZQ1))]