{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Crypto.Lol.Cyclotomic.Linear
( Linear, ExtendLinCtx
, linearDec, evalLin, liftLin, fmapLin, extendLin
) where
import Crypto.Lol.Cyclotomic.Language
import Crypto.Lol.Cyclotomic.Tensor
import Crypto.Lol.Prelude
import Crypto.Lol.Reflects
import Crypto.Lol.Types.Proto
import Crypto.Proto.Lol.LinearRq (LinearRq (LinearRq))
import Crypto.Proto.Lol.RqProduct (RqProduct)
import Algebra.Additive as Additive (C)
import Control.Applicative
import Control.DeepSeq
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as U
import Data.Word
newtype Linear c (e::Factored) (r::Factored) (s::Factored) z = RD [c s z]
deriving Show
type role Linear representational representational representational nominal nominal
deriving instance NFData (c s z) => NFData (Linear c e r s z)
linearDec :: forall c e r s z .
(e `Divides` r, e `Divides` s, Cyclotomic (c s z), ExtensionCyc c z)
=> [c s z] -> Linear c e r s z
linearDec ys = let ps = proxy powBasis (Proxy::Proxy e) `asTypeOf` ys
in if length ys <= length ps then RD (adviseCRT <$> ys)
else error $ "linearDec: too many entries: "
++ show (length ys) ++ " versus "
++ show (length ps)
evalLin :: forall c e r s z .
(e `Divides` r, e `Divides` s, Ring (c s z), ExtensionCyc c z)
=> Linear c e r s z -> c r z -> c s z
evalLin (RD ys) r = sum (zipWith (*) ys $ embed <$> (coeffsDec r :: [c e z]))
instance Additive (c s z) => Additive.C (Linear c e r s z) where
zero = RD []
(RD as) + (RD bs) = RD $ sumall as bs
where sumall [] ys = ys
sumall xs [] = xs
sumall (x:xs) (y:ys) = x+y : sumall xs ys
negate (RD as) = RD $ negate <$> as
instance (Reduce (c s z) (c s zp))
=> Reduce (Linear c e r s z) (Linear c e r s zp) where
reduce (RD ys) = RD $ reduce <$> ys
type instance LiftOf (Linear c e r s zp) = Linear c e r s (LiftOf zp)
liftLin :: (LiftCyc (c s zp), LiftOf (c s zp) ~ c s (LiftOf zp))
=> Maybe Basis -> Linear c e r s zp -> Linear c e r s (LiftOf zp)
liftLin b (RD ys) = RD $ liftCyc b <$> ys
fmapLin :: (c s z -> c' s z) -> Linear c e r s z -> Linear c' e r s z
fmapLin f (RD cs) = RD (f <$> cs)
type ExtendLinCtx c e r s e' r' s' z =
(e ~ FGCD r e',
FLCM r e' `Divides` r',
e' `Divides` s', s `Divides` s',
ExtensionCyc c z, Additive (c s' z))
extendLin :: forall c e r s e' r' s' z .
(ExtendLinCtx c e r s e' r' s' z)
=> Linear c e r s z -> Linear c e' r' s' z
extendLin (RD ys) =
let yvec = V.fromList ys
ylen = V.length yvec
idxs = baseIndicesPow @(FLCM r e') @r'
y'vec = V.generate (U.length idxs) $ \idx ->
let (j0,j1) = idxs U.! idx
in if j0 == 0 && j1 < ylen then embed (yvec V.! j1) else zero
in RD $ V.toList y'vec
instance (Reflects e Word32, Reflects r Word32,
Protoable (c s zq), ProtoType (c s zq) ~ RqProduct)
=> Protoable (Linear c e r s zq) where
type ProtoType (Linear c e r s zq) = LinearRq
toProto (RD cs) =
LinearRq (value @e) (value @r) $ toProto cs
fromProto (LinearRq e r cs) =
let e' = value @e
r' = value @r
in if e == e' && r == r'
then RD <$> fromProto cs
else error $ "Could not deserialize Linear: types imply e=" ++
show e' ++ " and r=" ++ show r' ++
", but serializd object is for e=" ++
show e ++ " and r=" ++ show r