{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts, NoImplicitPrelude,
PolyKinds, RebindableSyntax, ScopedTypeVariables,
TypeFamilies, TypeOperators #-}
-- | CT-specific functions for embedding/twacing in various bases
module Crypto.Lol.Cyclotomic.Tensor.CTensor.Extension
( embedPow', embedDec', embedCRT'
, twacePowDec' -- , twaceCRT'
, coeffs', powBasisPow'
, crtSetDec'
, backpermute'
) where
import Crypto.Lol.CRTrans
import Crypto.Lol.LatticePrelude as LP hiding (null, lift)
import Crypto.Lol.Cyclotomic.Tensor as T
import Crypto.Lol.Types.FiniteField
import Crypto.Lol.Types.ZmStar
import Crypto.Lol.Reflects
import Control.Applicative hiding (empty)
import Control.Monad.Trans (lift)
import Data.Maybe
import Data.Reflection (reify)
import qualified Data.Vector as V
import Data.Vector.Generic as G (generate, Vector, (!), length)
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Storable as SV
-- | /O(n)/ Yield the vector obtained by replacing each element @i@ of the
-- index vector by @xs'!'i@. This is equivalent to @'map' (xs'!') is@ but is
-- often much more efficient.
--
-- > backpermute <0,3,2,3,1,0> =
backpermute' :: (Vector v a)
=> U.Vector Int -- ^ @is@ index vector (of length @n@)
-> v a -- ^ @xs@ value vector
-> v a
--{-# INLINE backpermute' #-}
backpermute' is v = generate (G.length is) (\i -> v ! (is ! i))
embedPow', embedDec' :: (Additive r, Vector v r, m `Divides` m')
=> Tagged '(m, m') (v r -> v r)
-- | Embeds an vector in the powerful basis of the the mth cyclotomic ring
-- to an vector in the powerful basis of the m'th cyclotomic ring when @m | m'@
embedPow' = (\indices arr -> generate (U.length indices) $ \idx ->
let (j0,j1) = indices ! idx
in if j0 == 0
then arr ! j1
else zero) <$> baseIndicesPow
-- | Embeds an vector in the decoding basis of the the mth cyclotomic ring
-- to an vector in the decoding basis of the m'th cyclotomic ring when @m | m'@
embedDec' = (\indices arr -> generate (U.length indices)
(\idx -> maybe LP.zero
(\(sh,b) -> if b then negate (arr ! sh) else arr ! sh)
(indices U.! idx))) <$> baseIndicesDec
-- | Embeds an vector in the CRT basis of the the mth cyclotomic ring
-- to an vector in the CRT basis of the m'th cyclotomic ring when @m | m'@
embedCRT' :: forall m m' v r . (CRTrans r, Vector v r, m `Divides` m')
=> TaggedT '(m, m') Maybe (v r -> v r)
embedCRT' =
(lift (proxyT crtInfoFact (Proxy::Proxy m') :: Maybe (CRTInfo r))) >>
(pureT $ backpermute' <$> baseIndicesCRT)
-- | maps a vector in the powerful/decoding basis, representing an
-- O_m' element, to a vector of arrays representing O_m elements in
-- the same type of basis
coeffs' :: (Vector v r, m `Divides` m')
=> Tagged '(m, m') (v r -> [v r])
coeffs' = flip (\x -> V.toList . V.map (`backpermute'` x))
<$> extIndicesCoeffs
-- | The "tweaked trace" function in either the powerful or decoding
-- basis of the m'th cyclotomic ring to the mth cyclotomic ring when
-- @m | m'@.
twacePowDec' :: forall m m' r v . (Vector v r, m `Divides` m')
=> Tagged '(m, m') (v r -> v r)
twacePowDec' = backpermute' <$> extIndicesPowDec
-- EAC: twaceCRT is defined in CTensor because it needs access to C-backend functions
-- | The powerful extension basis, wrt the powerful basis.
-- Outputs a list of vectors in O_m' that are an O_m basis for O_m'
powBasisPow' :: forall m m' r . (m `Divides` m', Ring r, SV.Storable r)
=> Tagged '(m, m') [SV.Vector r]
powBasisPow' = do
(_, phi, phi', _) <- indexInfo
idxs <- baseIndicesPow
return $ LP.map (\k -> generate phi' $ \j ->
let (j0,j1) = idxs U.! j
in if j0==k && j1==0 then one else zero)
[0..phi' `div` phi - 1]
-- | A list of vectors representing the mod-p CRT set of the
-- extension O_m'/O_m
crtSetDec' :: forall m m' fp .
(m `Divides` m', PrimeField fp, Coprime (PToF (CharOf fp)) m', SV.Storable fp)
=> Tagged '(m, m') [SV.Vector fp]
crtSetDec' =
let m'p = Proxy :: Proxy m'
p = proxy valuePrime (Proxy::Proxy (CharOf fp))
phi = proxy totientFact m'p
d = proxy (order p) m'p
h :: Int = proxy valueHatFact m'p
hinv = recip $ fromIntegral h
in reify d $ \(_::Proxy d) -> do
let twCRTs' :: Matrix (GF fp d)
= fromMaybe (error "internal error: crtSetDec': twCRTs") $ proxyT twCRTs m'p
zmsToIdx = proxy T.zmsToIndexFact m'p
elt j i = indexM twCRTs' j (zmsToIdx i)
trace' = trace :: GF fp d -> fp -- to avoid recomputing powTraces
cosets <- partitionCosets p
return $ LP.map (\is -> generate phi
(\j -> hinv * trace'
(sum $ LP.map (elt j) is))) cosets