{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Crypto.Lol.Types.Unsafe.ZqBasic
( ZqBasic(..)
, goodQs
) where
import Crypto.Lol.CRTrans
import Crypto.Lol.Gadget
import Crypto.Lol.Prelude as LP
import Crypto.Lol.Reflects
import Math.NumberTheory.Primes
import Control.Applicative
import Control.Arrow
import Control.DeepSeq (NFData, force)
import Data.Maybe
import NumericPrelude.Numeric as NP (round)
import System.Random
import qualified Data.Vector as V
import qualified Algebra.Additive as Additive (C)
import qualified Algebra.Field as Field (C)
import qualified Algebra.IntegralDomain as IntegralDomain (C)
import qualified Algebra.Ring as Ring (C)
import qualified Algebra.ZeroTestable as ZeroTestable (C)
goodQs :: (ToInteger a) => a -> a -> [a]
goodQs m lower = filter (isJust . isPrime . toInteger) $
iterate (+m) $ lower + ((m-lower) `mod` m) + 1
{-# SPECIALIZE goodQs :: Int64 -> Int64 -> [Int64] #-}
newtype ZqBasic q z = ZqB { unZqB :: z }
deriving (Eq, Ord, ZeroTestable.C, Show, NFData)
type role ZqBasic nominal representational
reduce' :: forall q z . (Reflects q z, IntegralDomain z) => z -> ZqBasic q z
reduce' = ZqB . (`mod` value @q)
{-# INLINABLE reduce' #-}
decode' :: forall q z . (Reflects q z, Ring z, Ord z) => ZqBasic q z -> z
decode' = let qval = value @q
in \(ZqB x) -> if 2 * x < qval then x else x - qval
{-# INLINABLE decode' #-}
instance (Reflects q z, Ring z, Enum z) => Enumerable (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Enumerable (ZqBasic q Int64) #-}
values = ZqB <$> [0..(value @q - 1)]
instance (Reflects q z, ToInteger z) => Mod (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Mod (ZqBasic q Int64) #-}
type ModRep (ZqBasic q z) = z
modulus = value @q
type instance CharOf (ZqBasic p z) = p
instance (Reflects q z, IntegralDomain z) => Reduce z (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Reduce Int64 (ZqBasic q Int64) #-}
reduce = reduce'
instance {-# OVERLAPPING #-} (Reflects q z, ToInteger z) => Reduce Integer (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Reduce Integer (ZqBasic q Int64) #-}
reduce = fromInteger
type instance LiftOf (ZqBasic q z) = z
instance (Reflects q z, Ring z, Ord z, IntegralDomain z)
=> Lift' (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Lift' (ZqBasic q Int64) #-}
lift = decode'
instance (Reflects q z, ToInteger z, Reflects q' z, Ring z)
=> Rescale (ZqBasic q z) (ZqBasic q' z) where
{-# SPECIALIZE instance (Reflects q Int64, Reflects q' Int64) => Rescale (ZqBasic q Int64) (ZqBasic q' Int64) #-}
rescale = rescaleMod
instance (Reflects p z, Reflects q z, IntegralDomain z,
Field (ZqBasic q z), Field (ZqBasic p z))
=> Encode (ZqBasic p z) (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects p Int64, Reflects q Int64) => Encode (ZqBasic p Int64) (ZqBasic q Int64) #-}
lsdToMSD = let pval = value @p
negqval = negate $ value @q
in (reduce' negqval, recip $ reduce' pval)
principalRootUnity :: forall m q z .
(Reflects m Int, Reflects q z, ToInteger z, Enum z, NFData z)
=> TaggedT m Maybe (Int -> ZqBasic q z)
principalRootUnity =
let qval = fromIntegral (value @q :: z)
mval = value @m
order = qval-1
pfactors = unPrime . fst <$> (factorise @Integer) order
exps = div order <$> pfactors
isGen x = (x^order == one) && all (\e -> x^e /= one) exps
in tagT $ if isJust (isPrime qval)
then let (mq,mr) = order `divMod` fromIntegral mval
in if mr == 0
then let omega = head (filter isGen values) ^ mq
omegaPows = force $ V.iterateN mval (*omega) one
in Just $ (omegaPows V.!) . (`mod` mval)
else Nothing
else Nothing
mhatInv :: forall m q z . (Reflects m Int, Reflects q z, ToInteger z, PID z)
=> TaggedT m Maybe (ZqBasic q z)
mhatInv = tagT $ reduce' <$>
(`modinv` value @q) (fromIntegral $ valueHat (value @m :: Int))
instance (Reflects q z, ToInteger z, PID z, Enum z, NFData z)
=> CRTrans Maybe (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => CRTrans Maybe (ZqBasic q Int64) #-}
{-# INLINABLE crtInfo #-}
crtInfo = (,) <$> principalRootUnity <*> mhatInv
instance (Reflects q z, ToInteger z, Ring (ZqBasic q z))
=> CRTEmbed (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => CRTEmbed (ZqBasic q Int64) #-}
type CRTExt (ZqBasic q z) = Complex Double
toExt (ZqB x) = fromReal $ fromIntegral x
fromExt = reduce' . NP.round . real
instance (Reflects q z, IntegralDomain z) => Additive.C (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Additive.C (ZqBasic q Int64) #-}
{-# INLINABLE zero #-}
zero = ZqB zero
{-# INLINABLE (+) #-}
(ZqB x) + (ZqB y) = reduce' $ x + y
{-# INLINABLE negate #-}
negate (ZqB x) = reduce' $ negate x
instance (Reflects q z, ToInteger z) => Ring.C (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Ring.C (ZqBasic q Int64) #-}
{-# INLINABLE (*) #-}
(ZqB x) * (ZqB y) = reduce' $ x * y
{-# INLINABLE fromInteger #-}
fromInteger =
let qval = toInteger (value @q :: z)
in \x -> ZqB $ fromInteger $ x `mod` qval
instance (Reflects q z, ToInteger z, PID z, Show z) => Field.C (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Field.C (ZqBasic q Int64) #-}
{-# INLINABLE recip #-}
recip = let qval = value @q
in \(ZqB x) -> ZqB $
fromMaybe (error $ "ZqB.recip fail: " ++
show x ++ "\t" ++ show qval) $ modinv x qval
instance (Reflects q z, ToInteger z, PID z, Show z)
=> IntegralDomain.C (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => IntegralDomain.C (ZqBasic q Int64) #-}
divMod a b = (a/b, zero)
instance (Reflects q z, ToInteger z) => Gadget TrivGad (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Gadget TrivGad (ZqBasic q Int64) #-}
gadget = [one]
instance (Reflects q z, ToInteger z) => Decompose TrivGad (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Decompose TrivGad (ZqBasic q Int64) #-}
type DecompOf (ZqBasic q z) = z
decompose x = [lift x]
instance (Reflects q z, ToInteger z, Ring z) => Correct TrivGad (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Correct TrivGad (ZqBasic q Int64) #-}
correct [b] = (b, [zero])
correct _ = error "Correct TrivGad: wrong length"
gadlen :: (RealIntegral z) => z -> z -> Int
gadlen _ q | isZero q = 0
gadlen b q = 1 + gadlen b (q `div` b)
gadgetZ :: (RealIntegral z) => z -> z -> [z]
gadgetZ b q = take (gadlen b q) $ iterate (*b) one
instance (Reflects q z, ToInteger z, RealIntegral z, Reflects b z)
=> Gadget (BaseBGad b) (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64, Reflects b Int64) => Gadget (BaseBGad b) (ZqBasic q Int64) #-}
gadget = let qval = value @q
bval = value @b
in reduce' <$> gadgetZ bval qval
instance (Reflects q z, ToInteger z, Reflects b z)
=> Decompose (BaseBGad b) (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64, Reflects b Int64) => Decompose (BaseBGad b) (ZqBasic q Int64) #-}
type DecompOf (ZqBasic q z) = z
decompose = let qval = value @q
bval = value @b
k = gadlen bval qval
radices = replicate (k-1) bval
in decomp radices . lift
correctZ :: forall z . (RealIntegral z)
=> z
-> z
-> [z]
-> [z]
correctZ q b =
let gadZ = gadgetZ b q
k = length gadZ
gadlast = last gadZ
in \v ->
if length v /= k
then error $ "correctZ: wrong length: was " ++ show (length v) ++", expected " ++ show k
else let (w, x) = barBtRnd (q `div` b) v
(v', v'l) = subLast v $ qbarD w x
s = fst $ v'l `divModCent` gadlast
in zipWith (-) v' $ (s*) <$> gadZ
where
barBtRnd :: z -> [z] -> ([z], z)
barBtRnd _ [_] = ([], zero)
barBtRnd q' (v1:vs@(v2:_)) = let quo = fst $ divModCent (b*v1-v2) q
in (quo:) *** (quo*q' +) $
barBtRnd (q' `div` b) vs
qbarD :: [z] -> z -> [z]
qbarD [] x = [x]
qbarD (w0:ws) x = x : qbarD ws (b*x - q*w0)
subLast :: [z] -> [z] -> ([z], z)
subLast [v0] [v'0] = let y = v0-v'0 in ([y], y)
subLast (v0:vs) (v'0:v's) = first ((v0-v'0):) $ subLast vs v's
instance (Reflects q z, ToInteger z, Reflects b z)
=> Correct (BaseBGad b) (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64, Reflects b Int64) => Correct (BaseBGad b) (ZqBasic q Int64) #-}
correct =
let qval = value @q
bval = value @b
correct' = correctZ qval bval
in \tv -> let es = correct' $ lift <$> tv
in (head tv - reduce (head es), es)
instance (Reflects q z, Ring z, Random z) => Random (ZqBasic q z) where
{-# SPECIALIZE instance (Reflects q Int64) => Random (ZqBasic q Int64) #-}
random = let high = value @q - 1
in \g -> let (x,g') = randomR (0,high) g
in (ZqB x, g')
randomR _ = error "randomR non-sensical for Zq types"
{-# INLINABLE random #-}