packages feed

lol-0.2.0.0: Crypto/Lol/Cyclotomic/Tensor/RepaTensor/Dec.hs

{-# LANGUAGE ConstraintKinds, FlexibleContexts, NoImplicitPrelude,
             RebindableSyntax, ScopedTypeVariables #-}

-- | Linear transforms and operations related to the decoding basis.

module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Dec
( tGaussianDec', gSqNormDec' ) where

import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon as R
import Crypto.Lol.GaussRandom
import Crypto.Lol.LatticePrelude

import Control.Monad.Random

-- | Given @v=r^2@, yields the decoding-basis coefficients of a sample
-- from the tweaked Gaussian @t_m \cdot D_r@.
tGaussianDec' :: forall m v r rnd .
                 (Fact m, OrdFloat r, Random r, Unbox r, Elt r,
                  ToRational v, MonadRandom rnd)
                 => v -> rnd (Arr m r)
tGaussianDec' =
  let pm = Proxy::Proxy m
      m = proxy valueFact pm
      n = proxy totientFact pm
      rad = proxy radicalFact pm
  in \v -> do             -- rnd monad
    x <- realGaussians (v * fromIntegral (m `div` rad)) n
    let arr = Arr $ fromUnboxed (Z:.n) x
    return $ fE arr

-- | The @E_m@ transformation for an arbitrary @m@.
fE :: (Fact m, Transcendental r, Unbox r, Elt r) => Arr m r -> Arr m r
fE = eval $ fTensor $ ppTensor pE

-- | The @E_p@ transformation for a prime @p@.
pE :: forall p r . (Prim p, Transcendental r, Unbox r, Elt r)
      => Tagged p (Trans r)
pE = let pval = proxy valuePrime (Proxy::Proxy p)
     in tag $ if pval==2 then Id 1
              else trans (pval-1) $ mulMat $ force $
                   fromFunction (Z :. pval-1 :. pval-1)
              (\(Z:.i:.j) ->
               -- sqrt(2)*[ cos(2pi*i*(j+1)/p) | sin(same) ]
               -- (signs of columns doesn't matter for our purposes.)
               let theta = 2 * pi * fromIntegral (i*(j+1)) /
                           fromIntegral pval
               in sqrt 2 * if j < pval `div` 2
                           then cos theta else sin theta)

-- | Given coefficient tensor @e@ with respect to the decoding basis
-- of @R@, yield the (scaled) squared norm of @g_m \cdot e@ under
-- the canonical embedding, namely,
--  @\hat{m}^{ -1 } \cdot || \sigma(g_m -- \cdot e) ||^2@ .
gSqNormDec' :: (Fact m, Ring r, Unbox r, Elt r) => Arr m r -> r
gSqNormDec' e@(Arr ae) = let (Arr ae') = fGramDec' e
                         -- use sumAllP (define it in RTCommon)?
                         in sumAllS $ force $ R.zipWith (*) ae ae'

-- | Multiply by @\hat{m}@ times the Gram matrix of decoding basis of
-- @R^vee@.
fGramDec' :: (Fact m, Ring r, Unbox r, Elt r) => Arr m r -> Arr m r
fGramDec' = eval $ fTensor $ ppTensor pGramDec

-- | Multiply by (scaled) Gram matrix of decoding basis: (I_{p-1} + all-1s).
pGramDec :: forall p r . (Prim p, Ring r, Unbox r, Elt r) => Tagged p (Trans r)
pGramDec =
  let pval = proxy valuePrime (Proxy::Proxy p)
  in tag $ if pval==2 then Id 1
           else trans (pval-1) $
                    \arr -> let sums = sumS arr
                            in fromFunction (extent arr)
                                   (\sh@(sh' :. _) -> arr ! sh + sums ! sh')