module Crypto.Lol.Cyclotomic.UCyc
(
UCyc, P, D, C, UCElt, NFElt
, toPow, toDec, toCRT, fmapPow, fmapDec, unzipCyc, unzipUCElt
, scalarPow, scalarCRT
, mulG, divG, gSqNorm
, tGaussian, errorRounded, errorCoset
, embedPow, embedDec, embedCRT
, twacePow, twaceDec, twaceCRT
, coeffsPow, coeffsDec, powBasis, crtSet
) where
import Crypto.Lol.Cyclotomic.Tensor hiding (embedCRT, embedDec, embedPow,
scalarCRT, scalarPow,
twaceCRT)
import Crypto.Lol.CRTrans
import qualified Crypto.Lol.Cyclotomic.Tensor as T
import Crypto.Lol.LatticePrelude as LP
import Crypto.Lol.Types.FiniteField
import Crypto.Lol.Types.ZPP
import qualified Algebra.Additive as Additive (C)
import qualified Algebra.Module as Module (C)
import qualified Algebra.Ring as Ring (C)
import qualified Algebra.ZeroTestable as ZeroTestable (C)
import Control.Applicative as A
import Control.Arrow
import Control.DeepSeq
import Control.Monad
import Control.Monad.Random
import Data.Foldable as F
import Data.Maybe
import Data.Traversable
import Test.QuickCheck
data P
data D
data C
data UCyc t m rep r where
Pow :: !(t m r) -> UCyc t m P r
Dec :: !(t m r) -> UCyc t m D r
CRTr :: !(t m r) -> UCyc t m C r
CRTe :: !(t m (CRTExt r)) -> UCyc t m C r
type UCElt t r = (Tensor t, CRTEmbed r, CRTElt t r, CRTElt t (CRTExt r))
type NFElt r = (NFData r, NFData (CRTExt r))
scalarPow :: (Tensor t, Fact m, Ring r, TElt t r) => r -> UCyc t m P r
scalarPow = Pow . T.scalarPow
scalarCRT :: (Fact m, UCElt t r) => r -> UCyc t m C r
scalarCRT = fromMaybe
(CRTe . fromJust' "UCyc: no CRT over CRTExt" T.scalarCRT . toExt)
((CRTr .) <$> T.scalarCRT)
instance (Eq r, Tensor t, Fact m, TElt t r) => Eq (UCyc t m P r) where
(Pow v1) == (Pow v2) = v1 == v2 \\ witness entailEqT v1
instance (Eq r, Tensor t, Fact m, TElt t r) => Eq (UCyc t m D r) where
(Dec v1) == (Dec v2) = v1 == v2 \\ witness entailEqT v1
instance (Eq r, Fact m, UCElt t r) => Eq (UCyc t m C r) where
(CRTr v1) == (CRTr v2) = v1 == v2 \\ witness entailEqT v1
u1 == u2 = toPow u1 == toPow u2
instance (ZeroTestable r, Tensor t, Fact m, TElt t r)
=> ZeroTestable.C (UCyc t m P r) where
isZero (Pow v) = isZero v \\ witness entailZTT v
instance (ZeroTestable r, Tensor t, Fact m, TElt t r)
=> ZeroTestable.C (UCyc t m D r) where
isZero (Dec v) = isZero v \\ witness entailZTT v
instance (ZeroTestable r, Fact m, UCElt t r)
=> ZeroTestable.C (UCyc t m C r) where
isZero (CRTr v) = isZero v \\ witness entailZTT v
isZero u = isZero $ toPow u
instance (Additive r, Tensor t, Fact m, TElt t r) => Additive.C (UCyc t m P r) where
zero = Pow $ T.scalarPow zero
(Pow v1) + (Pow v2) = Pow $ zipWithT (+) v1 v2
(Pow v1) (Pow v2) = Pow $ zipWithT () v1 v2
negate (Pow v) = Pow $ fmapT negate v
instance (Additive r, Tensor t, Fact m, TElt t r) => Additive.C (UCyc t m D r) where
zero = Dec $ T.scalarPow zero
(Dec v1) + (Dec v2) = Dec $ zipWithT (+) v1 v2
(Dec v1) (Dec v2) = Dec $ zipWithT () v1 v2
negate (Dec v) = Dec $ fmapT negate v
instance (Fact m, UCElt t r) => Additive.C (UCyc t m C r) where
zero = scalarCRT zero
(CRTr v1) + (CRTr v2) = CRTr $ zipWithT (+) v1 v2
(CRTe v1) + (CRTe v2) = CRTe $ zipWithT (+) v1 v2
_ + _ = error "UCyc (+) internal error: mixed CRTr/CRTe"
(CRTr v1) (CRTr v2) = CRTr $ zipWithT () v1 v2
(CRTe v1) (CRTe v2) = CRTe $ zipWithT () v1 v2
_ _ = error "UCyc (-) internal error: mixed CRTr/CRTe"
negate (CRTr v) = CRTr $ fmapT negate v
negate (CRTe v) = CRTe $ fmapT negate v
instance (Fact m, UCElt t r) => Ring.C (UCyc t m C r) where
one = scalarCRT one
fromInteger c = scalarCRT $ fromInteger c
(CRTr v1) * (CRTr v2) = CRTr $ zipWithT (*) v1 v2
(CRTe v1) * (CRTe v2) = CRTe $ zipWithT (*) v1 v2
_ * _ = error "UCyc internal error: mixed CRTr/CRTe"
instance (Ring r, Tensor t, Fact m, TElt t r) => Module.C r (UCyc t m P r) where
r *> (Pow v) = Pow $ fmapT (r *) v
instance (Ring r, Tensor t, Fact m, TElt t r) => Module.C r (UCyc t m D r) where
r *> (Dec v) = Dec $ fmapT (r *) v
instance (Ring r, Fact m, UCElt t r) => Module.C r (UCyc t m C r) where
r *> (CRTr v) = CRTr $ fmapT (r *) v
r *> (CRTe v) = CRTe $ fmapT (toExt r *) v
instance (GFCtx fp d, Fact m, UCElt t fp) => Module.C (GF fp d) (UCyc t m P fp) where
r *> (Pow v) = Pow $ r LP.*> v \\ witness entailModuleT (r,v)
instance (Reduce a b, Tensor t, Fact m, TElt t a, TElt t b)
=> Reduce (UCyc t m P a) (UCyc t m P b) where
reduce (Pow v) = Pow $ fmapT reduce v
instance (Reduce a b, Tensor t, Fact m, TElt t a, TElt t b)
=> Reduce (UCyc t m D a) (UCyc t m D b) where
reduce (Dec v) = Dec $ fmapT reduce v
type instance LiftOf (UCyc t m P r) = UCyc t m P (LiftOf r)
type instance LiftOf (UCyc t m D r) = UCyc t m D (LiftOf r)
instance (Lift' r, Tensor t, Fact m, TElt t r, TElt t (LiftOf r))
=> Lift' (UCyc t m P r) where
lift (Pow v) = Pow $ fmapT lift v
instance (Lift' r, Tensor t, Fact m, TElt t r, TElt t (LiftOf r))
=> Lift' (UCyc t m D r) where
lift (Dec v) = Dec $ fmapT lift v
instance (Rescale a b, Tensor t, Fact m, TElt t a, TElt t b)
=> Rescale (UCyc t m P a) (UCyc t m P b) where
rescale (Pow v) = Pow $ fmapT rescale v
instance (Rescale a b, Tensor t, Fact m, TElt t a, TElt t b)
=> Rescale (UCyc t m D a) (UCyc t m D b) where
rescale (Dec v) = Dec $ fmapT rescale v
fmapPow :: (Tensor t, Fact m, TElt t a, TElt t b)
=> (a -> b) -> UCyc t m P a -> UCyc t m P b
fmapPow f (Pow v) = Pow $ fmapT f v
fmapDec :: (Tensor t, Fact m, TElt t a, TElt t b)
=> (a -> b) -> UCyc t m D a -> UCyc t m D b
fmapDec f (Dec v) = Dec $ fmapT f v
unzipCyc :: (Tensor t, Fact m)
=> UCyc t m rep (a,b) -> (UCyc t m rep a, UCyc t m rep b)
unzipCyc (Pow v) = Pow *** Pow $ unzipT v
unzipCyc (Dec v) = Dec *** Dec $ unzipT v
unzipCyc (CRTr v) = CRTr *** CRTr $ unzipT v
unzipCyc (CRTe v) = CRTe *** CRTe $ unzipT v
unzipUCElt :: (Tensor t, Fact m, UCElt t (a,b), UCElt t a, UCElt t b)
=> UCyc t m rep (a,b) -> (UCyc t m rep a, UCyc t m rep b)
unzipUCElt (Pow v) = Pow *** Pow $ unzipTElt v
unzipUCElt (Dec v) = Dec *** Dec $ unzipTElt v
unzipUCElt (CRTr v) = CRTr *** CRTr $ unzipTElt v
unzipUCElt (CRTe v) = CRTe *** CRTe $ unzipTElt v
mulG :: (Tensor t, Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m rep r
mulG (Pow v) = Pow $ mulGPow v
mulG (Dec v) = Dec $ mulGDec v
mulG (CRTr v) = CRTr $ fromJust' "UCyc.mulG CRTr" mulGCRT v
mulG (CRTe v) = CRTe $ fromJust' "UCyc.mulG CRTe" mulGCRT v
divG :: (Tensor t, Fact m, UCElt t r) => UCyc t m rep r -> Maybe (UCyc t m rep r)
divG (Pow v) = Pow <$> divGPow v
divG (Dec v) = Dec <$> divGDec v
divG (CRTr v) = Just $ CRTr $ fromJust' "UCyc.divG CRTr" divGCRT v
divG (CRTe v) = Just $ CRTe $ fromJust' "UCyc.divG CRTe" divGCRT v
gSqNorm :: (Ring r, Tensor t, Fact m, TElt t r) => UCyc t m D r -> r
gSqNorm (Dec v) = gSqNormDec v
tGaussian :: (Tensor t, Fact m, OrdFloat q, Random q, TElt t q,
ToRational v, MonadRandom rnd)
=> v -> rnd (UCyc t m D q)
tGaussian = fmap Dec . tGaussianDec
errorRounded :: forall v rnd t m z .
(ToInteger z, Tensor t, Fact m, TElt t z,
ToRational v, MonadRandom rnd)
=> v -> rnd (UCyc t m D z)
errorRounded svar =
Dec . fmapT (roundMult one) <$> (tGaussianDec svar :: rnd (t m Double))
errorCoset :: forall t m zp z v rnd .
(Mod zp, z ~ ModRep zp, Lift zp z, Tensor t, Fact m,
TElt t zp, TElt t z, ToRational v, MonadRandom rnd)
=> v -> UCyc t m D zp -> rnd (UCyc t m D z)
errorCoset =
let pval = fromIntegral $ proxy modulus (Proxy::Proxy zp)
in \ svar c -> do err <- tGaussian (svar*pval*pval) :: rnd (UCyc t m D Double)
return $! roundCoset <$> c <*> err
embedPow :: (Additive r, Tensor t, m `Divides` m', TElt t r)
=> UCyc t m P r -> UCyc t m' P r
embedPow (Pow v) = Pow $ T.embedPow v
embedDec :: (Additive r, Tensor t, m `Divides` m', TElt t r)
=> UCyc t m D r -> UCyc t m' D r
embedDec (Dec v) = Dec $ T.embedDec v
embedCRT :: forall t m m' r . (m `Divides` m', UCElt t r)
=> UCyc t m C r -> Either (UCyc t m' P r) (UCyc t m' C r)
embedCRT x@(CRTr v) = fromMaybe (Left $ embedPow $ toPow x)
(Right . CRTr <$> (T.embedCRT <*> pure v))
embedCRT x@(CRTe v) =
fromMaybe (Right $ CRTe $ fromJust' "UCyc.embedCRT CRTe" T.embedCRT v)
(proxyT hasCRTFuncs (Proxy::Proxy (t m r)) A.*>
pure (Left $ embedPow $ toPow x))
twacePow :: (Ring r, Tensor t, m `Divides` m', TElt t r)
=> UCyc t m' P r -> UCyc t m P r
twacePow (Pow v) = Pow $ twacePowDec v
twaceDec :: (Ring r, Tensor t, m `Divides` m', TElt t r)
=> UCyc t m' D r -> UCyc t m D r
twaceDec (Dec v) = Dec $ twacePowDec v
twaceCRT :: forall t m m' r . (m `Divides` m', UCElt t r)
=> UCyc t m' C r -> Either (UCyc t m P r) (UCyc t m C r)
twaceCRT x@(CRTr v) =
fromMaybe (Left $ twacePow $ toPow x) (Right . CRTr <$> (T.twaceCRT <*> pure v))
twaceCRT x@(CRTe v) =
fromMaybe (Right $ CRTe $ fromJust' "UCyc.twace CRTe" T.twaceCRT v)
(proxyT hasCRTFuncs (Proxy::Proxy (t m r)) A.*>
Just (Left $ twacePow $ toPow x))
coeffsPow :: (Ring r, Tensor t, m `Divides` m', TElt t r)
=> UCyc t m' P r -> [UCyc t m P r]
coeffsPow (Pow v) = LP.map Pow $ coeffs v
coeffsDec :: (Ring r, Tensor t, m `Divides` m', TElt t r)
=> UCyc t m' D r -> [UCyc t m D r]
coeffsDec (Dec v) = LP.map Dec $ coeffs v
powBasis :: (Ring r, Tensor t, m `Divides` m', TElt t r)
=> Tagged m [UCyc t m' P r]
powBasis = (Pow <$>) <$> powBasisPow
crtSet :: forall t m m' r p mbar m'bar .
(m `Divides` m', ZPP r, p ~ CharOf (ZpOf r),
mbar ~ PFree p m, m'bar ~ PFree p m',
UCElt t r, TElt t (ZpOf r))
=> Tagged m [UCyc t m' P r]
crtSet =
let (p,e) = proxy modulusZPP (Proxy::Proxy r)
pp = Proxy::Proxy p
pm = Proxy::Proxy m
pm' = Proxy::Proxy m'
in retag (fmap (embedPow .
(if e > 1 then toPow . (^(p^(e1))) . toCRT else toPow) .
Dec . fmapT liftZp) <$>
(crtSetDec :: Tagged mbar [t m'bar (ZpOf r)]))
\\ pFreeDivides pp pm pm' \\ pSplitTheorems pp pm \\ pSplitTheorems pp pm'
toPow :: (Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m P r
toPow x@(Pow _) = x
toPow (Dec v) = Pow $ l v
toPow (CRTr v) = Pow $ fromJust' "UCyc.toPow CRTr" crtInv v
toPow (CRTe v) =
Pow $ fmapT fromExt $ fromJust' "UCyc.toPow CRTe" crtInv v
toDec :: (Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m D r
toDec (Pow v) = Dec $ lInv v
toDec x@(Dec _) = x
toDec x@(CRTr _) = toDec $ toPow x
toDec x@(CRTe _) = toDec $ toPow x
toCRT :: forall t m rep r . (Fact m, UCElt t r)
=> UCyc t m rep r -> UCyc t m C r
toCRT = let crte = CRTe . fromJust' "UCyc.toCRT: no crt for Ext" crt
crtr = fmap (CRTr .) crt
fromPow :: t m r -> UCyc t m C r
fromPow v = fromMaybe (crte $ fmapT toExt v) (crtr <*> Just v)
in \x -> case x of
(CRTr _) -> x
(CRTe _) -> x
(Pow v) -> fromPow v
(Dec v) -> fromPow $ l v
instance (Tensor t, Fact m) => Functor (UCyc t m P) where
fmap f x = pure f <*> x
instance (Tensor t, Fact m) => Functor (UCyc t m D) where
fmap f x = pure f <*> x
instance (Tensor t, Fact m) => Applicative (UCyc t m P) where
pure = Pow . pure \\ proxy entailIndexT (Proxy::Proxy (t m r))
(Pow f) <*> (Pow v) = Pow $ f <*> v \\ witness entailIndexT v
instance (Tensor t, Fact m) => Applicative (UCyc t m D) where
pure = Dec . pure \\ proxy entailIndexT (Proxy::Proxy (t m r))
(Dec f) <*> (Dec v) = Dec $ f <*> v \\ witness entailIndexT v
instance (Tensor t, Fact m) => Foldable (UCyc t m P) where
foldr f b (Pow v) = F.foldr f b v \\ witness entailIndexT v
instance (Tensor t, Fact m) => Foldable (UCyc t m D) where
foldr f b (Dec v) = F.foldr f b v \\ witness entailIndexT v
instance (Tensor t, Fact m) => Traversable (UCyc t m P) where
traverse f (Pow v) = Pow <$> traverse f v \\ witness entailIndexT v
instance (Tensor t, Fact m) => Traversable (UCyc t m D) where
traverse f (Dec v) = Dec <$> traverse f v \\ witness entailIndexT v
instance (Random r, Tensor t, Fact m, CRTElt t r)
=> Random (Either (UCyc t m P r) (UCyc t m C r)) where
random = let cons = fromMaybe (Left . Pow)
(proxyT hasCRTFuncs (Proxy::Proxy (t m r))
>> Just (Right . CRTr))
in \g -> let (v,g') = random g \\ witness entailRandomT v
in (cons v, g')
randomR _ = error "randomR non-sensical for UCyc"
instance (Show r, Show (CRTExt r), Tensor t, Fact m, TElt t r, TElt t (CRTExt r))
=> Show (UCyc t m rep r) where
show (Pow v) = "UCyc Pow: " ++ show v \\ witness entailShowT v
show (Dec v) = "UCyc Dec: " ++ show v \\ witness entailShowT v
show (CRTr v) = "UCyc CRTr: " ++ show v \\ witness entailShowT v
show (CRTe v) = "UCyc CRTe: " ++ show v \\ witness entailShowT v
instance (Arbitrary (t m r)) => Arbitrary (UCyc t m P r) where
arbitrary = Pow <$> arbitrary
shrink = shrinkNothing
instance (Arbitrary (t m r)) => Arbitrary (UCyc t m D r) where
arbitrary = Dec <$> arbitrary
shrink = shrinkNothing
instance (Arbitrary (t m r)) => Arbitrary (UCyc t m C r) where
arbitrary = CRTr <$> arbitrary
shrink = shrinkNothing
instance (Tensor t, Fact m, NFElt r, TElt t r, TElt t (CRTExt r))
=> NFData (UCyc t m rep r) where
rnf (Pow x) = rnf x \\ witness entailNFDataT x
rnf (Dec x) = rnf x \\ witness entailNFDataT x
rnf (CRTr x) = rnf x \\ witness entailNFDataT x
rnf (CRTe x) = rnf x \\ witness entailNFDataT x