module Crypto.Lol.Types.ZqBasic
( ZqBasic
) where
import Crypto.Lol.CRTrans
import Crypto.Lol.Gadget
import Crypto.Lol.LatticePrelude as LP
import Crypto.Lol.Reflects
import Crypto.Lol.Types.FiniteField
import Crypto.Lol.Types.ZPP
import Math.NumberTheory.Primes.Factorisation
import Math.NumberTheory.Primes.Testing
import Control.Applicative
import Control.Arrow
import Control.DeepSeq (NFData)
import Data.Coerce
import Data.Maybe
import NumericPrelude.Numeric as NP (round)
import System.Random
import Test.QuickCheck
import qualified Data.Vector as V
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Generic.Mutable as M
import qualified Data.Vector.Unboxed as U
import Foreign.Storable
import qualified Data.Array.Repa.Eval as E
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)
newtype ZqBasic q z = ZqB z
deriving (Eq, Ord, ZeroTestable.C, E.Elt, Show, NFData, Storable)
type role ZqBasic nominal representational
type ReflectsTI q z = (Reflects q z, ToInteger z)
reduce' :: forall q z . (ReflectsTI q z) => z -> ZqBasic q z
reduce' = ZqB . (`mod` proxy value (Proxy::Proxy q))
decode' :: forall q z . (ReflectsTI q z) => ZqBasic q z -> z
decode' = let qval = proxy value (Proxy::Proxy q)
in \(ZqB x) -> if 2 * x < qval
then x
else x qval
instance (ReflectsTI q z, Enum z) => Enumerable (ZqBasic q z) where
values = let qval :: z = proxy value (Proxy::Proxy q)
in coerce [0..(qval1)]
instance (ReflectsTI q z) => Mod (ZqBasic q z) where
type ModRep (ZqBasic q z) = z
modulus = retag (value :: Tagged q z)
type instance CharOf (ZqBasic p z) = p
instance (PPow pp, zq ~ ZqBasic pp z,
PrimeField (ZpOf zq), Ring zq, Ring (ZpOf zq))
=> ZPP (ZqBasic (pp :: PrimePower) z) where
type ZpOf (ZqBasic pp z) = ZqBasic (PrimePP pp) z
modulusZPP = retag (ppPPow :: Tagged pp PP)
liftZp = coerce
instance (ReflectsTI q z) => Reduce z (ZqBasic q z) where
reduce = reduce'
instance (Reflects q z, Ring (ZqBasic q z)) => Reduce Integer (ZqBasic q z) where
reduce = fromInteger
type instance LiftOf (ZqBasic q z) = z
instance (ReflectsTI q z) => Lift' (ZqBasic q z) where
lift = decode'
instance (ReflectsTI q z, ReflectsTI q' z, Ring z)
=> Rescale (ZqBasic q z) (ZqBasic q' z) where
rescale = rescaleMod
instance (Reflects p z, ReflectsTI q z,
Field (ZqBasic p z), Field (ZqBasic q z))
=> Encode (ZqBasic p z) (ZqBasic q z) where
lsdToMSD = let pval :: z = proxy value (Proxy::Proxy p)
negqval :: z = negate $ proxy value (Proxy::Proxy q)
in (reduce' negqval, recip $ reduce' pval)
principalRootUnity :: forall q z . (ReflectsTI q z, Enumerable (ZqBasic q z))
=> Int -> Maybe (Int -> ZqBasic q z)
principalRootUnity =
let qval = fromIntegral $ (proxy value (Proxy::Proxy q) :: z)
order = qval1
pfactors = fst <$> factorise order
exps = div order <$> pfactors
isGen x = (x^order == one) && all (\e -> x^e /= one) exps
in if isPrime qval
then \m -> let (mq,mr) = order `divMod` fromIntegral m
in if mr == 0
then let omega = head (filter isGen values) ^ mq
omegaPows = V.iterateN m (*omega) one
in Just $ (omegaPows V.!) . (`mod` m)
else Nothing
else const Nothing
instance (ReflectsTI q z, PID z, Enumerable (ZqBasic q z))
=> CRTrans (ZqBasic q z) where
crtInfo =
let qval :: z = proxy value (Proxy::Proxy q)
in \m -> (,) <$> principalRootUnity m <*>
(reduce' <$> fromIntegral (valueHat m) `modinv` qval)
instance (ReflectsTI q z, Ring (ZqBasic q z)) => CRTEmbed (ZqBasic q z) where
type CRTExt (ZqBasic q z) = Complex Double
toExt (ZqB x) = fromReal $ fromIntegral x
fromExt x = reduce' $ NP.round $ real x
instance (ReflectsTI q z, Additive z) => Additive.C (ZqBasic q z) where
zero = ZqB zero
(+) = let qval = proxy value (Proxy::Proxy q)
in \ (ZqB x) (ZqB y) ->
let z = x + y
in ZqB (if z >= qval then z qval else z)
negate (ZqB x) = reduce' $ negate x
instance (ReflectsTI q z, Ring z) => Ring.C (ZqBasic q z) where
(ZqB x) * (ZqB y) = reduce' $ x * y
fromInteger =
let qval = toInteger (proxy value (Proxy::Proxy q) :: z)
in \x -> ZqB $ fromInteger $ x `mod` qval
instance (ReflectsTI q z, PID z, Show z) => Field.C (ZqBasic q z) where
recip = let qval = proxy value (Proxy::Proxy q)
in \(ZqB x) -> ZqB $
fromMaybe (error $ "ZqB.recip fail: " ++
show x ++ "\t" ++ show qval) $ modinv x qval
instance (Field (ZqBasic q z)) => IntegralDomain.C (ZqBasic q z) where
divMod a b = (a/b, zero)
instance (ReflectsTI q z, Additive z) => Gadget TrivGad (ZqBasic q z) where
gadget = tag [one]
instance (ReflectsTI q z, Ring z) => Decompose TrivGad (ZqBasic q z) where
type DecompOf (ZqBasic q z) = z
decompose x = tag [lift x]
instance (ReflectsTI q z, Ring z) => Correct TrivGad (ZqBasic q z) where
correct a = case untag a of
[b] -> (b, [zero])
_ -> 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 (ReflectsTI q z, RealIntegral z, Reflects b z)
=> Gadget (BaseBGad b) (ZqBasic q z) where
gadget = let qval = proxy value (Proxy :: Proxy q)
bval = proxy value (Proxy :: Proxy b)
in tag $ reduce' <$> gadgetZ bval qval
instance (ReflectsTI q z, Ring z, ZeroTestable z, Reflects b z)
=> Decompose (BaseBGad b) (ZqBasic q z) where
type DecompOf (ZqBasic q z) = z
decompose = let qval = proxy value (Proxy :: Proxy q)
bval = proxy value (Proxy :: Proxy b)
k = gadlen bval qval
radices = replicate (k1) bval
in tag . 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*v1v2) 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 = v0v'0 in ([y], y)
subLast (v0:vs) (v'0:v's) = first ((v0v'0):) $ subLast vs v's
instance (ReflectsTI q z, Ring z, Reflects b z)
=> Correct (BaseBGad b) (ZqBasic q z) where
correct =
let qval = proxy value (Proxy :: Proxy q)
bval = proxy value (Proxy :: Proxy b)
correct' = correctZ qval bval
in \tv -> let v = untag tv
es = correct' $ lift <$> v
in (head v reduce (head es), es)
instance (ReflectsTI q z, Random z) => Random (ZqBasic q z) where
random = let high = proxy value (Proxy::Proxy q) 1
in \g -> let (x,g') = randomR (0,high) g
in (ZqB x, g')
randomR _ = error "randomR non-sensical for Zq types"
instance (ReflectsTI q z, Random z) => Arbitrary (ZqBasic q z) where
arbitrary =
let qval :: z = proxy value (Proxy::Proxy q)
in fromIntegral <$> choose (0, qval1)
shrink = shrinkNothing
newtype instance U.MVector s (ZqBasic q z) = MV_ZqBasic (U.MVector s z)
newtype instance U.Vector (ZqBasic q z) = V_ZqBasic (U.Vector z)
instance U.Unbox z => U.Unbox (ZqBasic q z)
instance U.Unbox z => M.MVector U.MVector (ZqBasic q z) where
basicLength (MV_ZqBasic v) = M.basicLength v
basicUnsafeSlice z n (MV_ZqBasic v) = MV_ZqBasic $ M.basicUnsafeSlice z n v
basicOverlaps (MV_ZqBasic v1) (MV_ZqBasic v2) = M.basicOverlaps v1 v2
basicInitialize (MV_ZqBasic v) = M.basicInitialize v
basicUnsafeNew n = MV_ZqBasic <$> M.basicUnsafeNew n
basicUnsafeReplicate n (ZqB x) = MV_ZqBasic <$> M.basicUnsafeReplicate n x
basicUnsafeRead (MV_ZqBasic v) z = ZqB <$> M.basicUnsafeRead v z
basicUnsafeWrite (MV_ZqBasic v) z (ZqB x) = M.basicUnsafeWrite v z x
basicClear (MV_ZqBasic v) = M.basicClear v
basicSet (MV_ZqBasic v) (ZqB x) = M.basicSet v x
basicUnsafeCopy (MV_ZqBasic v1) (MV_ZqBasic v2) = M.basicUnsafeCopy v1 v2
basicUnsafeMove (MV_ZqBasic v1) (MV_ZqBasic v2) = M.basicUnsafeMove v1 v2
basicUnsafeGrow (MV_ZqBasic v) n = MV_ZqBasic <$> M.basicUnsafeGrow v n
instance U.Unbox z => G.Vector U.Vector (ZqBasic q z) where
basicUnsafeFreeze (MV_ZqBasic v) = V_ZqBasic <$> G.basicUnsafeFreeze v
basicUnsafeThaw (V_ZqBasic v) = MV_ZqBasic <$> G.basicUnsafeThaw v
basicLength (V_ZqBasic v) = G.basicLength v
basicUnsafeSlice z n (V_ZqBasic v) = V_ZqBasic $ G.basicUnsafeSlice z n v
basicUnsafeIndexM (V_ZqBasic v) z = ZqB <$> G.basicUnsafeIndexM v z
basicUnsafeCopy (MV_ZqBasic mv) (V_ZqBasic v) = G.basicUnsafeCopy mv v
elemseq _ = seq