module Crypto.Lol.CRTrans
( CRTrans(..), CRTEmbed(..)
, CRTInfo
, crtInfoFact, crtInfoPPow, crtInfoNatC
, gEmbPPow, gEmbNatC
, omegaPowMod, zqHasCRT
) where
import Crypto.Lol.LatticePrelude
import Math.NumberTheory.Primes.Factorisation (carmichael, factorise)
import Control.Arrow
import Data.Singletons
import Data.Singletons.Prelude
import Data.Type.Natural (Sing (SS))
import qualified Data.Vector as V
type CRTInfo r = (Int -> r, r)
class Ring r => CRTrans r where
crtInfo :: Int -> Maybe (CRTInfo r)
crtInfo = const Nothing
class (Ring r, Ring (CRTExt r)) => CRTEmbed r where
type CRTExt r
toExt :: r -> CRTExt r
fromExt :: CRTExt r -> r
instance (CRTrans a, CRTrans b) => CRTrans (a,b) where
crtInfo i = do
(apow, aiInv) <- crtInfo i
(bpow, biInv) <- crtInfo i
return (apow &&& bpow, (aiInv, biInv))
instance (CRTEmbed a, CRTEmbed b) => CRTEmbed (a,b) where
type CRTExt (a,b) = (CRTExt a, CRTExt b)
toExt = toExt *** toExt
fromExt = fromExt *** fromExt
omegaPowMod :: forall r . (Mod r, Enumerable r, Ring r, Eq r)
=> Int -> Maybe (Int -> r)
omegaPowMod =
let
exponent = carmichael $ fromIntegral (proxy modulus (Proxy::Proxy r))
primes = map fst $ factorise exponent
exps = map (exponent `div`) primes
isGood x = (x^exponent == one) && all (\e -> x^e /= one) exps
in \m -> let (mq, mr) = exponent `divMod` fromIntegral m
in if mr == 0
then let omega = head (filter isGood values) ^ mq
omegaPows = V.iterateN m (*omega) one
in Just $ (omegaPows V.!) . (`mod` m)
else Nothing
omegaPowC :: (Transcendental a) => Int -> Int -> Complex a
omegaPowC m i = cis (2*pi*fromIntegral i / fromIntegral m)
crtInfoFact :: (Fact m, CRTrans r) => TaggedT m Maybe (CRTInfo r)
crtInfoFact = (tagT . crtInfo) =<< pureT valueFact
crtInfoPPow :: (PPow pp, CRTrans r) => TaggedT pp Maybe (CRTInfo r)
crtInfoPPow = (tagT . crtInfo) =<< pureT valuePPow
crtInfoNatC :: (NatC p, CRTrans r) => TaggedT p Maybe (CRTInfo r)
crtInfoNatC = (tagT . crtInfo) =<< pureT valueNatC
gEmbPPow :: forall pp r . (PPow pp, CRTrans r) => TaggedT pp Maybe (Int -> r)
gEmbPPow = tagT $ case (sing :: SPrimePower pp) of
(SPP (STuple2 sp (SS _))) -> withWitnessT gEmbNatC sp
gEmbNatC :: (NatC p, CRTrans r) => TaggedT p Maybe (Int -> r)
gEmbNatC = do
(f, _) <- crtInfoNatC
return $ \i -> one f i
zqHasCRT :: (ToInteger i, PID i) => i -> i -> Bool
zqHasCRT m q = let exponent = fromIntegral $ carmichael $
fromIntegral q
mhat = if 2 `divides` m then m `div` 2 else m
in m `divides` exponent && fst (extendedGCD mhat q) == one
instance (Transcendental a) => CRTrans (Complex a) where
crtInfo m = Just (omegaPowC m, recip $ fromIntegral $ valueHat m)
instance (Transcendental a) => CRTEmbed (Complex a) where
type CRTExt (Complex a) = Complex a
toExt = id
fromExt = id
instance CRTrans Double
instance CRTrans Int
instance CRTrans Int64
instance CRTrans Integer
instance CRTEmbed Double where
type CRTExt Double = Complex Double
toExt = fromReal . realToField
fromExt = realToField . real
instance CRTEmbed Int where
type CRTExt Int = Complex Double
toExt = fromIntegral
fromExt = fst . roundComplex
instance CRTEmbed Int64 where
type CRTExt Int64 = Complex Double
toExt = fromIntegral
fromExt = fst . roundComplex
instance CRTEmbed Integer where
type CRTExt Integer = Complex Double
toExt = fromIntegral
fromExt = fst . roundComplex