packages feed

lol 0.1.0.0 → 0.2.0.0

raw patch · 101 files changed

+10904/−10105 lines, 101 filesdep +DRBGdep +binarydep +bytestringdep −storable-tupledep −timedep −type-naturaldep ~MonadRandomdep ~basedep ~constraintsPVP ok

version bump matches the API change (PVP)

Dependencies added: DRBG, binary, bytestring, criterion, crypto-api, template-haskell

Dependencies removed: storable-tuple, time, type-natural

Dependency ranges changed: MonadRandom, base, constraints, deepseq, mtl, random, repa, singletons, transformers, vector

API changes (from Hackage documentation)

- Crypto.Lol.Applications.SymmSHE: addPublic :: (AddPublicCtx t m m' zp zq) => Cyc t m zp -> CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)
- Crypto.Lol.Applications.SymmSHE: addScalar :: (AddScalarCtx t m' zp zq) => zp -> CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)
- Crypto.Lol.Applications.SymmSHE: data CT (m :: Factored) zp r'q
- Crypto.Lol.Applications.SymmSHE: data SK r
- Crypto.Lol.Applications.SymmSHE: decrypt :: (DecryptCtx t m m' z zp zq) => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> PT (Cyc t m zp)
- Crypto.Lol.Applications.SymmSHE: decryptUnrestricted :: (Fact m, Fact m', CElt t zp, m `Divides` m', Reduce z zq, Lift' zq, CElt t z, ToSDCtx t m' zp zq, Reduce (LiftOf zq) zp) => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> PT (Cyc t m zp)
- Crypto.Lol.Applications.SymmSHE: embedCT :: (CElt t zq, r `Divides` r', s `Divides` s', r `Divides` s, r' `Divides` s') => CT r zp (Cyc t r' zq) -> CT s zp (Cyc t s' zq)
- Crypto.Lol.Applications.SymmSHE: embedSK :: (CElt t z, m `Divides` m') => SK (Cyc t m z) -> SK (Cyc t m' z)
- Crypto.Lol.Applications.SymmSHE: encrypt :: (EncryptCtx t m m' z zp zq, MonadRandom rnd) => SK (Cyc t m' z) -> PT (Cyc t m zp) -> rnd (CT m zp (Cyc t m' zq))
- Crypto.Lol.Applications.SymmSHE: errorTerm :: (ErrorTermCtx t m' z zp zq) => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> Cyc t m' (LiftOf zq)
- Crypto.Lol.Applications.SymmSHE: errorTermUnrestricted :: (Reduce z zq, Lift' zq, CElt t z, ToSDCtx t m' zp zq) => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> Cyc t m' (LiftOf zq)
- Crypto.Lol.Applications.SymmSHE: genSK :: (GenSKCtx t m z v, MonadRandom rnd) => v -> rnd (SK (Cyc t m z))
- Crypto.Lol.Applications.SymmSHE: instance (Control.DeepSeq.NFData zp, Control.DeepSeq.NFData r'q) => Control.DeepSeq.NFData (Crypto.Lol.Applications.SymmSHE.CT m zp r'q)
- Crypto.Lol.Applications.SymmSHE: instance (Crypto.Lol.Applications.SymmSHE.ToSDCtx t m' zp zq, Crypto.Lol.Types.Numeric.Additive (Crypto.Lol.Applications.SymmSHE.CT m zp (Crypto.Lol.Cyclotomic.Cyc.Cyc t m' zq))) => Algebra.Ring.C (Crypto.Lol.Applications.SymmSHE.CT m zp (Crypto.Lol.Cyclotomic.Cyc.Cyc t m' zq))
- Crypto.Lol.Applications.SymmSHE: instance (GHC.Classes.Eq zp, Crypto.Lol.Factored.Divides m m', Crypto.Lol.Applications.SymmSHE.ToSDCtx t m' zp zq) => Algebra.Additive.C (Crypto.Lol.Applications.SymmSHE.CT m zp (Crypto.Lol.Cyclotomic.Cyc.Cyc t m' zq))
- Crypto.Lol.Applications.SymmSHE: instance (GHC.Show.Show zp, GHC.Show.Show r'q) => GHC.Show.Show (Crypto.Lol.Applications.SymmSHE.CT m zp r'q)
- Crypto.Lol.Applications.SymmSHE: instance Control.DeepSeq.NFData r => Control.DeepSeq.NFData (Crypto.Lol.Applications.SymmSHE.SK r)
- Crypto.Lol.Applications.SymmSHE: instance GHC.Classes.Eq Crypto.Lol.Applications.SymmSHE.Encoding
- Crypto.Lol.Applications.SymmSHE: instance GHC.Show.Show Crypto.Lol.Applications.SymmSHE.Encoding
- Crypto.Lol.Applications.SymmSHE: keySwitchLinear :: (KeySwitchCtx gad t m' zp zq zq', KSHintCtx gad t m' z zq', MonadRandom rnd) => SK (Cyc t m' z) -> SK (Cyc t m' z) -> TaggedT (gad, zq') rnd (CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq))
- Crypto.Lol.Applications.SymmSHE: keySwitchQuadCirc :: (KeySwitchCtx gad t m' zp zq zq', KSHintCtx gad t m' z zq', MonadRandom rnd) => SK (Cyc t m' z) -> TaggedT (gad, zq') rnd (CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq))
- Crypto.Lol.Applications.SymmSHE: modSwitchPT :: (ModSwitchPTCtx t m' zp zp' zq) => CT m zp (Cyc t m' zq) -> CT m zp' (Cyc t m' zq)
- Crypto.Lol.Applications.SymmSHE: mulPublic :: (MulPublicCtx t m m' zp zq) => Cyc t m zp -> CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)
- Crypto.Lol.Applications.SymmSHE: rescaleLinearCT :: (RescaleCyc (Cyc t) zq zq', ToSDCtx t m' zp zq) => CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq')
- Crypto.Lol.Applications.SymmSHE: toLSD :: ToSDCtx t m' zp zq => CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)
- Crypto.Lol.Applications.SymmSHE: toMSD :: ToSDCtx t m' zp zq => CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)
- Crypto.Lol.Applications.SymmSHE: tunnelCT :: (TunnelCtx t e r s e' r' s' z zp zq zq' gad, MonadRandom rnd) => Linear t zp e r s -> SK (Cyc t s' z) -> SK (Cyc t r' z) -> TaggedT (gad, zq') rnd (CT r zp (Cyc t r' zq) -> CT s zp (Cyc t s' zq))
- Crypto.Lol.Applications.SymmSHE: twaceCT :: (CElt t zq, r `Divides` r', s' `Divides` r', s ~ (FGCD s' r)) => CT r zp (Cyc t r' zq) -> CT s zp (Cyc t s' zq)
- Crypto.Lol.Applications.SymmSHE: type AddPublicCtx t m m' zp zq = (Lift' zp, Reduce (LiftOf zp) zq, m `Divides` m', CElt t zp, CElt t (LiftOf zp), ToSDCtx t m' zp zq)
- Crypto.Lol.Applications.SymmSHE: type DecryptCtx t m m' z zp zq = (ErrorTermCtx t m' z zp zq, Reduce (LiftOf zq) zp, m `Divides` m', CElt t zp)
- Crypto.Lol.Applications.SymmSHE: type EncryptCtx t m m' z zp zq = (Mod zp, Ring zp, Ring zq, Lift zp (ModRep zp), Reduce z zq, Reduce (LiftOf zp) zq, CElt t zq, CElt t zp, CElt t z, CElt t (LiftOf zp), m `Divides` m')
- Crypto.Lol.Applications.SymmSHE: type ErrorTermCtx t m' z zp zq = (Reduce z zq, Lift' zq, CElt t z, CElt t (LiftOf zq), ToSDCtx t m' zp zq)
- Crypto.Lol.Applications.SymmSHE: type GenSKCtx t m z v = (ToInteger z, Fact m, CElt t z, ToRational v, NFData v)
- Crypto.Lol.Applications.SymmSHE: type InnerKeySwitchCtx gad t m' zq zq' = (RescaleCyc (Cyc t) zq' zq, RescaleCyc (Cyc t) zq zq', Decompose gad zq', KnapsackCtx t m' (DecompOf zq') zq')
- Crypto.Lol.Applications.SymmSHE: type KSHintCtx gad t m' z zq = (LWECtx t m' z zq, Reduce (DecompOf zq) zq, Gadget gad zq, CElt t (DecompOf zq))
- Crypto.Lol.Applications.SymmSHE: type KeySwitchCtx gad t m' zp zq zq' = (ToSDCtx t m' zp zq, InnerKeySwitchCtx gad t m' zq zq')
- Crypto.Lol.Applications.SymmSHE: type ModSwitchPTCtx t m' zp zp' zq = (Lift' zp, Reduce (LiftOf zp) zp', ToSDCtx t m' zp zq)
- Crypto.Lol.Applications.SymmSHE: type MulPublicCtx t m m' zp zq = (Lift' zp, Reduce (LiftOf zp) zq, Ring zq, m `Divides` m', CElt t zp, CElt t (LiftOf zp), CElt t zq)
- Crypto.Lol.Applications.SymmSHE: type PT rp = rp
- Crypto.Lol.Applications.SymmSHE: type ToSDCtx t m' zp zq = (Encode zp zq, Fact m', CElt t zq)
- Crypto.Lol.Applications.SymmSHE: type TunnelCtx t e r s e' r' s' z zp zq zq' gad = (ExtendLinIdx e r s e' r' s', e' ~ (e * (r' / r)), KSHintCtx gad t r' z zq', Reduce z zq, Lift zp z, CElt t zp, KeySwitchCtx gad t s' zp zq zq')
- Crypto.Lol.CRTrans: crtInfoNatC :: (NatC p, CRTrans r) => TaggedT p Maybe (CRTInfo r)
- Crypto.Lol.CRTrans: gEmbNatC :: (NatC p, CRTrans r) => TaggedT p Maybe (Int -> r)
- Crypto.Lol.CRTrans: omegaPowMod :: (Mod r, Enumerable r, Ring r, Eq r) => Int -> Maybe (Int -> r)
- Crypto.Lol.CRTrans: zqHasCRT :: (ToInteger i, PID i) => i -> i -> Bool
- Crypto.Lol.Cyclotomic.Cyc: cyc :: UCyc t m r -> Cyc t m r
- Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.LatticePrelude.Reduce a b, Crypto.Lol.Factored.Fact m, Crypto.Lol.Cyclotomic.UCyc.CElt t a, Crypto.Lol.Cyclotomic.UCyc.CElt t b) => Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a) (Crypto.Lol.Cyclotomic.Cyc.Cyc t m b)
- Crypto.Lol.Cyclotomic.Cyc: instance (System.Random.Random r, Data.Singletons.SingI m, Algebra.IntegralDomain.C r, Algebra.ZeroTestable.C r, Crypto.Lol.CRTrans.CRTrans r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => System.Random.Random (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
- Crypto.Lol.Cyclotomic.Cyc: instance Control.DeepSeq.NFData (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) => Control.DeepSeq.NFData (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a)
- Crypto.Lol.Cyclotomic.Cyc: instance Crypto.Lol.Cyclotomic.Utility.RescaleCyc (Crypto.Lol.Cyclotomic.UCyc.UCyc t) a b => Crypto.Lol.Cyclotomic.Utility.RescaleCyc (Crypto.Lol.Cyclotomic.Cyc.Cyc t) a b
- Crypto.Lol.Cyclotomic.Cyc: instance Crypto.Lol.Types.Numeric.Additive (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a)
- Crypto.Lol.Cyclotomic.Cyc: instance Crypto.Lol.Types.Numeric.Ring (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) => Algebra.Ring.C (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a)
- Crypto.Lol.Cyclotomic.Cyc: instance GHC.Classes.Eq (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) => GHC.Classes.Eq (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a)
- Crypto.Lol.Cyclotomic.Cyc: instance GHC.Show.Show (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) => GHC.Show.Show (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a)
- Crypto.Lol.Cyclotomic.Cyc: instance Test.QuickCheck.Arbitrary.Arbitrary (t m r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
- Crypto.Lol.Cyclotomic.Cyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.Factored.Factored -> * -> *) (m :: Crypto.Lol.Factored.Factored) a. Crypto.Lol.Gadget.Correct gad (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) => Crypto.Lol.Gadget.Correct gad (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a)
- Crypto.Lol.Cyclotomic.Cyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.Factored.Factored -> * -> *) (m :: Crypto.Lol.Factored.Factored) a. Crypto.Lol.Gadget.Gadget gad (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) => Crypto.Lol.Gadget.Gadget gad (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a)
- Crypto.Lol.Cyclotomic.Cyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.Factored.Factored -> * -> *) (m :: Crypto.Lol.Factored.Factored) zq. (Crypto.Lol.Gadget.Decompose gad (Crypto.Lol.Cyclotomic.UCyc.UCyc t m zq), Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.Cyc.Cyc t m (Crypto.Lol.Gadget.DecompOf zq)) (Crypto.Lol.Cyclotomic.Cyc.Cyc t m zq)) => Crypto.Lol.Gadget.Decompose gad (Crypto.Lol.Cyclotomic.Cyc.Cyc t m zq)
- Crypto.Lol.Cyclotomic.Cyc: unsafeUnCyc :: Cyc t m r -> UCyc t m r
- Crypto.Lol.Cyclotomic.Linear: instance (Crypto.Lol.Cyclotomic.UCyc.CElt t zp, Crypto.Lol.Cyclotomic.UCyc.CElt t z, z ~ Crypto.Lol.LatticePrelude.LiftOf zp, Crypto.Lol.LatticePrelude.Lift zp z, Crypto.Lol.Factored.Fact s) => Crypto.Lol.LatticePrelude.Lift' (Crypto.Lol.Cyclotomic.Linear.Linear t zp e r s)
- Crypto.Lol.Cyclotomic.Linear: instance (Crypto.Lol.LatticePrelude.Reduce z zq, Crypto.Lol.Factored.Fact s, Crypto.Lol.Cyclotomic.UCyc.CElt t z, Crypto.Lol.Cyclotomic.UCyc.CElt t zq) => Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.Linear.Linear t z e r s) (Crypto.Lol.Cyclotomic.Linear.Linear t zq e r s)
- Crypto.Lol.Cyclotomic.Tensor: entailRingT :: Tensor t => Tagged (t m r) ((Ring r, Fact m, TElt t r) :- (Ring (t m r)))
- Crypto.Lol.Cyclotomic.Tensor.CTensor: class CRNS r
- Crypto.Lol.Cyclotomic.Tensor.CTensor: class Dispatch r
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Crypto.Lol.Cyclotomic.Tensor.TElt Crypto.Lol.Cyclotomic.Tensor.CTensor.CT (Crypto.Lol.Types.Complex.Complex a), Crypto.Lol.Cyclotomic.Tensor.CTensor.Dispatch (Crypto.Lol.Types.Complex.Complex a)) => Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS (Crypto.Lol.Types.Complex.Complex a)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Crypto.Lol.Factored.Fact m, Crypto.Lol.Types.Numeric.Ring r, Foreign.Storable.Storable r, Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS r) => Algebra.Ring.C (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m r)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Crypto.Lol.Types.Numeric.Additive r, Foreign.Storable.Storable r, Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS r, Crypto.Lol.Factored.Fact m) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m r)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Crypto.Lol.Types.Numeric.ZeroTestable r, Foreign.Storable.Storable r, Crypto.Lol.Factored.Fact m) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m r)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Foreign.Storable.Storable a, Foreign.Storable.Storable b, Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS a, Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS b, Crypto.Lol.CRTrans.CRTrans a, Crypto.Lol.CRTrans.CRTrans b, Crypto.Lol.Types.Numeric.ZeroTestable a, Crypto.Lol.Types.Numeric.ZeroTestable b, Crypto.Lol.Types.Numeric.IntegralDomain a, Crypto.Lol.Types.Numeric.IntegralDomain b, System.Random.Random a, System.Random.Random b) => Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS (a, b)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Foreign.Storable.Storable r, System.Random.Random r, Crypto.Lol.Factored.Fact m) => System.Random.Random (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT' m r)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Test.QuickCheck.Arbitrary.Arbitrary r, Crypto.Lol.Factored.Fact m, Foreign.Storable.Storable r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT' m r)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS GHC.Int.Int64
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS GHC.Types.Double
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Cyclotomic.Tensor.CTensor.Dispatch (Crypto.Lol.Types.Complex.Complex GHC.Types.Double)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Cyclotomic.Tensor.CTensor.Dispatch GHC.Int.Int64
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Cyclotomic.Tensor.CTensor.Dispatch GHC.Types.Double
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Factored.Fact m => Data.Foldable.Foldable (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Factored.Fact m => Data.Traversable.Traversable (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Factored.Fact m => GHC.Base.Applicative (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.Factored.Fact m => GHC.Base.Functor (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Foreign.Storable.Storable Crypto.Lol.Cyclotomic.Tensor.CTensor.CPP
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance GHC.Show.Show Crypto.Lol.Cyclotomic.Tensor.CTensor.CPP
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance forall (k :: BOX) (q :: k) i. (Crypto.Lol.Cyclotomic.Tensor.TElt Crypto.Lol.Cyclotomic.Tensor.CTensor.CT (Crypto.Lol.Types.ZqBasic.ZqBasic q i), Crypto.Lol.Cyclotomic.Tensor.CTensor.Dispatch (Crypto.Lol.Types.ZqBasic.ZqBasic q i)) => Crypto.Lol.Cyclotomic.Tensor.CTensor.CRNS (Crypto.Lol.Types.ZqBasic.ZqBasic q i)
- Crypto.Lol.Cyclotomic.Tensor.CTensor: instance forall (k :: BOX) (q :: k). Crypto.Lol.Reflects.Reflects q GHC.Int.Int64 => Crypto.Lol.Cyclotomic.Tensor.CTensor.Dispatch (Crypto.Lol.Types.ZqBasic.ZqBasic q GHC.Int.Int64)
- Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance (Crypto.Lol.Factored.Fact m, Crypto.Lol.Types.Numeric.Additive r, Data.Vector.Unboxed.Base.Unbox r, Data.Array.Repa.Eval.Elt.Elt r) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m r)
- Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance (Crypto.Lol.Factored.Fact m, Crypto.Lol.Types.Numeric.Ring r, Data.Vector.Unboxed.Base.Unbox r, Data.Array.Repa.Eval.Elt.Elt r) => Algebra.Ring.C (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m r)
- Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance (Crypto.Lol.Factored.Fact m, Crypto.Lol.Types.Numeric.ZeroTestable r, Data.Vector.Unboxed.Base.Unbox r, Data.Array.Repa.Eval.Elt.Elt r) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m r)
- Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.Factored.Fact m => Data.Foldable.Foldable (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
- Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.Factored.Fact m => Data.Traversable.Traversable (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
- Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.Factored.Fact m => GHC.Base.Applicative (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
- Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.Factored.Fact m => GHC.Base.Functor (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
- Crypto.Lol.Cyclotomic.UCyc: Dec :: Basis
- Crypto.Lol.Cyclotomic.UCyc: Pow :: Basis
- Crypto.Lol.Cyclotomic.UCyc: adviseCRT :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r
- Crypto.Lol.Cyclotomic.UCyc: class RescaleCyc c a b
- Crypto.Lol.Cyclotomic.UCyc: coeffsCyc :: (m `Divides` m', CElt t r) => Basis -> UCyc t m' r -> [UCyc t m r]
- Crypto.Lol.Cyclotomic.UCyc: data Basis
- Crypto.Lol.Cyclotomic.UCyc: embed :: (m `Divides` m') => UCyc t m r -> UCyc t m' r
- Crypto.Lol.Cyclotomic.UCyc: fmapC :: (Fact m, CElt t a, CElt t b) => (a -> b) -> UCyc t m a -> UCyc t m b
- Crypto.Lol.Cyclotomic.UCyc: fmapCM :: (Fact m, CElt t a, CElt t b, Monad mon) => (a -> mon b) -> UCyc t m a -> mon (UCyc t m b)
- Crypto.Lol.Cyclotomic.UCyc: forceAny :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r
- Crypto.Lol.Cyclotomic.UCyc: forceBasis :: (Fact m, CElt t r) => Maybe Basis -> UCyc t m r -> UCyc t m r
- Crypto.Lol.Cyclotomic.UCyc: forceDec :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r
- Crypto.Lol.Cyclotomic.UCyc: forcePow :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.Factored.Fact m) => Data.Foldable.Foldable (Crypto.Lol.Cyclotomic.UCyc.UCyc t m)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.Factored.Fact m) => Data.Traversable.Traversable (Crypto.Lol.Cyclotomic.UCyc.UCyc t m)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.Factored.Fact m) => GHC.Base.Applicative (Crypto.Lol.Cyclotomic.UCyc.UCyc t m)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.Factored.Fact m) => GHC.Base.Functor (Crypto.Lol.Cyclotomic.UCyc.UCyc t m)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.Factored.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Crypto.Lol.CRTrans.CRTrans r, System.Random.Random r, Crypto.Lol.Types.Numeric.ZeroTestable r, Crypto.Lol.Types.Numeric.IntegralDomain r) => System.Random.Random (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.Factored.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Crypto.Lol.Cyclotomic.Tensor.TElt t (Crypto.Lol.CRTrans.CRTExt r), Control.DeepSeq.NFData r, Control.DeepSeq.NFData (Crypto.Lol.CRTrans.CRTExt r)) => Control.DeepSeq.NFData (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.UCyc.UCCtx t r, Crypto.Lol.Factored.Fact m) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.UCyc.UCCtx t r, Crypto.Lol.Factored.Fact m) => Algebra.Ring.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.UCyc.UCCtx t r, Crypto.Lol.Factored.Fact m) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.UCyc.UCCtx t r, Crypto.Lol.Factored.Fact m, GHC.Classes.Eq r) => GHC.Classes.Eq (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Mod a, Crypto.Lol.Types.Numeric.Field b, Crypto.Lol.LatticePrelude.Lift a (Crypto.Lol.LatticePrelude.ModRep a), Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.LatticePrelude.LiftOf a) b, Crypto.Lol.Cyclotomic.UCyc.CElt t a, Crypto.Lol.Cyclotomic.UCyc.CElt t b, Crypto.Lol.Cyclotomic.UCyc.CElt t (a, b), Crypto.Lol.Cyclotomic.UCyc.CElt t (Crypto.Lol.LatticePrelude.LiftOf a)) => Crypto.Lol.Cyclotomic.Utility.RescaleCyc (Crypto.Lol.Cyclotomic.UCyc.UCyc t) (a, b) b
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Reduce a b, Crypto.Lol.Factored.Fact m, Crypto.Lol.Cyclotomic.UCyc.CElt t a, Crypto.Lol.Cyclotomic.UCyc.CElt t b) => Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.UCyc.UCyc t m a) (Crypto.Lol.Cyclotomic.UCyc.UCyc t m b)
- Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Rescale a b, Crypto.Lol.Cyclotomic.UCyc.CElt t a, Crypto.Lol.Cyclotomic.UCyc.CElt t b) => Crypto.Lol.Cyclotomic.Utility.RescaleCyc (Crypto.Lol.Cyclotomic.UCyc.UCyc t) a b
- Crypto.Lol.Cyclotomic.UCyc: instance (GHC.Show.Show r, GHC.Show.Show (t m r), GHC.Show.Show (t m (Crypto.Lol.CRTrans.CRTExt r))) => GHC.Show.Show (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance Test.QuickCheck.Arbitrary.Arbitrary (t m r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.UCyc.UCyc t m r)
- Crypto.Lol.Cyclotomic.UCyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.Factored.Factored -> * -> *) (m :: Crypto.Lol.Factored.Factored) zq. (Crypto.Lol.Gadget.Correct gad zq, Crypto.Lol.Factored.Fact m, Crypto.Lol.Cyclotomic.UCyc.CElt t zq) => Crypto.Lol.Gadget.Correct gad (Crypto.Lol.Cyclotomic.UCyc.UCyc t m zq)
- Crypto.Lol.Cyclotomic.UCyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.Factored.Factored -> * -> *) (m :: Crypto.Lol.Factored.Factored) zq. (Crypto.Lol.Gadget.Decompose gad zq, Crypto.Lol.Factored.Fact m, Crypto.Lol.Cyclotomic.UCyc.CElt t zq, Crypto.Lol.Cyclotomic.UCyc.CElt t (Crypto.Lol.Gadget.DecompOf zq), Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Gadget.DecompOf zq) zq) => Crypto.Lol.Gadget.Decompose gad (Crypto.Lol.Cyclotomic.UCyc.UCyc t m zq)
- Crypto.Lol.Cyclotomic.UCyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.Factored.Factored -> * -> *) (m :: Crypto.Lol.Factored.Factored) zq. (Crypto.Lol.Gadget.Gadget gad zq, Crypto.Lol.Factored.Fact m, Crypto.Lol.Cyclotomic.UCyc.CElt t zq) => Crypto.Lol.Gadget.Gadget gad (Crypto.Lol.Cyclotomic.UCyc.UCyc t m zq)
- Crypto.Lol.Cyclotomic.UCyc: liftCyc :: (Lift b a, Fact m, CElt t a, CElt t b) => Basis -> UCyc t m b -> UCyc t m a
- Crypto.Lol.Cyclotomic.UCyc: scalarCyc :: (Fact m, CElt t a) => a -> UCyc t m a
- Crypto.Lol.Cyclotomic.UCyc: twace :: (UCCtx t r, m `Divides` m') => UCyc t m' r -> UCyc t m r
- Crypto.Lol.Cyclotomic.UCyc: type CElt t r = (Tensor t, RElt t r, RElt t (CRTExt r), CRTEmbed r, Eq r, Random r)
- Crypto.Lol.Cyclotomic.UCyc: type RElt t r = (TElt t r, CRTrans r, IntegralDomain r, ZeroTestable r, NFData r)
- Crypto.Lol.Cyclotomic.Utility: Dec :: Basis
- Crypto.Lol.Cyclotomic.Utility: Pow :: Basis
- Crypto.Lol.Cyclotomic.Utility: class RescaleCyc c a b
- Crypto.Lol.Cyclotomic.Utility: data Basis
- Crypto.Lol.Cyclotomic.Utility: instance Control.DeepSeq.NFData Crypto.Lol.Cyclotomic.Utility.Basis
- Crypto.Lol.Cyclotomic.Utility: rescaleCyc :: (RescaleCyc c a b, Fact m) => Basis -> c m a -> c m b
- Crypto.Lol.Factored: F :: [PrimePower] -> Factored
- Crypto.Lol.Factored: PP :: (Nat, Nat) -> PrimePower
- Crypto.Lol.Factored: data Nat :: *
- Crypto.Lol.Factored: instance Data.Singletons.Decide.SDecide 'Data.Proxy.KProxy
- Crypto.Lol.Factored: instance Data.Singletons.Prelude.Eq.PEq 'Data.Proxy.KProxy
- Crypto.Lol.Factored: instance Data.Singletons.Prelude.Eq.SEq 'Data.Proxy.KProxy
- Crypto.Lol.Factored: instance Data.Singletons.SingI n0 => Data.Singletons.SingI ('Crypto.Lol.Factored.F n0)
- Crypto.Lol.Factored: instance Data.Singletons.SingI n0 => Data.Singletons.SingI ('Crypto.Lol.Factored.PP n0)
- Crypto.Lol.Factored: instance Data.Singletons.SingKind 'Data.Proxy.KProxy
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.ExponentPPSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FDivSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FDivSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FDividesSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FDividesSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FGCDSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FGCDSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FLCMSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FLCMSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FMulSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FMulSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FOddRadicalSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FPPMulSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FPPMulSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.FSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464426Scrutinee_1627464407Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464426Scrutinee_1627464407Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464426Scrutinee_1627464407Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464426Scrutinee_1627464407Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464426Scrutinee_1627464407Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464454Scrutinee_1627464409Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464454Scrutinee_1627464409Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464454Scrutinee_1627464409Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464454Scrutinee_1627464409Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464454Scrutinee_1627464409Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464524PpSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464524PpSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627464524PpSym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477504PSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477504PSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477504PSym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477533Scrutinee_1627477483Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477533Scrutinee_1627477483Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477533Scrutinee_1627477483Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477533Scrutinee_1627477483Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477533Scrutinee_1627477483Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477533Scrutinee_1627477483Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477569Scrutinee_1627477485Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477569Scrutinee_1627477485Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477569Scrutinee_1627477485Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477569Scrutinee_1627477485Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477569Scrutinee_1627477485Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477569Scrutinee_1627477485Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477605Scrutinee_1627477487Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477605Scrutinee_1627477487Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477605Scrutinee_1627477487Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477605Scrutinee_1627477487Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477605Scrutinee_1627477487Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477605Scrutinee_1627477487Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477668Scrutinee_1627477481Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477668Scrutinee_1627477481Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477668Scrutinee_1627477481Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477668Scrutinee_1627477481Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477668Scrutinee_1627477481Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477668Scrutinee_1627477481Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477716YsSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477716YsSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477726XsSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477726XsSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477740Scrutinee_1627477469Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477740Scrutinee_1627477469Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477740Scrutinee_1627477469Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477740Scrutinee_1627477469Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477740Scrutinee_1627477469Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477740Scrutinee_1627477469Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477776Scrutinee_1627477471Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477776Scrutinee_1627477471Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477776Scrutinee_1627477471Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477776Scrutinee_1627477471Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477776Scrutinee_1627477471Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477776Scrutinee_1627477471Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477841Scrutinee_1627477465Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477841Scrutinee_1627477465Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477841Scrutinee_1627477465Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477841Scrutinee_1627477465Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477841Scrutinee_1627477465Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477841Scrutinee_1627477465Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477877Scrutinee_1627477467Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477877Scrutinee_1627477467Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477877Scrutinee_1627477467Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477877Scrutinee_1627477467Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477877Scrutinee_1627477467Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627477877Scrutinee_1627477467Sym5
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502462GoSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502462GoSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502462GoSym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502479PpSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502479PpSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502479PpSym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502479PpSym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502479PpSym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502505Scrutinee_1627502447Sym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502505Scrutinee_1627502447Sym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502505Scrutinee_1627502447Sym2
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502505Scrutinee_1627502447Sym3
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.Let1627502505Scrutinee_1627502447Sym4
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PFreeSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PFreeSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PPSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpMulSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpMulSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpToFSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsDivSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsDivSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsDividesSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsDividesSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsGCDSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsGCDSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsLCMSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsLCMSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsMulSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsMulSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PpsOddRadSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PrimeNatSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PrimePPSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.PrimeToFSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.ToPPSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.ToPPSym1
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.UnFSym0
- Crypto.Lol.Factored: instance Data.Singletons.SuppressUnusedWarnings.SuppressUnusedWarnings Crypto.Lol.Factored.UnPPSym0
- Crypto.Lol.Factored: instance GHC.Classes.Eq Crypto.Lol.Factored.Factored
- Crypto.Lol.Factored: instance GHC.Classes.Eq Crypto.Lol.Factored.PrimePower
- Crypto.Lol.Factored: instance GHC.Show.Show Crypto.Lol.Factored.Factored
- Crypto.Lol.Factored: instance GHC.Show.Show Crypto.Lol.Factored.PrimePower
- Crypto.Lol.Factored: newtype Factored
- Crypto.Lol.Factored: newtype PrimePower
- Crypto.Lol.Factored: sToPP :: Sing t_amV0 -> Sing t_amV1 -> Sing (Apply (Apply ToPPSym0 t_amV0) t_amV1 :: PrimePower)
- Crypto.Lol.Factored: toPP :: Nat -> Nat -> PrimePower
- Crypto.Lol.Factored: type NatC (p :: Nat) = SingI p
- Crypto.Lol.Factored: type PToF p = PpToF (ToPP p N1)
- Crypto.Lol.Factored: type Prime p = (NatC p, PrimeNat p ~ True)
- Crypto.Lol.Factored: valueNatC :: (NatC p) => Tagged p Int
- Crypto.Lol.LatticePrelude: logCeil :: (ToInteger i) => i -> i -> Int
- Crypto.Lol.Reflects: instance (Crypto.Lol.Factored.Fact m, GHC.Real.Integral i) => Crypto.Lol.Reflects.Reflects m i
- Crypto.Lol.Reflects: instance (Crypto.Lol.Factored.NatC a, GHC.Real.Integral i) => Crypto.Lol.Reflects.Reflects a i
- Crypto.Lol.Reflects: instance (Crypto.Lol.Factored.PPow pp, GHC.Real.Integral i) => Crypto.Lol.Reflects.Reflects pp i
- Crypto.Lol.Reflects: instance (GHC.TypeLits.KnownNat a, GHC.Real.Integral i) => Crypto.Lol.Reflects.Reflects a i
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). (GHC.Classes.Eq fp, Algebra.ZeroTestable.C fp) => GHC.Classes.Eq (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). Algebra.Additive.C fp => Algebra.Additive.C (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). Algebra.ZeroTestable.C fp => Algebra.ZeroTestable.C (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). Control.DeepSeq.NFData fp => Control.DeepSeq.NFData (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). Crypto.Lol.Types.FiniteField.GFCtx fp deg => Algebra.Field.C (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). Crypto.Lol.Types.FiniteField.GFCtx fp deg => Algebra.Ring.C (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). Crypto.Lol.Types.FiniteField.GFCtx fp deg => Crypto.Lol.CRTrans.CRTrans (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). Crypto.Lol.Types.FiniteField.GFCtx fp deg => Crypto.Lol.LatticePrelude.Enumerable (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (deg :: k). GHC.Show.Show fp => GHC.Show.Show (Crypto.Lol.Types.FiniteField.GF fp deg)
- Crypto.Lol.Types.IrreducibleChar2: instance (Crypto.Lol.Types.PrimeField.CharOf a ~ Data.Type.Natural.Definitions.N2, Crypto.Lol.Types.Numeric.Ring a) => Crypto.Lol.Types.PrimeField.IrreduciblePoly a
- Crypto.Lol.Types.PrimeField: (^) :: (Ring a) => X -> Int -> Polynomial a
- Crypto.Lol.Types.PrimeField: X :: X
- Crypto.Lol.Types.PrimeField: class (Ring fp, Prime (CharOf fp)) => IrreduciblePoly fp
- Crypto.Lol.Types.PrimeField: data X
- Crypto.Lol.Types.PrimeField: irreduciblePoly :: (IrreduciblePoly fp, Reflects deg Int) => Tagged deg (Polynomial fp)
- Crypto.Lol.Types.PrimeField: taggedProxy :: Tagged s (Proxy s)
- Crypto.Lol.Types.PrimeField: type PrimeField fp = (Enumerable fp, Eq fp, ZeroTestable fp, Field fp, IrreduciblePoly fp)
- Crypto.Lol.Types.ZqBasic: instance (Crypto.Lol.Factored.PPow pp, zq ~ Crypto.Lol.Types.ZqBasic.ZqBasic pp z, Crypto.Lol.Types.PrimeField.PrimeField (Crypto.Lol.Types.ZPP.ZPOf zq), Crypto.Lol.Types.Numeric.Ring zq, Crypto.Lol.Types.Numeric.Ring (Crypto.Lol.Types.ZPP.ZPOf zq)) => Crypto.Lol.Types.ZPP.ZPP (Crypto.Lol.Types.ZqBasic.ZqBasic pp z)
- Crypto.Lol.Types.ZqBasic: instance forall (k :: BOX) (k1 :: BOX) (b :: k) (q :: k1) z. (Crypto.Lol.Types.ZqBasic.ReflectsTI q z, Crypto.Lol.Types.Numeric.Additive z, Crypto.Lol.Reflects.Reflects b z) => Crypto.Lol.Gadget.Gadget (Crypto.Lol.Gadget.BaseBGad b) (Crypto.Lol.Types.ZqBasic.ZqBasic q z)
- Crypto.Lol.Types.ZqBasic: instance forall (k :: BOX) (k1 :: BOX) (b :: k) (q :: k1) z. (Crypto.Lol.Types.ZqBasic.ReflectsTI q z, Crypto.Lol.Types.Numeric.Ring z, Crypto.Lol.Reflects.Reflects b z) => Crypto.Lol.Gadget.Decompose (Crypto.Lol.Gadget.BaseBGad b) (Crypto.Lol.Types.ZqBasic.ZqBasic q z)
- Crypto.Lol.Types.ZqBasic: instance forall (k :: BOX) (q :: k) z r. (Crypto.Lol.Reflects.Reflects q z, Crypto.Lol.Types.Numeric.PID z, r ~ Crypto.Lol.Types.ZqBasic.ZqBasic q z, Crypto.Lol.LatticePrelude.Mod r, Crypto.Lol.LatticePrelude.Enumerable r, GHC.Show.Show z) => Crypto.Lol.CRTrans.CRTrans (Crypto.Lol.Types.ZqBasic.ZqBasic q z)
+ Crypto.Lol.CRTrans: crtInfoPrime :: (Prim p, CRTrans r) => TaggedT p Maybe (CRTInfo r)
+ Crypto.Lol.CRTrans: gEmbPrime :: (Prim p, CRTrans r) => TaggedT p Maybe (Int -> r)
+ Crypto.Lol.Cyclotomic.Cyc: Dec :: Basis
+ Crypto.Lol.Cyclotomic.Cyc: Pow :: Basis
+ Crypto.Lol.Cyclotomic.Cyc: class RescaleCyc c a b
+ Crypto.Lol.Cyclotomic.Cyc: cycCRT :: UCyc t m C r -> Cyc t m r
+ Crypto.Lol.Cyclotomic.Cyc: cycDec :: UCyc t m D r -> Cyc t m r
+ Crypto.Lol.Cyclotomic.Cyc: cycPow :: UCyc t m P r -> Cyc t m r
+ Crypto.Lol.Cyclotomic.Cyc: data Basis
+ Crypto.Lol.Cyclotomic.Cyc: gSqNorm :: (Fact m, CElt t r) => Cyc t m r -> r
+ Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Control.DeepSeq.NFData r, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Control.DeepSeq.NFData (Crypto.Lol.CRTrans.CRTExt r), Crypto.Lol.Cyclotomic.Tensor.TElt t (Crypto.Lol.CRTrans.CRTExt r)) => Control.DeepSeq.NFData (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t r) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t r) => Algebra.Ring.C (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t r) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.LatticePrelude.Mod a, Crypto.Lol.Types.Numeric.Field b, Crypto.Lol.LatticePrelude.Lift a (Crypto.Lol.LatticePrelude.ModRep a), Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.LatticePrelude.LiftOf a) b, Crypto.Lol.Cyclotomic.Cyc.CElt t (a, b), Crypto.Lol.Cyclotomic.Cyc.CElt t a, Crypto.Lol.Cyclotomic.Cyc.CElt t b, Crypto.Lol.Cyclotomic.Cyc.CElt t (Crypto.Lol.LatticePrelude.LiftOf a)) => Crypto.Lol.Cyclotomic.RescaleCyc.RescaleCyc (Crypto.Lol.Cyclotomic.Cyc.Cyc t) (a, b) b
+ Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.LatticePrelude.Reduce a b, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t a, Crypto.Lol.Cyclotomic.Cyc.CElt t b) => Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.Cyc.Cyc t m a) (Crypto.Lol.Cyclotomic.Cyc.Cyc t m b)
+ Crypto.Lol.Cyclotomic.Cyc: instance (Crypto.Lol.LatticePrelude.Rescale a b, Crypto.Lol.Cyclotomic.Cyc.CElt t a, Crypto.Lol.Cyclotomic.Tensor.TElt t b) => Crypto.Lol.Cyclotomic.RescaleCyc.RescaleCyc (Crypto.Lol.Cyclotomic.Cyc.Cyc t) a b
+ Crypto.Lol.Cyclotomic.Cyc: instance (GHC.Classes.Eq r, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t r) => GHC.Classes.Eq (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance (GHC.Show.Show r, GHC.Show.Show (Crypto.Lol.CRTrans.CRTExt r), Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Crypto.Lol.Cyclotomic.Tensor.TElt t (Crypto.Lol.CRTrans.CRTExt r)) => GHC.Show.Show (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance (System.Random.Random r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.CRTElt t r) => System.Random.Random (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.Cyc.Cyc t m r)
+ Crypto.Lol.Cyclotomic.Cyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.FactoredDefs.Factored -> * -> *) (m :: Crypto.Lol.FactoredDefs.Factored) zq. (Crypto.Lol.Gadget.Correct gad zq, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t zq) => Crypto.Lol.Gadget.Correct gad (Crypto.Lol.Cyclotomic.Cyc.Cyc t m zq)
+ Crypto.Lol.Cyclotomic.Cyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.FactoredDefs.Factored -> * -> *) (m :: Crypto.Lol.FactoredDefs.Factored) zq. (Crypto.Lol.Gadget.Decompose gad zq, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t zq, Crypto.Lol.Cyclotomic.Cyc.CElt t (Crypto.Lol.Gadget.DecompOf zq)) => Crypto.Lol.Gadget.Decompose gad (Crypto.Lol.Cyclotomic.Cyc.Cyc t m zq)
+ Crypto.Lol.Cyclotomic.Cyc: instance forall (k :: BOX) (gad :: k) (t :: Crypto.Lol.FactoredDefs.Factored -> * -> *) (m :: Crypto.Lol.FactoredDefs.Factored) zq. (Crypto.Lol.Gadget.Gadget gad zq, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t zq) => Crypto.Lol.Gadget.Gadget gad (Crypto.Lol.Cyclotomic.Cyc.Cyc t m zq)
+ Crypto.Lol.Cyclotomic.Cyc: instance forall (k :: BOX) fp (d :: k) (t :: Crypto.Lol.FactoredDefs.Factored -> * -> *) (m :: Crypto.Lol.FactoredDefs.Factored). (Crypto.Lol.Types.FiniteField.GFCtx fp d, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Cyc.CElt t fp) => Algebra.Module.C (Crypto.Lol.Types.FiniteField.GF fp d) (Crypto.Lol.Cyclotomic.Cyc.Cyc t m fp)
+ Crypto.Lol.Cyclotomic.Cyc: liftDec :: (Lift b a, Fact m, TElt t a, CElt t b) => Cyc t m b -> Cyc t m a
+ Crypto.Lol.Cyclotomic.Cyc: liftPow :: (Lift b a, Fact m, TElt t a, CElt t b) => Cyc t m b -> Cyc t m a
+ Crypto.Lol.Cyclotomic.Cyc: rescaleCyc :: (RescaleCyc c a b, Fact m) => Basis -> c m a -> c m b
+ Crypto.Lol.Cyclotomic.Cyc: type NFElt r = (NFData r, NFData (CRTExt r))
+ Crypto.Lol.Cyclotomic.Cyc: uncycCRT :: (Fact m, CElt t r) => Cyc t m r -> UCyc t m C r
+ Crypto.Lol.Cyclotomic.Cyc: uncycDec :: (Fact m, CElt t r) => Cyc t m r -> UCyc t m D r
+ Crypto.Lol.Cyclotomic.Cyc: uncycPow :: (Fact m, CElt t r) => Cyc t m r -> UCyc t m P r
+ Crypto.Lol.Cyclotomic.Cyc: unzipCElt :: (Tensor t, Fact m, CElt t (a, b), CElt t a, CElt t b) => Cyc t m (a, b) -> (Cyc t m a, Cyc t m b)
+ Crypto.Lol.Cyclotomic.Cyc: unzipCyc :: (Tensor t, Fact m) => Cyc t m (a, b) -> (Cyc t m a, Cyc t m b)
+ Crypto.Lol.Cyclotomic.Linear: instance (Crypto.Lol.Cyclotomic.Cyc.CElt t zp, Crypto.Lol.Cyclotomic.Cyc.CElt t z, z ~ Crypto.Lol.LatticePrelude.LiftOf zp, Crypto.Lol.LatticePrelude.Lift zp z, Crypto.Lol.FactoredDefs.Fact s) => Crypto.Lol.LatticePrelude.Lift' (Crypto.Lol.Cyclotomic.Linear.Linear t zp e r s)
+ Crypto.Lol.Cyclotomic.Linear: instance (Crypto.Lol.LatticePrelude.Reduce z zq, Crypto.Lol.FactoredDefs.Fact s, Crypto.Lol.Cyclotomic.Cyc.CElt t z, Crypto.Lol.Cyclotomic.Cyc.CElt t zq) => Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.Linear.Linear t z e r s) (Crypto.Lol.Cyclotomic.Linear.Linear t zq e r s)
+ Crypto.Lol.Cyclotomic.RescaleCyc: Dec :: Basis
+ Crypto.Lol.Cyclotomic.RescaleCyc: Pow :: Basis
+ Crypto.Lol.Cyclotomic.RescaleCyc: class RescaleCyc c a b
+ Crypto.Lol.Cyclotomic.RescaleCyc: data Basis
+ Crypto.Lol.Cyclotomic.RescaleCyc: rescaleCyc :: (RescaleCyc c a b, Fact m) => Basis -> c m a -> c m b
+ Crypto.Lol.Cyclotomic.RescaleCyc: rescaleDec :: (RescaleCyc c a b, Fact m) => c m a -> c m b
+ Crypto.Lol.Cyclotomic.RescaleCyc: rescalePow :: (RescaleCyc c a b, Fact m) => c m a -> c m b
+ Crypto.Lol.Cyclotomic.Tensor: entailModuleT :: Tensor t => Tagged (GF fp d, t m fp) ((GFCtx fp d, Fact m, TElt t fp) :- Module (GF fp d) (t m fp))
+ Crypto.Lol.Cyclotomic.Tensor: entailShowT :: Tensor t => Tagged (t m r) ((Show r, Fact m, TElt t r) :- (Show (t m r)))
+ Crypto.Lol.Cyclotomic.Tensor: gSqNormDec :: (Tensor t, Ring r, Fact m, TElt t r) => t m r -> r
+ Crypto.Lol.Cyclotomic.Tensor: type CRTElt t r = (ZeroTestable r, IntegralDomain r, CRTrans r, TElt t r)
+ Crypto.Lol.Cyclotomic.Tensor: unzipT :: (Tensor t, Fact m) => t m (a, b) -> (t m a, t m b)
+ Crypto.Lol.Cyclotomic.Tensor: unzipTElt :: (Tensor t, Fact m, TElt t (a, b), TElt t a, TElt t b) => t m (a, b) -> (t m a, t m b)
+ Crypto.Lol.Cyclotomic.Tensor: zipWithT :: (Tensor t, Fact m, TElt t a, TElt t b, TElt t c) => (a -> b -> c) -> t m a -> t m b -> t m c
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Crypto.Lol.Types.Numeric.Additive r, Foreign.Storable.Storable r, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.CTensor.Backend.Dispatch r) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m r)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Crypto.Lol.Types.Numeric.ZeroTestable r, Foreign.Storable.Storable r, Crypto.Lol.FactoredDefs.Fact m) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m r)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Foreign.Storable.Storable r, System.Random.Random r, Crypto.Lol.FactoredDefs.Fact m) => System.Random.Random (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT' m r)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance (Test.QuickCheck.Arbitrary.Arbitrary r, Crypto.Lol.FactoredDefs.Fact m, Foreign.Storable.Storable r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT' m r)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.FactoredDefs.Fact m => Data.Foldable.Foldable (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.FactoredDefs.Fact m => Data.Traversable.Traversable (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.FactoredDefs.Fact m => GHC.Base.Applicative (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance Crypto.Lol.FactoredDefs.Fact m => GHC.Base.Functor (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m)
+ Crypto.Lol.Cyclotomic.Tensor.CTensor: instance forall (k :: BOX) fp (d :: k) (m :: Crypto.Lol.FactoredDefs.Factored). (Crypto.Lol.Types.FiniteField.GFCtx fp d, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Types.Numeric.Additive (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m fp)) => Algebra.Module.C (Crypto.Lol.Types.FiniteField.GF fp d) (Crypto.Lol.Cyclotomic.Tensor.CTensor.CT m fp)
+ Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance (Crypto.Lol.Types.Numeric.ZeroTestable (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon.Arr m r), Crypto.Lol.Types.Numeric.ZeroTestable (Crypto.Lol.Types.IZipVector.IZipVector m r)) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m r)
+ Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance (Data.Vector.Unboxed.Base.Unbox r, Crypto.Lol.Types.Numeric.Additive (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon.Arr m r)) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m r)
+ Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.FactoredDefs.Fact m => Data.Foldable.Foldable (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
+ Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.FactoredDefs.Fact m => Data.Traversable.Traversable (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
+ Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.FactoredDefs.Fact m => GHC.Base.Applicative (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
+ Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance Crypto.Lol.FactoredDefs.Fact m => GHC.Base.Functor (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m)
+ Crypto.Lol.Cyclotomic.Tensor.RepaTensor: instance forall (k :: BOX) fp (d :: k) (m :: Crypto.Lol.FactoredDefs.Factored). (Crypto.Lol.Types.FiniteField.GFCtx fp d, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Types.Numeric.Additive (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m fp)) => Algebra.Module.C (Crypto.Lol.Types.FiniteField.GF fp d) (Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RT m fp)
+ Crypto.Lol.Cyclotomic.UCyc: coeffsDec :: (Ring r, Tensor t, m `Divides` m', TElt t r) => UCyc t m' D r -> [UCyc t m D r]
+ Crypto.Lol.Cyclotomic.UCyc: coeffsPow :: (Ring r, Tensor t, m `Divides` m', TElt t r) => UCyc t m' P r -> [UCyc t m P r]
+ Crypto.Lol.Cyclotomic.UCyc: data C
+ Crypto.Lol.Cyclotomic.UCyc: data D
+ Crypto.Lol.Cyclotomic.UCyc: data P
+ Crypto.Lol.Cyclotomic.UCyc: embedCRT :: (m `Divides` m', UCElt t r) => UCyc t m C r -> Either (UCyc t m' P r) (UCyc t m' C r)
+ Crypto.Lol.Cyclotomic.UCyc: embedDec :: (Additive r, Tensor t, m `Divides` m', TElt t r) => UCyc t m D r -> UCyc t m' D r
+ Crypto.Lol.Cyclotomic.UCyc: embedPow :: (Additive r, Tensor t, m `Divides` m', TElt t r) => UCyc t m P r -> UCyc t m' P r
+ Crypto.Lol.Cyclotomic.UCyc: fmapDec :: (Tensor t, Fact m, TElt t a, TElt t b) => (a -> b) -> UCyc t m D a -> UCyc t m D b
+ Crypto.Lol.Cyclotomic.UCyc: fmapPow :: (Tensor t, Fact m, TElt t a, TElt t b) => (a -> b) -> UCyc t m P a -> UCyc t m P b
+ Crypto.Lol.Cyclotomic.UCyc: gSqNorm :: (Ring r, Tensor t, Fact m, TElt t r) => UCyc t m D r -> r
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => Data.Foldable.Foldable (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => Data.Foldable.Foldable (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => Data.Traversable.Traversable (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => Data.Traversable.Traversable (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => GHC.Base.Applicative (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => GHC.Base.Applicative (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => GHC.Base.Functor (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m) => GHC.Base.Functor (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.UCyc.NFElt r, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Crypto.Lol.Cyclotomic.Tensor.TElt t (Crypto.Lol.CRTrans.CRTExt r)) => Control.DeepSeq.NFData (Crypto.Lol.Cyclotomic.UCyc.UCyc t m rep r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.UCyc.UCElt t r) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.C r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.UCyc.UCElt t r) => Algebra.Ring.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.C r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Lift' r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Crypto.Lol.Cyclotomic.Tensor.TElt t (Crypto.Lol.LatticePrelude.LiftOf r)) => Crypto.Lol.LatticePrelude.Lift' (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Lift' r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Crypto.Lol.Cyclotomic.Tensor.TElt t (Crypto.Lol.LatticePrelude.LiftOf r)) => Crypto.Lol.LatticePrelude.Lift' (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Reduce a b, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t a, Crypto.Lol.Cyclotomic.Tensor.TElt t b) => Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D a) (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D b)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Reduce a b, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t a, Crypto.Lol.Cyclotomic.Tensor.TElt t b) => Crypto.Lol.LatticePrelude.Reduce (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P a) (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P b)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Rescale a b, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t a, Crypto.Lol.Cyclotomic.Tensor.TElt t b) => Crypto.Lol.LatticePrelude.Rescale (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D a) (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D b)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.LatticePrelude.Rescale a b, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t a, Crypto.Lol.Cyclotomic.Tensor.TElt t b) => Crypto.Lol.LatticePrelude.Rescale (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P a) (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P b)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.Additive r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.Additive r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => Algebra.Additive.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.Ring r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => Algebra.Module.C r (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.Ring r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => Algebra.Module.C r (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.Ring r, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.UCyc.UCElt t r) => Algebra.Module.C r (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.C r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.ZeroTestable r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.ZeroTestable r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (Crypto.Lol.Types.Numeric.ZeroTestable r, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.UCyc.UCElt t r) => Algebra.ZeroTestable.C (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.C r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (GHC.Classes.Eq r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => GHC.Classes.Eq (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (GHC.Classes.Eq r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r) => GHC.Classes.Eq (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (GHC.Classes.Eq r, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.UCyc.UCElt t r) => GHC.Classes.Eq (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.C r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (GHC.Show.Show r, GHC.Show.Show (Crypto.Lol.CRTrans.CRTExt r), Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.TElt t r, Crypto.Lol.Cyclotomic.Tensor.TElt t (Crypto.Lol.CRTrans.CRTExt r)) => GHC.Show.Show (Crypto.Lol.Cyclotomic.UCyc.UCyc t m rep r)
+ Crypto.Lol.Cyclotomic.UCyc: instance (System.Random.Random r, Crypto.Lol.Cyclotomic.Tensor.Tensor t, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.Tensor.CRTElt t r) => System.Random.Random (Data.Either.Either (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r) (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.C r))
+ Crypto.Lol.Cyclotomic.UCyc: instance forall (k :: BOX) (t :: k -> * -> *) (m :: k) r. Test.QuickCheck.Arbitrary.Arbitrary (t m r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.C r)
+ Crypto.Lol.Cyclotomic.UCyc: instance forall (k :: BOX) (t :: k -> * -> *) (m :: k) r. Test.QuickCheck.Arbitrary.Arbitrary (t m r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.D r)
+ Crypto.Lol.Cyclotomic.UCyc: instance forall (k :: BOX) (t :: k -> * -> *) (m :: k) r. Test.QuickCheck.Arbitrary.Arbitrary (t m r) => Test.QuickCheck.Arbitrary.Arbitrary (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P r)
+ Crypto.Lol.Cyclotomic.UCyc: instance forall (k :: BOX) fp (d :: k) (t :: Crypto.Lol.FactoredDefs.Factored -> * -> *) (m :: Crypto.Lol.FactoredDefs.Factored). (Crypto.Lol.Types.FiniteField.GFCtx fp d, Crypto.Lol.FactoredDefs.Fact m, Crypto.Lol.Cyclotomic.UCyc.UCElt t fp) => Algebra.Module.C (Crypto.Lol.Types.FiniteField.GF fp d) (Crypto.Lol.Cyclotomic.UCyc.UCyc t m Crypto.Lol.Cyclotomic.UCyc.P fp)
+ Crypto.Lol.Cyclotomic.UCyc: scalarCRT :: (Fact m, UCElt t r) => r -> UCyc t m C r
+ Crypto.Lol.Cyclotomic.UCyc: scalarPow :: (Tensor t, Fact m, Ring r, TElt t r) => r -> UCyc t m P r
+ Crypto.Lol.Cyclotomic.UCyc: toCRT :: (Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m C r
+ Crypto.Lol.Cyclotomic.UCyc: toDec :: (Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m D r
+ Crypto.Lol.Cyclotomic.UCyc: toPow :: (Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m P r
+ Crypto.Lol.Cyclotomic.UCyc: twaceCRT :: (m `Divides` m', UCElt t r) => UCyc t m' C r -> Either (UCyc t m P r) (UCyc t m C r)
+ Crypto.Lol.Cyclotomic.UCyc: twaceDec :: (Ring r, Tensor t, m `Divides` m', TElt t r) => UCyc t m' D r -> UCyc t m D r
+ Crypto.Lol.Cyclotomic.UCyc: twacePow :: (Ring r, Tensor t, m `Divides` m', TElt t r) => UCyc t m' P r -> UCyc t m P r
+ Crypto.Lol.Cyclotomic.UCyc: type NFElt r = (NFData r, NFData (CRTExt r))
+ Crypto.Lol.Cyclotomic.UCyc: type UCElt t r = (Tensor t, CRTEmbed r, CRTElt t r, CRTElt t (CRTExt r))
+ Crypto.Lol.Cyclotomic.UCyc: unzipCyc :: (Tensor t, Fact m) => UCyc t m rep (a, b) -> (UCyc t m rep a, UCyc t m rep b)
+ Crypto.Lol.Cyclotomic.UCyc: unzipUCElt :: (Tensor t, Fact m, UCElt t (a, b), UCElt t a, UCElt t b) => UCyc t m rep (a, b) -> (UCyc t m rep a, UCyc t m rep b)
+ Crypto.Lol.Factored: data Factored
+ Crypto.Lol.Factored: data Prime
+ Crypto.Lol.Factored: data PrimePower
+ Crypto.Lol.Factored: fDec :: Int -> DecQ
+ Crypto.Lol.Factored: fType :: Int -> TypeQ
+ Crypto.Lol.Factored: pDec :: Int -> DecQ
+ Crypto.Lol.Factored: pToF :: Prime -> Factored
+ Crypto.Lol.Factored: pToPP :: Prime -> PrimePower
+ Crypto.Lol.Factored: pType :: Int -> TypeQ
+ Crypto.Lol.Factored: ppDec :: PP -> DecQ
+ Crypto.Lol.Factored: ppType :: PP -> TypeQ
+ Crypto.Lol.Factored: sPToF :: Sing t_aOYE -> Sing (Apply PToFSym0 t_aOYE :: Factored)
+ Crypto.Lol.Factored: sPToPP :: Sing t_aOYD -> Sing (Apply PToPPSym0 t_aOYD :: PrimePower)
+ Crypto.Lol.Factored: type F1 = F '[]
+ Crypto.Lol.Factored: type F10 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F100 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F101 = F '[PP '(P (D1 (D0 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F102 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F1024 = F '[PP '(P (D0 B1), S (S (S (S (S (S (S (S (S O)))))))))]
+ Crypto.Lol.Factored: type F103 = F '[PP '(P (D1 (D1 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F104 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F105 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F106 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F107 = F '[PP '(P (D1 (D1 (D0 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F108 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), S (S O))]
+ Crypto.Lol.Factored: type F109 = F '[PP '(P (D1 (D0 (D1 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F11 = F '[PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F110 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F111 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F112 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F113 = F '[PP '(P (D1 (D0 (D0 (D0 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F114 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F115 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F116 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F117 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F118 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F119 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F12 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F120 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F121 = F '[PP '(P (D1 (D1 (D0 B1))), S O)]
+ Crypto.Lol.Factored: type F122 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F123 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F124 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F125 = F '[PP '(P (D1 (D0 B1)), S (S O))]
+ Crypto.Lol.Factored: type F126 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F127 = F '[PP '(P (D1 (D1 (D1 (D1 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F128 = F '[PP '(P (D0 B1), S (S (S (S (S (S O))))))]
+ Crypto.Lol.Factored: type F129 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F13 = F '[PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F130 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F131 = F '[PP '(P (D1 (D1 (D0 (D0 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F132 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F133 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F134 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F135 = F '[PP '(P (D1 B1), S (S O)), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F136 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F137 = F '[PP '(P (D1 (D0 (D0 (D1 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F138 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F139 = F '[PP '(P (D1 (D1 (D0 (D1 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F14 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F140 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F141 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F142 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F143 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F144 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 B1), S O)]
+ Crypto.Lol.Factored: type F145 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F146 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F147 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F148 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F149 = F '[PP '(P (D1 (D0 (D1 (D0 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F15 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F150 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F151 = F '[PP '(P (D1 (D1 (D1 (D0 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F152 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F153 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F154 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F155 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F156 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F157 = F '[PP '(P (D1 (D0 (D1 (D1 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F158 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F159 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F16 = F '[PP '(P (D0 B1), S (S (S O)))]
+ Crypto.Lol.Factored: type F160 = F '[PP '(P (D0 B1), S (S (S (S O)))), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F161 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F162 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S (S (S O)))]
+ Crypto.Lol.Factored: type F163 = F '[PP '(P (D1 (D1 (D0 (D0 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F164 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F165 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F166 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F167 = F '[PP '(P (D1 (D1 (D1 (D0 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F168 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F169 = F '[PP '(P (D1 (D0 (D1 B1))), S O)]
+ Crypto.Lol.Factored: type F17 = F '[PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F170 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F171 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F172 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F173 = F '[PP '(P (D1 (D0 (D1 (D1 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F174 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F175 = F '[PP '(P (D1 (D0 B1)), S O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F176 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F177 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F178 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D1 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F179 = F '[PP '(P (D1 (D1 (D0 (D0 (D1 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F18 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O)]
+ Crypto.Lol.Factored: type F180 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F181 = F '[PP '(P (D1 (D0 (D1 (D0 (D1 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F182 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F183 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F184 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F185 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F186 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F187 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F188 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F189 = F '[PP '(P (D1 B1), S (S O)), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F19 = F '[PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F190 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F191 = F '[PP '(P (D1 (D1 (D1 (D1 (D1 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F192 = F '[PP '(P (D0 B1), S (S (S (S (S O))))), PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F193 = F '[PP '(P (D1 (D0 (D0 (D0 (D0 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F194 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F195 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F196 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F197 = F '[PP '(P (D1 (D0 (D1 (D0 (D0 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F198 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F199 = F '[PP '(P (D1 (D1 (D1 (D0 (D0 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F2 = F '[PP '(P (D0 B1), O)]
+ Crypto.Lol.Factored: type F20 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F200 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F201 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F202 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F203 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F204 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F2048 = F '[PP '(P (D0 B1), S (S (S (S (S (S (S (S (S (S O))))))))))]
+ Crypto.Lol.Factored: type F205 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F206 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F207 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F208 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F209 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F21 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F210 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F211 = F '[PP '(P (D1 (D1 (D0 (D0 (D1 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F212 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F213 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F214 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F215 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F216 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), S (S O))]
+ Crypto.Lol.Factored: type F217 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F218 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F219 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F22 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F220 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F221 = F '[PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F222 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F223 = F '[PP '(P (D1 (D1 (D1 (D1 (D1 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F224 = F '[PP '(P (D0 B1), S (S (S (S O)))), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F225 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F226 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D0 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F227 = F '[PP '(P (D1 (D1 (D0 (D0 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F228 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F229 = F '[PP '(P (D1 (D0 (D1 (D0 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F23 = F '[PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F230 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F231 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F232 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F233 = F '[PP '(P (D1 (D0 (D0 (D1 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F234 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F235 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F236 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F237 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F238 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F239 = F '[PP '(P (D1 (D1 (D1 (D1 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F24 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F240 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F241 = F '[PP '(P (D1 (D0 (D0 (D0 (D1 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F242 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 B1))), S O)]
+ Crypto.Lol.Factored: type F243 = F '[PP '(P (D1 B1), S (S (S (S O))))]
+ Crypto.Lol.Factored: type F244 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F245 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F246 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F247 = F '[PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F248 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F249 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F25 = F '[PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F250 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), S (S O))]
+ Crypto.Lol.Factored: type F251 = F '[PP '(P (D1 (D1 (D0 (D1 (D1 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F252 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), S O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F253 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F254 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D1 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F255 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F256 = F '[PP '(P (D0 B1), S (S (S (S (S (S (S O)))))))]
+ Crypto.Lol.Factored: type F257 = F '[PP '(P (D1 (D0 (D0 (D0 (D0 (D0 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F258 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F259 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F26 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F260 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F261 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F262 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F263 = F '[PP '(P (D1 (D1 (D1 (D0 (D0 (D0 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F264 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F265 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F266 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F267 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D1 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F268 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F269 = F '[PP '(P (D1 (D0 (D1 (D1 (D0 (D0 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F27 = F '[PP '(P (D1 B1), S (S O))]
+ Crypto.Lol.Factored: type F270 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S (S O)), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F271 = F '[PP '(P (D1 (D1 (D1 (D1 (D0 (D0 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F272 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F273 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F274 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F275 = F '[PP '(P (D1 (D0 B1)), S O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F276 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F277 = F '[PP '(P (D1 (D0 (D1 (D0 (D1 (D0 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F278 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D1 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F279 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F28 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F280 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F281 = F '[PP '(P (D1 (D0 (D0 (D1 (D1 (D0 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F282 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F283 = F '[PP '(P (D1 (D1 (D0 (D1 (D1 (D0 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F284 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D1 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F285 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F286 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F287 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F288 = F '[PP '(P (D0 B1), S (S (S (S O)))), PP '(P (D1 B1), S O)]
+ Crypto.Lol.Factored: type F289 = F '[PP '(P (D1 (D0 (D0 (D0 B1)))), S O)]
+ Crypto.Lol.Factored: type F29 = F '[PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F290 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F291 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F292 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F293 = F '[PP '(P (D1 (D0 (D1 (D0 (D0 (D1 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F294 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F295 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F296 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F297 = F '[PP '(P (D1 B1), S (S O)), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F298 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D0 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F299 = F '[PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F3 = F '[PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F30 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F300 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F301 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F302 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D0 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F303 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F304 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F305 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F306 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F307 = F '[PP '(P (D1 (D1 (D0 (D0 (D1 (D1 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F308 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F309 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F31 = F '[PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F310 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F311 = F '[PP '(P (D1 (D1 (D1 (D0 (D1 (D1 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F312 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F313 = F '[PP '(P (D1 (D0 (D0 (D1 (D1 (D1 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F314 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D1 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F315 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F316 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D1 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F317 = F '[PP '(P (D1 (D0 (D1 (D1 (D1 (D1 (D0 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F318 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F319 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F32 = F '[PP '(P (D0 B1), S (S (S (S O))))]
+ Crypto.Lol.Factored: type F320 = F '[PP '(P (D0 B1), S (S (S (S (S O))))), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F321 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F322 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F323 = F '[PP '(P (D1 (D0 (D0 (D0 B1)))), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F324 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), S (S (S O)))]
+ Crypto.Lol.Factored: type F325 = F '[PP '(P (D1 (D0 B1)), S O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F326 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F327 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F328 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F329 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F33 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F330 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F331 = F '[PP '(P (D1 (D1 (D0 (D1 (D0 (D0 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F332 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 (D0 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F333 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F334 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F335 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F336 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F337 = F '[PP '(P (D1 (D0 (D0 (D0 (D1 (D0 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F338 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 B1))), S O)]
+ Crypto.Lol.Factored: type F339 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D0 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F34 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F340 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F341 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F342 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F343 = F '[PP '(P (D1 (D1 B1)), S (S O))]
+ Crypto.Lol.Factored: type F344 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F345 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F346 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D1 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F347 = F '[PP '(P (D1 (D1 (D0 (D1 (D1 (D0 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F348 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F349 = F '[PP '(P (D1 (D0 (D1 (D1 (D1 (D0 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F35 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F350 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), S O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F351 = F '[PP '(P (D1 B1), S (S O)), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F352 = F '[PP '(P (D0 B1), S (S (S (S O)))), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F353 = F '[PP '(P (D1 (D0 (D0 (D0 (D0 (D1 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F354 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F355 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F356 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D0 (D1 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F357 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F358 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 (D1 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F359 = F '[PP '(P (D1 (D1 (D1 (D0 (D0 (D1 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F36 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), S O)]
+ Crypto.Lol.Factored: type F360 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F361 = F '[PP '(P (D1 (D1 (D0 (D0 B1)))), S O)]
+ Crypto.Lol.Factored: type F362 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D0 (D1 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F363 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 B1))), S O)]
+ Crypto.Lol.Factored: type F364 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F365 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F366 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F367 = F '[PP '(P (D1 (D1 (D1 (D1 (D0 (D1 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F368 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F369 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F37 = F '[PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F370 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F371 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F372 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F373 = F '[PP '(P (D1 (D0 (D1 (D0 (D1 (D1 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F374 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F375 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), S (S O))]
+ Crypto.Lol.Factored: type F376 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F377 = F '[PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F378 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S (S O)), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F379 = F '[PP '(P (D1 (D1 (D0 (D1 (D1 (D1 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F38 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F380 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F381 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F382 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D1 (D1 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F383 = F '[PP '(P (D1 (D1 (D1 (D1 (D1 (D1 (D1 (D0 B1)))))))), O)]
+ Crypto.Lol.Factored: type F384 = F '[PP '(P (D0 B1), S (S (S (S (S (S O)))))), PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F385 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F386 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D0 (D0 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F387 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F388 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D0 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F389 = F '[PP '(P (D1 (D0 (D1 (D0 (D0 (D0 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F39 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F390 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F391 = F '[PP '(P (D1 (D0 (D0 (D0 B1)))), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F392 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F393 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F394 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F395 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F396 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F397 = F '[PP '(P (D1 (D0 (D1 (D1 (D0 (D0 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F398 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F399 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F4 = F '[PP '(P (D0 B1), S O)]
+ Crypto.Lol.Factored: type F40 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F400 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F401 = F '[PP '(P (D1 (D0 (D0 (D0 (D1 (D0 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F402 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F403 = F '[PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F404 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F405 = F '[PP '(P (D1 B1), S (S (S O))), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F406 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F407 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F408 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F409 = F '[PP '(P (D1 (D0 (D0 (D1 (D1 (D0 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F41 = F '[PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F410 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F411 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F412 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F413 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F414 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F415 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D0 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F416 = F '[PP '(P (D0 B1), S (S (S (S O)))), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F417 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D1 (D0 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F418 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F419 = F '[PP '(P (D1 (D1 (D0 (D0 (D0 (D1 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F42 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F420 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F421 = F '[PP '(P (D1 (D0 (D1 (D0 (D0 (D1 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F422 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 (D1 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F423 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F424 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F425 = F '[PP '(P (D1 (D0 B1)), S O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F426 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F427 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F428 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F429 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F43 = F '[PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F430 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F431 = F '[PP '(P (D1 (D1 (D1 (D1 (D0 (D1 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F432 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 B1), S (S O))]
+ Crypto.Lol.Factored: type F433 = F '[PP '(P (D1 (D0 (D0 (D0 (D1 (D1 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F434 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F435 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F436 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D1 (D1 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F437 = F '[PP '(P (D1 (D1 (D0 (D0 B1)))), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F438 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F439 = F '[PP '(P (D1 (D1 (D1 (D0 (D1 (D1 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F44 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F440 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F441 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F442 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F443 = F '[PP '(P (D1 (D1 (D0 (D1 (D1 (D1 (D0 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F444 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F445 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D1 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F446 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D1 (D1 (D0 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F447 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D0 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F448 = F '[PP '(P (D0 B1), S (S (S (S (S O))))), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F449 = F '[PP '(P (D1 (D0 (D0 (D0 (D0 (D0 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F45 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F450 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F451 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F452 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D0 (D0 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F453 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F454 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F455 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F456 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F457 = F '[PP '(P (D1 (D0 (D0 (D1 (D0 (D0 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F458 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F459 = F '[PP '(P (D1 B1), S (S O)), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F46 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F460 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F461 = F '[PP '(P (D1 (D0 (D1 (D1 (D0 (D0 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F462 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F463 = F '[PP '(P (D1 (D1 (D1 (D1 (D0 (D0 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F464 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F465 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F466 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F467 = F '[PP '(P (D1 (D1 (D0 (D0 (D1 (D0 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F468 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F469 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F47 = F '[PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F470 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F471 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D1 (D1 (D0 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F472 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F473 = F '[PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F474 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F475 = F '[PP '(P (D1 (D0 B1)), S O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F476 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F477 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F478 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D1 (D0 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F479 = F '[PP '(P (D1 (D1 (D1 (D1 (D1 (D0 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F48 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F480 = F '[PP '(P (D0 B1), S (S (S (S O)))), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F481 = F '[PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F482 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D0 (D1 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F483 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F484 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 B1))), S O)]
+ Crypto.Lol.Factored: type F485 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F486 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S (S (S (S O))))]
+ Crypto.Lol.Factored: type F487 = F '[PP '(P (D1 (D1 (D1 (D0 (D0 (D1 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F488 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F489 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F49 = F '[PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F490 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F491 = F '[PP '(P (D1 (D1 (D0 (D1 (D0 (D1 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F492 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F493 = F '[PP '(P (D1 (D0 (D0 (D0 B1)))), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F494 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 B1))), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F495 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F496 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F497 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F498 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F499 = F '[PP '(P (D1 (D1 (D0 (D0 (D1 (D1 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F5 = F '[PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F50 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F500 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 B1)), S (S O))]
+ Crypto.Lol.Factored: type F501 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 (D0 (D1 (D0 B1))))))), O)]
+ Crypto.Lol.Factored: type F502 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D1 (D1 (D1 (D1 B1))))))), O)]
+ Crypto.Lol.Factored: type F503 = F '[PP '(P (D1 (D1 (D1 (D0 (D1 (D1 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F504 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), S O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F505 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F506 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 B1))), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F507 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 B1))), S O)]
+ Crypto.Lol.Factored: type F508 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D1 (D1 (D1 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F509 = F '[PP '(P (D1 (D0 (D1 (D1 (D1 (D1 (D1 (D1 B1)))))))), O)]
+ Crypto.Lol.Factored: type F51 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F510 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F511 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D0 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F512 = F '[PP '(P (D0 B1), S (S (S (S (S (S (S (S O))))))))]
+ Crypto.Lol.Factored: type F52 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F53 = F '[PP '(P (D1 (D0 (D1 (D0 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F54 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S (S O))]
+ Crypto.Lol.Factored: type F55 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F56 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F57 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F58 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F59 = F '[PP '(P (D1 (D1 (D0 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F6 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F60 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F61 = F '[PP '(P (D1 (D0 (D1 (D1 (D1 B1))))), O)]
+ Crypto.Lol.Factored: type F62 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F63 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F64 = F '[PP '(P (D0 B1), S (S (S (S (S O)))))]
+ Crypto.Lol.Factored: type F65 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F66 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F67 = F '[PP '(P (D1 (D1 (D0 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F68 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F69 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F7 = F '[PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F70 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F71 = F '[PP '(P (D1 (D1 (D1 (D0 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F72 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 B1), S O)]
+ Crypto.Lol.Factored: type F73 = F '[PP '(P (D1 (D0 (D0 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F74 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D1 (D0 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F75 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 B1)), S O)]
+ Crypto.Lol.Factored: type F76 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F77 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F78 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F79 = F '[PP '(P (D1 (D1 (D1 (D1 (D0 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F8 = F '[PP '(P (D0 B1), S (S O))]
+ Crypto.Lol.Factored: type F80 = F '[PP '(P (D0 B1), S (S (S O))), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F81 = F '[PP '(P (D1 B1), S (S (S O)))]
+ Crypto.Lol.Factored: type F82 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D0 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F83 = F '[PP '(P (D1 (D1 (D0 (D0 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F84 = F '[PP '(P (D0 B1), S O), PP '(P (D1 B1), O), PP '(P (D1 (D1 B1)), O)]
+ Crypto.Lol.Factored: type F85 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D0 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F86 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D0 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F87 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D0 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F88 = F '[PP '(P (D0 B1), S (S O)), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type F89 = F '[PP '(P (D1 (D0 (D0 (D1 (D1 (D0 B1)))))), O)]
+ Crypto.Lol.Factored: type F9 = F '[PP '(P (D1 B1), S O)]
+ Crypto.Lol.Factored: type F90 = F '[PP '(P (D0 B1), O), PP '(P (D1 B1), S O), PP '(P (D1 (D0 B1)), O)]
+ Crypto.Lol.Factored: type F91 = F '[PP '(P (D1 (D1 B1)), O), PP '(P (D1 (D0 (D1 B1))), O)]
+ Crypto.Lol.Factored: type F92 = F '[PP '(P (D0 B1), S O), PP '(P (D1 (D1 (D1 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F93 = F '[PP '(P (D1 B1), O), PP '(P (D1 (D1 (D1 (D1 B1)))), O)]
+ Crypto.Lol.Factored: type F94 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 (D1 (D1 (D0 B1))))), O)]
+ Crypto.Lol.Factored: type F95 = F '[PP '(P (D1 (D0 B1)), O), PP '(P (D1 (D1 (D0 (D0 B1)))), O)]
+ Crypto.Lol.Factored: type F96 = F '[PP '(P (D0 B1), S (S (S (S O)))), PP '(P (D1 B1), O)]
+ Crypto.Lol.Factored: type F97 = F '[PP '(P (D1 (D0 (D0 (D0 (D0 (D1 B1)))))), O)]
+ Crypto.Lol.Factored: type F98 = F '[PP '(P (D0 B1), O), PP '(P (D1 (D1 B1)), S O)]
+ Crypto.Lol.Factored: type F99 = F '[PP '(P (D1 B1), S O), PP '(P (D1 (D1 (D0 B1))), O)]
+ Crypto.Lol.Factored: type PP11 = PP '(P (D1 (D1 (D0 B1))), O)
+ Crypto.Lol.Factored: type PP128 = PP '(P (D0 B1), S (S (S (S (S (S O))))))
+ Crypto.Lol.Factored: type PP16 = PP '(P (D0 B1), S (S (S O)))
+ Crypto.Lol.Factored: type PP2 = PP '(P (D0 B1), O)
+ Crypto.Lol.Factored: type PP27 = PP '(P (D1 B1), S (S O))
+ Crypto.Lol.Factored: type PP3 = PP '(P (D1 B1), O)
+ Crypto.Lol.Factored: type PP32 = PP '(P (D0 B1), S (S (S (S O))))
+ Crypto.Lol.Factored: type PP4 = PP '(P (D0 B1), S O)
+ Crypto.Lol.Factored: type PP5 = PP '(P (D1 (D0 B1)), O)
+ Crypto.Lol.Factored: type PP64 = PP '(P (D0 B1), S (S (S (S (S O)))))
+ Crypto.Lol.Factored: type PP7 = PP '(P (D1 (D1 B1)), O)
+ Crypto.Lol.Factored: type PP8 = PP '(P (D0 B1), S (S O))
+ Crypto.Lol.Factored: type PP81 = PP '(P (D1 B1), S (S (S O)))
+ Crypto.Lol.Factored: type PP9 = PP '(P (D1 B1), S O)
+ Crypto.Lol.Factored: type Prim (p :: Prime) = SingI p
+ Crypto.Lol.Factored: type Prime101 = P (D1 (D0 (D1 (D0 (D0 (D1 B1))))))
+ Crypto.Lol.Factored: type Prime103 = P (D1 (D1 (D1 (D0 (D0 (D1 B1))))))
+ Crypto.Lol.Factored: type Prime107 = P (D1 (D1 (D0 (D1 (D0 (D1 B1))))))
+ Crypto.Lol.Factored: type Prime109 = P (D1 (D0 (D1 (D1 (D0 (D1 B1))))))
+ Crypto.Lol.Factored: type Prime11 = P (D1 (D1 (D0 B1)))
+ Crypto.Lol.Factored: type Prime113 = P (D1 (D0 (D0 (D0 (D1 (D1 B1))))))
+ Crypto.Lol.Factored: type Prime127 = P (D1 (D1 (D1 (D1 (D1 (D1 B1))))))
+ Crypto.Lol.Factored: type Prime13 = P (D1 (D0 (D1 B1)))
+ Crypto.Lol.Factored: type Prime131 = P (D1 (D1 (D0 (D0 (D0 (D0 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime137 = P (D1 (D0 (D0 (D1 (D0 (D0 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime139 = P (D1 (D1 (D0 (D1 (D0 (D0 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime149 = P (D1 (D0 (D1 (D0 (D1 (D0 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime151 = P (D1 (D1 (D1 (D0 (D1 (D0 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime157 = P (D1 (D0 (D1 (D1 (D1 (D0 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime163 = P (D1 (D1 (D0 (D0 (D0 (D1 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime167 = P (D1 (D1 (D1 (D0 (D0 (D1 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime17 = P (D1 (D0 (D0 (D0 B1))))
+ Crypto.Lol.Factored: type Prime173 = P (D1 (D0 (D1 (D1 (D0 (D1 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime179 = P (D1 (D1 (D0 (D0 (D1 (D1 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime181 = P (D1 (D0 (D1 (D0 (D1 (D1 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime19 = P (D1 (D1 (D0 (D0 B1))))
+ Crypto.Lol.Factored: type Prime191 = P (D1 (D1 (D1 (D1 (D1 (D1 (D0 B1)))))))
+ Crypto.Lol.Factored: type Prime193 = P (D1 (D0 (D0 (D0 (D0 (D0 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime197 = P (D1 (D0 (D1 (D0 (D0 (D0 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime199 = P (D1 (D1 (D1 (D0 (D0 (D0 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime2 = P (D0 B1)
+ Crypto.Lol.Factored: type Prime211 = P (D1 (D1 (D0 (D0 (D1 (D0 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime223 = P (D1 (D1 (D1 (D1 (D1 (D0 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime227 = P (D1 (D1 (D0 (D0 (D0 (D1 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime229 = P (D1 (D0 (D1 (D0 (D0 (D1 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime23 = P (D1 (D1 (D1 (D0 B1))))
+ Crypto.Lol.Factored: type Prime233 = P (D1 (D0 (D0 (D1 (D0 (D1 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime239 = P (D1 (D1 (D1 (D1 (D0 (D1 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime241 = P (D1 (D0 (D0 (D0 (D1 (D1 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime251 = P (D1 (D1 (D0 (D1 (D1 (D1 (D1 B1)))))))
+ Crypto.Lol.Factored: type Prime257 = P (D1 (D0 (D0 (D0 (D0 (D0 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime263 = P (D1 (D1 (D1 (D0 (D0 (D0 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime269 = P (D1 (D0 (D1 (D1 (D0 (D0 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime271 = P (D1 (D1 (D1 (D1 (D0 (D0 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime277 = P (D1 (D0 (D1 (D0 (D1 (D0 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime281 = P (D1 (D0 (D0 (D1 (D1 (D0 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime283 = P (D1 (D1 (D0 (D1 (D1 (D0 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime29 = P (D1 (D0 (D1 (D1 B1))))
+ Crypto.Lol.Factored: type Prime293 = P (D1 (D0 (D1 (D0 (D0 (D1 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime3 = P (D1 B1)
+ Crypto.Lol.Factored: type Prime307 = P (D1 (D1 (D0 (D0 (D1 (D1 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime31 = P (D1 (D1 (D1 (D1 B1))))
+ Crypto.Lol.Factored: type Prime311 = P (D1 (D1 (D1 (D0 (D1 (D1 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime313 = P (D1 (D0 (D0 (D1 (D1 (D1 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime317 = P (D1 (D0 (D1 (D1 (D1 (D1 (D0 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime331 = P (D1 (D1 (D0 (D1 (D0 (D0 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime337 = P (D1 (D0 (D0 (D0 (D1 (D0 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime347 = P (D1 (D1 (D0 (D1 (D1 (D0 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime349 = P (D1 (D0 (D1 (D1 (D1 (D0 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime353 = P (D1 (D0 (D0 (D0 (D0 (D1 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime359 = P (D1 (D1 (D1 (D0 (D0 (D1 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime367 = P (D1 (D1 (D1 (D1 (D0 (D1 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime37 = P (D1 (D0 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.Factored: type Prime373 = P (D1 (D0 (D1 (D0 (D1 (D1 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime379 = P (D1 (D1 (D0 (D1 (D1 (D1 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime383 = P (D1 (D1 (D1 (D1 (D1 (D1 (D1 (D0 B1))))))))
+ Crypto.Lol.Factored: type Prime389 = P (D1 (D0 (D1 (D0 (D0 (D0 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime397 = P (D1 (D0 (D1 (D1 (D0 (D0 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime401 = P (D1 (D0 (D0 (D0 (D1 (D0 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime409 = P (D1 (D0 (D0 (D1 (D1 (D0 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime41 = P (D1 (D0 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.Factored: type Prime419 = P (D1 (D1 (D0 (D0 (D0 (D1 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime421 = P (D1 (D0 (D1 (D0 (D0 (D1 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime43 = P (D1 (D1 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.Factored: type Prime431 = P (D1 (D1 (D1 (D1 (D0 (D1 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime433 = P (D1 (D0 (D0 (D0 (D1 (D1 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime439 = P (D1 (D1 (D1 (D0 (D1 (D1 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime443 = P (D1 (D1 (D0 (D1 (D1 (D1 (D0 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime449 = P (D1 (D0 (D0 (D0 (D0 (D0 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime457 = P (D1 (D0 (D0 (D1 (D0 (D0 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime461 = P (D1 (D0 (D1 (D1 (D0 (D0 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime463 = P (D1 (D1 (D1 (D1 (D0 (D0 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime467 = P (D1 (D1 (D0 (D0 (D1 (D0 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime47 = P (D1 (D1 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.Factored: type Prime479 = P (D1 (D1 (D1 (D1 (D1 (D0 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime487 = P (D1 (D1 (D1 (D0 (D0 (D1 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime491 = P (D1 (D1 (D0 (D1 (D0 (D1 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime499 = P (D1 (D1 (D0 (D0 (D1 (D1 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime5 = P (D1 (D0 B1))
+ Crypto.Lol.Factored: type Prime503 = P (D1 (D1 (D1 (D0 (D1 (D1 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime509 = P (D1 (D0 (D1 (D1 (D1 (D1 (D1 (D1 B1))))))))
+ Crypto.Lol.Factored: type Prime521 = P (D1 (D0 (D0 (D1 (D0 (D0 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime523 = P (D1 (D1 (D0 (D1 (D0 (D0 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime53 = P (D1 (D0 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.Factored: type Prime541 = P (D1 (D0 (D1 (D1 (D1 (D0 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime547 = P (D1 (D1 (D0 (D0 (D0 (D1 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime557 = P (D1 (D0 (D1 (D1 (D0 (D1 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime563 = P (D1 (D1 (D0 (D0 (D1 (D1 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime569 = P (D1 (D0 (D0 (D1 (D1 (D1 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime571 = P (D1 (D1 (D0 (D1 (D1 (D1 (D0 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime577 = P (D1 (D0 (D0 (D0 (D0 (D0 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime587 = P (D1 (D1 (D0 (D1 (D0 (D0 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime59 = P (D1 (D1 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.Factored: type Prime593 = P (D1 (D0 (D0 (D0 (D1 (D0 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime599 = P (D1 (D1 (D1 (D0 (D1 (D0 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime601 = P (D1 (D0 (D0 (D1 (D1 (D0 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime607 = P (D1 (D1 (D1 (D1 (D1 (D0 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime61 = P (D1 (D0 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.Factored: type Prime613 = P (D1 (D0 (D1 (D0 (D0 (D1 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime617 = P (D1 (D0 (D0 (D1 (D0 (D1 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime619 = P (D1 (D1 (D0 (D1 (D0 (D1 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime631 = P (D1 (D1 (D1 (D0 (D1 (D1 (D1 (D0 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime641 = P (D1 (D0 (D0 (D0 (D0 (D0 (D0 (D1 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime643 = P (D1 (D1 (D0 (D0 (D0 (D0 (D0 (D1 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime647 = P (D1 (D1 (D1 (D0 (D0 (D0 (D0 (D1 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime653 = P (D1 (D0 (D1 (D1 (D0 (D0 (D0 (D1 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime659 = P (D1 (D1 (D0 (D0 (D1 (D0 (D0 (D1 (D0 B1)))))))))
+ Crypto.Lol.Factored: type Prime67 = P (D1 (D1 (D0 (D0 (D0 (D0 B1))))))
+ Crypto.Lol.Factored: type Prime7 = P (D1 (D1 B1))
+ Crypto.Lol.Factored: type Prime71 = P (D1 (D1 (D1 (D0 (D0 (D0 B1))))))
+ Crypto.Lol.Factored: type Prime73 = P (D1 (D0 (D0 (D1 (D0 (D0 B1))))))
+ Crypto.Lol.Factored: type Prime79 = P (D1 (D1 (D1 (D1 (D0 (D0 B1))))))
+ Crypto.Lol.Factored: type Prime83 = P (D1 (D1 (D0 (D0 (D1 (D0 B1))))))
+ Crypto.Lol.Factored: type Prime89 = P (D1 (D0 (D0 (D1 (D1 (D0 B1))))))
+ Crypto.Lol.Factored: type Prime97 = P (D1 (D0 (D0 (D0 (D0 (D1 B1))))))
+ Crypto.Lol.Factored: type SPrime = (Sing :: Prime -> *)
+ Crypto.Lol.Factored: valuePrime :: Prim p => Tagged p Int
+ Crypto.Lol.Gadget: instance forall (k :: BOX) (gad :: k) a b. (Crypto.Lol.Gadget.Correct gad a, Crypto.Lol.Gadget.Correct gad b, Crypto.Lol.LatticePrelude.Mod a, Crypto.Lol.LatticePrelude.Mod b, Crypto.Lol.Types.Numeric.Field a, Crypto.Lol.Types.Numeric.Field b, Crypto.Lol.LatticePrelude.Lift' a, Crypto.Lol.LatticePrelude.Lift' b, Crypto.Lol.Types.Numeric.ToInteger (Crypto.Lol.LatticePrelude.LiftOf a), Crypto.Lol.Types.Numeric.ToInteger (Crypto.Lol.LatticePrelude.LiftOf b)) => Crypto.Lol.Gadget.Correct gad (a, b)
+ Crypto.Lol.PosBin: B1 :: Bin
+ Crypto.Lol.PosBin: D0 :: Bin -> Bin
+ Crypto.Lol.PosBin: D1 :: Bin -> Bin
+ Crypto.Lol.PosBin: O :: Pos
+ Crypto.Lol.PosBin: S :: Pos -> Pos
+ Crypto.Lol.PosBin: addPos :: Pos -> Pos -> Pos
+ Crypto.Lol.PosBin: binDec :: Int -> DecQ
+ Crypto.Lol.PosBin: binToInt :: C z => Bin -> z
+ Crypto.Lol.PosBin: binType :: Int -> TypeQ
+ Crypto.Lol.PosBin: data AddPosSym0 (l_ayFQ :: TyFun Pos (TyFun Pos Pos -> *))
+ Crypto.Lol.PosBin: data AddPosSym1 (l_ayFT :: Pos) (l_ayFS :: TyFun Pos Pos)
+ Crypto.Lol.PosBin: data Bin
+ Crypto.Lol.PosBin: data D0Sym0 (l_aAoE :: TyFun Bin Bin)
+ Crypto.Lol.PosBin: data D1Sym0 (l_aAoH :: TyFun Bin Bin)
+ Crypto.Lol.PosBin: data Pos
+ Crypto.Lol.PosBin: data SSym0 (l_ayFx :: TyFun Pos Pos)
+ Crypto.Lol.PosBin: data SubPosSym0 (l_ayFB :: TyFun Pos (TyFun Pos Pos -> *))
+ Crypto.Lol.PosBin: data SubPosSym1 (l_ayFE :: Pos) (l_ayFD :: TyFun Pos Pos)
+ Crypto.Lol.PosBin: intDec :: String -> (Int -> TypeQ) -> Int -> DecQ
+ Crypto.Lol.PosBin: posDec :: Int -> DecQ
+ Crypto.Lol.PosBin: posToInt :: C z => Pos -> z
+ Crypto.Lol.PosBin: posType :: Int -> TypeQ
+ Crypto.Lol.PosBin: prime :: Int -> Bool
+ Crypto.Lol.PosBin: primes :: [Int]
+ Crypto.Lol.PosBin: sAddPos :: Sing t_ayJl -> Sing t_ayJm -> Sing (Apply (Apply AddPosSym0 t_ayJl) t_ayJm :: Pos)
+ Crypto.Lol.PosBin: sSubPos :: Sing t_ayJj -> Sing t_ayJk -> Sing (Apply (Apply SubPosSym0 t_ayJj) t_ayJk :: Pos)
+ Crypto.Lol.PosBin: subPos :: Pos -> Pos -> Pos
+ Crypto.Lol.PosBin: type B1 = B1
+ Crypto.Lol.PosBin: type B10 = D0 (D1 (D0 B1))
+ Crypto.Lol.PosBin: type B100 = D0 (D0 (D1 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B101 = D1 (D0 (D1 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B102 = D0 (D1 (D1 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B103 = D1 (D1 (D1 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B104 = D0 (D0 (D0 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B105 = D1 (D0 (D0 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B106 = D0 (D1 (D0 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B107 = D1 (D1 (D0 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B108 = D0 (D0 (D1 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B109 = D1 (D0 (D1 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B11 = D1 (D1 (D0 B1))
+ Crypto.Lol.PosBin: type B110 = D0 (D1 (D1 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B111 = D1 (D1 (D1 (D1 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B112 = D0 (D0 (D0 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B113 = D1 (D0 (D0 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B114 = D0 (D1 (D0 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B115 = D1 (D1 (D0 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B116 = D0 (D0 (D1 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B117 = D1 (D0 (D1 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B118 = D0 (D1 (D1 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B119 = D1 (D1 (D1 (D0 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B12 = D0 (D0 (D1 B1))
+ Crypto.Lol.PosBin: type B120 = D0 (D0 (D0 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B121 = D1 (D0 (D0 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B122 = D0 (D1 (D0 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B123 = D1 (D1 (D0 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B124 = D0 (D0 (D1 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B125 = D1 (D0 (D1 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B126 = D0 (D1 (D1 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B127 = D1 (D1 (D1 (D1 (D1 (D1 B1)))))
+ Crypto.Lol.PosBin: type B128 = D0 (D0 (D0 (D0 (D0 (D0 (D0 B1))))))
+ Crypto.Lol.PosBin: type B13 = D1 (D0 (D1 B1))
+ Crypto.Lol.PosBin: type B14 = D0 (D1 (D1 B1))
+ Crypto.Lol.PosBin: type B15 = D1 (D1 (D1 B1))
+ Crypto.Lol.PosBin: type B16 = D0 (D0 (D0 (D0 B1)))
+ Crypto.Lol.PosBin: type B17 = D1 (D0 (D0 (D0 B1)))
+ Crypto.Lol.PosBin: type B18 = D0 (D1 (D0 (D0 B1)))
+ Crypto.Lol.PosBin: type B19 = D1 (D1 (D0 (D0 B1)))
+ Crypto.Lol.PosBin: type B1Sym0 = B1
+ Crypto.Lol.PosBin: type B2 = D0 B1
+ Crypto.Lol.PosBin: type B20 = D0 (D0 (D1 (D0 B1)))
+ Crypto.Lol.PosBin: type B21 = D1 (D0 (D1 (D0 B1)))
+ Crypto.Lol.PosBin: type B22 = D0 (D1 (D1 (D0 B1)))
+ Crypto.Lol.PosBin: type B23 = D1 (D1 (D1 (D0 B1)))
+ Crypto.Lol.PosBin: type B24 = D0 (D0 (D0 (D1 B1)))
+ Crypto.Lol.PosBin: type B25 = D1 (D0 (D0 (D1 B1)))
+ Crypto.Lol.PosBin: type B26 = D0 (D1 (D0 (D1 B1)))
+ Crypto.Lol.PosBin: type B27 = D1 (D1 (D0 (D1 B1)))
+ Crypto.Lol.PosBin: type B28 = D0 (D0 (D1 (D1 B1)))
+ Crypto.Lol.PosBin: type B29 = D1 (D0 (D1 (D1 B1)))
+ Crypto.Lol.PosBin: type B3 = D1 B1
+ Crypto.Lol.PosBin: type B30 = D0 (D1 (D1 (D1 B1)))
+ Crypto.Lol.PosBin: type B31 = D1 (D1 (D1 (D1 B1)))
+ Crypto.Lol.PosBin: type B32 = D0 (D0 (D0 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B33 = D1 (D0 (D0 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B34 = D0 (D1 (D0 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B35 = D1 (D1 (D0 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B36 = D0 (D0 (D1 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B37 = D1 (D0 (D1 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B38 = D0 (D1 (D1 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B39 = D1 (D1 (D1 (D0 (D0 B1))))
+ Crypto.Lol.PosBin: type B4 = D0 (D0 B1)
+ Crypto.Lol.PosBin: type B40 = D0 (D0 (D0 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B41 = D1 (D0 (D0 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B42 = D0 (D1 (D0 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B43 = D1 (D1 (D0 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B44 = D0 (D0 (D1 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B45 = D1 (D0 (D1 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B46 = D0 (D1 (D1 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B47 = D1 (D1 (D1 (D1 (D0 B1))))
+ Crypto.Lol.PosBin: type B48 = D0 (D0 (D0 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B49 = D1 (D0 (D0 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B5 = D1 (D0 B1)
+ Crypto.Lol.PosBin: type B50 = D0 (D1 (D0 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B51 = D1 (D1 (D0 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B52 = D0 (D0 (D1 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B53 = D1 (D0 (D1 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B54 = D0 (D1 (D1 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B55 = D1 (D1 (D1 (D0 (D1 B1))))
+ Crypto.Lol.PosBin: type B56 = D0 (D0 (D0 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B57 = D1 (D0 (D0 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B58 = D0 (D1 (D0 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B59 = D1 (D1 (D0 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B6 = D0 (D1 B1)
+ Crypto.Lol.PosBin: type B60 = D0 (D0 (D1 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B61 = D1 (D0 (D1 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B62 = D0 (D1 (D1 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B63 = D1 (D1 (D1 (D1 (D1 B1))))
+ Crypto.Lol.PosBin: type B64 = D0 (D0 (D0 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B65 = D1 (D0 (D0 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B66 = D0 (D1 (D0 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B67 = D1 (D1 (D0 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B68 = D0 (D0 (D1 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B69 = D1 (D0 (D1 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B7 = D1 (D1 B1)
+ Crypto.Lol.PosBin: type B70 = D0 (D1 (D1 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B71 = D1 (D1 (D1 (D0 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B72 = D0 (D0 (D0 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B73 = D1 (D0 (D0 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B74 = D0 (D1 (D0 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B75 = D1 (D1 (D0 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B76 = D0 (D0 (D1 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B77 = D1 (D0 (D1 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B78 = D0 (D1 (D1 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B79 = D1 (D1 (D1 (D1 (D0 (D0 B1)))))
+ Crypto.Lol.PosBin: type B8 = D0 (D0 (D0 B1))
+ Crypto.Lol.PosBin: type B80 = D0 (D0 (D0 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B81 = D1 (D0 (D0 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B82 = D0 (D1 (D0 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B83 = D1 (D1 (D0 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B84 = D0 (D0 (D1 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B85 = D1 (D0 (D1 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B86 = D0 (D1 (D1 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B87 = D1 (D1 (D1 (D0 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B88 = D0 (D0 (D0 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B89 = D1 (D0 (D0 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B9 = D1 (D0 (D0 B1))
+ Crypto.Lol.PosBin: type B90 = D0 (D1 (D0 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B91 = D1 (D1 (D0 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B92 = D0 (D0 (D1 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B93 = D1 (D0 (D1 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B94 = D0 (D1 (D1 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B95 = D1 (D1 (D1 (D1 (D1 (D0 B1)))))
+ Crypto.Lol.PosBin: type B96 = D0 (D0 (D0 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B97 = D1 (D0 (D0 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B98 = D0 (D1 (D0 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type B99 = D1 (D1 (D0 (D0 (D0 (D1 B1)))))
+ Crypto.Lol.PosBin: type BinC (b :: Bin) = SingI b
+ Crypto.Lol.PosBin: type D0Sym1 (t_aAoD :: Bin) = D0 t_aAoD
+ Crypto.Lol.PosBin: type D1Sym1 (t_aAoG :: Bin) = D1 t_aAoG
+ Crypto.Lol.PosBin: type OSym0 = O
+ Crypto.Lol.PosBin: type P1 = O
+ Crypto.Lol.PosBin: type P10 = S (S (S (S (S (S (S (S (S O))))))))
+ Crypto.Lol.PosBin: type P11 = S (S (S (S (S (S (S (S (S (S O)))))))))
+ Crypto.Lol.PosBin: type P12 = S (S (S (S (S (S (S (S (S (S (S O))))))))))
+ Crypto.Lol.PosBin: type P13 = S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))
+ Crypto.Lol.PosBin: type P14 = S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))
+ Crypto.Lol.PosBin: type P15 = S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))
+ Crypto.Lol.PosBin: type P16 = S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))
+ Crypto.Lol.PosBin: type P2 = S O
+ Crypto.Lol.PosBin: type P3 = S (S O)
+ Crypto.Lol.PosBin: type P4 = S (S (S O))
+ Crypto.Lol.PosBin: type P5 = S (S (S (S O)))
+ Crypto.Lol.PosBin: type P6 = S (S (S (S (S O))))
+ Crypto.Lol.PosBin: type P7 = S (S (S (S (S (S O)))))
+ Crypto.Lol.PosBin: type P8 = S (S (S (S (S (S (S O))))))
+ Crypto.Lol.PosBin: type P9 = S (S (S (S (S (S (S (S O)))))))
+ Crypto.Lol.PosBin: type PosC (p :: Pos) = SingI p
+ Crypto.Lol.PosBin: type SBin = (Sing :: Bin -> *)
+ Crypto.Lol.PosBin: type SPos = (Sing :: Pos -> *)
+ Crypto.Lol.PosBin: type SSym1 (t_ayFw :: Pos) = S t_ayFw
+ Crypto.Lol.Reflects: instance (Crypto.Lol.FactoredDefs.Fact m, Algebra.ToInteger.C i) => Crypto.Lol.Reflects.Reflects m i
+ Crypto.Lol.Reflects: instance (Crypto.Lol.FactoredDefs.PPow pp, Algebra.ToInteger.C i) => Crypto.Lol.Reflects.Reflects pp i
+ Crypto.Lol.Reflects: instance (Crypto.Lol.FactoredDefs.Prim p, Algebra.ToInteger.C i) => Crypto.Lol.Reflects.Reflects p i
+ Crypto.Lol.Reflects: instance (GHC.TypeLits.KnownNat a, Algebra.ToInteger.C i) => Crypto.Lol.Reflects.Reflects a i
+ Crypto.Lol.Types.FiniteField: (^^) :: Ring a => X -> Int -> Polynomial a
+ Crypto.Lol.Types.FiniteField: Coeffs :: [a] -> TensorCoeffs a
+ Crypto.Lol.Types.FiniteField: X :: X
+ Crypto.Lol.Types.FiniteField: [unCoeffs] :: TensorCoeffs a -> [a]
+ Crypto.Lol.Types.FiniteField: class Field fp => IrreduciblePoly fp
+ Crypto.Lol.Types.FiniteField: data X
+ Crypto.Lol.Types.FiniteField: fromList :: (Reflects d Int) => [fp] -> GF fp d
+ Crypto.Lol.Types.FiniteField: instance Algebra.Additive.C a => Algebra.Additive.C (Crypto.Lol.Types.FiniteField.TensorCoeffs a)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). (Crypto.Lol.Types.Numeric.Additive fp, Crypto.Lol.Types.Numeric.Ring (Crypto.Lol.Types.FiniteField.GF fp d), Crypto.Lol.Reflects.Reflects d GHC.Types.Int) => Algebra.Module.C (Crypto.Lol.Types.FiniteField.GF fp d) (Crypto.Lol.Types.FiniteField.TensorCoeffs fp)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). (GHC.Classes.Eq fp, Algebra.ZeroTestable.C fp) => GHC.Classes.Eq (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). Algebra.Additive.C fp => Algebra.Additive.C (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). Algebra.ZeroTestable.C fp => Algebra.ZeroTestable.C (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). Control.DeepSeq.NFData fp => Control.DeepSeq.NFData (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). Crypto.Lol.Types.FiniteField.GFCtx fp d => Algebra.Field.C (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). Crypto.Lol.Types.FiniteField.GFCtx fp d => Algebra.Ring.C (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). Crypto.Lol.Types.FiniteField.GFCtx fp d => Crypto.Lol.CRTrans.CRTrans (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). Crypto.Lol.Types.FiniteField.GFCtx fp d => Crypto.Lol.LatticePrelude.Enumerable (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: instance forall (k :: BOX) fp (d :: k). GHC.Show.Show fp => GHC.Show.Show (Crypto.Lol.Types.FiniteField.GF fp d)
+ Crypto.Lol.Types.FiniteField: irreduciblePoly :: (IrreduciblePoly fp, Reflects d Int) => Tagged d (Polynomial fp)
+ Crypto.Lol.Types.FiniteField: newtype TensorCoeffs a
+ Crypto.Lol.Types.FiniteField: toList :: (Reflects d Int, Additive fp) => GF fp d -> [fp]
+ Crypto.Lol.Types.FiniteField: type GFCtx fp d = (PrimeField fp, Reflects d Int)
+ Crypto.Lol.Types.IrreducibleChar2: instance (Crypto.Lol.LatticePrelude.CharOf a ~ Crypto.Lol.Factored.Prime2, Crypto.Lol.Types.Numeric.Field a) => Crypto.Lol.Types.FiniteField.IrreduciblePoly a
+ Crypto.Lol.Types.Random: data CryptoRand g
+ Crypto.Lol.Types.Random: instance Crypto.Random.CryptoRandomGen g => Crypto.Random.CryptoRandomGen (Crypto.Lol.Types.Random.CryptoRand g)
+ Crypto.Lol.Types.Random: instance Crypto.Random.CryptoRandomGen g => System.Random.RandomGen (Crypto.Lol.Types.Random.CryptoRand g)
+ Crypto.Lol.Types.ZqBasic: instance (Crypto.Lol.FactoredDefs.PPow pp, zq ~ Crypto.Lol.Types.ZqBasic.ZqBasic pp z, Crypto.Lol.Types.FiniteField.PrimeField (Crypto.Lol.Types.ZPP.ZpOf zq), Crypto.Lol.Types.Numeric.Ring zq, Crypto.Lol.Types.Numeric.Ring (Crypto.Lol.Types.ZPP.ZpOf zq)) => Crypto.Lol.Types.ZPP.ZPP (Crypto.Lol.Types.ZqBasic.ZqBasic pp z)
+ Crypto.Lol.Types.ZqBasic: instance forall (k :: BOX) (k1 :: BOX) (b :: k) (q :: k1) z. (Crypto.Lol.Types.ZqBasic.ReflectsTI q z, Crypto.Lol.Types.Numeric.RealIntegral z, Crypto.Lol.Reflects.Reflects b z) => Crypto.Lol.Gadget.Gadget (Crypto.Lol.Gadget.BaseBGad b) (Crypto.Lol.Types.ZqBasic.ZqBasic q z)
+ Crypto.Lol.Types.ZqBasic: instance forall (k :: BOX) (k1 :: BOX) (b :: k) (q :: k1) z. (Crypto.Lol.Types.ZqBasic.ReflectsTI q z, Crypto.Lol.Types.Numeric.Ring z, Crypto.Lol.Reflects.Reflects b z) => Crypto.Lol.Gadget.Correct (Crypto.Lol.Gadget.BaseBGad b) (Crypto.Lol.Types.ZqBasic.ZqBasic q z)
+ Crypto.Lol.Types.ZqBasic: instance forall (k :: BOX) (k1 :: BOX) (b :: k) (q :: k1) z. (Crypto.Lol.Types.ZqBasic.ReflectsTI q z, Crypto.Lol.Types.Numeric.Ring z, Crypto.Lol.Types.Numeric.ZeroTestable z, Crypto.Lol.Reflects.Reflects b z) => Crypto.Lol.Gadget.Decompose (Crypto.Lol.Gadget.BaseBGad b) (Crypto.Lol.Types.ZqBasic.ZqBasic q z)
+ Crypto.Lol.Types.ZqBasic: instance forall (k :: BOX) (q :: k) z. (Crypto.Lol.Types.ZqBasic.ReflectsTI q z, Crypto.Lol.Types.Numeric.PID z, Crypto.Lol.LatticePrelude.Enumerable (Crypto.Lol.Types.ZqBasic.ZqBasic q z)) => Crypto.Lol.CRTrans.CRTrans (Crypto.Lol.Types.ZqBasic.ZqBasic q z)
- Crypto.Lol.Cyclotomic.Cyc: crtSet :: (m `Divides` m', ZPP r, CElt t r, CElt t (ZPOf r)) => Tagged m [Cyc t m' r]
+ Crypto.Lol.Cyclotomic.Cyc: crtSet :: (m `Divides` m', ZPP r, CElt t r, TElt t (ZpOf r)) => Tagged m [Cyc t m' r]
- Crypto.Lol.Cyclotomic.Cyc: embed :: (m `Divides` m', CElt t r) => Cyc t m r -> Cyc t m' r
+ Crypto.Lol.Cyclotomic.Cyc: embed :: (m `Divides` m') => Cyc t m r -> Cyc t m' r
- Crypto.Lol.Cyclotomic.Cyc: errorCoset :: (Mod zp, z ~ ModRep zp, Lift zp z, Fact m, CElt t zp, CElt t z, ToRational v, MonadRandom rnd) => v -> Cyc t m zp -> rnd (Cyc t m z)
+ Crypto.Lol.Cyclotomic.Cyc: errorCoset :: (Mod zp, z ~ ModRep zp, Lift zp z, Fact m, CElt t zp, TElt t z, ToRational v, MonadRandom rnd) => v -> Cyc t m zp -> rnd (Cyc t m z)
- Crypto.Lol.Cyclotomic.Cyc: errorRounded :: (ToInteger z, Fact m, CElt t z, ToRational v, MonadRandom rnd) => v -> rnd (Cyc t m z)
+ Crypto.Lol.Cyclotomic.Cyc: errorRounded :: (ToInteger z, Tensor t, Fact m, TElt t z, ToRational v, MonadRandom rnd) => v -> rnd (Cyc t m z)
- Crypto.Lol.Cyclotomic.Cyc: liftCyc :: (Lift b a, Fact m, CElt t a, CElt t b) => Basis -> Cyc t m b -> Cyc t m a
+ Crypto.Lol.Cyclotomic.Cyc: liftCyc :: (Lift b a, Fact m, TElt t a, CElt t b) => Basis -> Cyc t m b -> Cyc t m a
- Crypto.Lol.Cyclotomic.Cyc: scalarCyc :: (Fact m, CElt t a) => a -> Cyc t m a
+ Crypto.Lol.Cyclotomic.Cyc: scalarCyc :: r -> Cyc t m r
- Crypto.Lol.Cyclotomic.Cyc: tGaussian :: (Fact m, OrdFloat q, Random q, CElt t q, ToRational v, MonadRandom rnd) => v -> rnd (Cyc t m q)
+ Crypto.Lol.Cyclotomic.Cyc: tGaussian :: (Fact m, OrdFloat q, Random q, Tensor t, TElt t q, ToRational v, MonadRandom rnd) => v -> rnd (Cyc t m q)
- Crypto.Lol.Cyclotomic.Cyc: type CElt t r = (Tensor t, RElt t r, RElt t (CRTExt r), CRTEmbed r, Eq r, Random r)
+ Crypto.Lol.Cyclotomic.Cyc: type CElt t r = UCElt t r
- Crypto.Lol.Cyclotomic.Tensor: crt :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, Fact m, TElt t r) => Maybe (t m r -> t m r)
+ Crypto.Lol.Cyclotomic.Tensor: crt :: (Tensor t, Fact m, CRTElt t r) => Maybe (t m r -> t m r)
- Crypto.Lol.Cyclotomic.Tensor: crtExtFuncs :: (Tensor t, ZeroTestable r, IntegralDomain r, CRTrans r, m `Divides` m', TElt t r) => Maybe (t m' r -> t m r, t m r -> t m' r)
+ Crypto.Lol.Cyclotomic.Tensor: crtExtFuncs :: (Tensor t, m `Divides` m', CRTElt t r) => Maybe (t m' r -> t m r, t m r -> t m' r)
- Crypto.Lol.Cyclotomic.Tensor: crtFuncs :: (Tensor t, ZeroTestable r, IntegralDomain r, CRTrans r, Fact m, TElt t r) => Maybe (r -> t m r, t m r -> t m r, t m r -> t m r, t m r -> t m r, t m r -> t m r)
+ Crypto.Lol.Cyclotomic.Tensor: crtFuncs :: (Tensor t, Fact m, CRTElt t r) => Maybe (r -> t m r, t m r -> t m r, t m r -> t m r, t m r -> t m r, t m r -> t m r)
- Crypto.Lol.Cyclotomic.Tensor: crtInv :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, Fact m, TElt t r) => Maybe (t m r -> t m r)
+ Crypto.Lol.Cyclotomic.Tensor: crtInv :: (Tensor t, Fact m, CRTElt t r) => Maybe (t m r -> t m r)
- Crypto.Lol.Cyclotomic.Tensor: crtSetDec :: (Tensor t, PrimeField fp, m `Divides` m', Coprime (PToF (CharOf fp)) m', TElt t fp) => Tagged m [t m' fp]
+ Crypto.Lol.Cyclotomic.Tensor: crtSetDec :: (Tensor t, m `Divides` m', PrimeField fp, Coprime (PToF (CharOf fp)) m', TElt t fp) => Tagged m [t m' fp]
- Crypto.Lol.Cyclotomic.Tensor: divGCRT :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, Fact m, TElt t r) => Maybe (t m r -> t m r)
+ Crypto.Lol.Cyclotomic.Tensor: divGCRT :: (Tensor t, Fact m, CRTElt t r) => Maybe (t m r -> t m r)
- Crypto.Lol.Cyclotomic.Tensor: embedCRT :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, m `Divides` m', TElt t r) => Maybe (t m r -> t m' r)
+ Crypto.Lol.Cyclotomic.Tensor: embedCRT :: (Tensor t, m `Divides` m', CRTElt t r) => Maybe (t m r -> t m' r)
- Crypto.Lol.Cyclotomic.Tensor: embedDec :: (Tensor t, Ring r, m `Divides` m', TElt t r) => t m r -> t m' r
+ Crypto.Lol.Cyclotomic.Tensor: embedDec :: (Tensor t, Additive r, m `Divides` m', TElt t r) => t m r -> t m' r
- Crypto.Lol.Cyclotomic.Tensor: embedPow :: (Tensor t, Ring r, m `Divides` m', TElt t r) => t m r -> t m' r
+ Crypto.Lol.Cyclotomic.Tensor: embedPow :: (Tensor t, Additive r, m `Divides` m', TElt t r) => t m r -> t m' r
- Crypto.Lol.Cyclotomic.Tensor: entailEqT :: Tensor t => Tagged (t m r) ((Eq r, Fact m, TElt t r) :- (Eq (t m r)))
+ Crypto.Lol.Cyclotomic.Tensor: entailEqT :: Tensor t => Tagged (t m r) ((Eq r, Fact m, TElt t r) :- Eq (t m r))
- Crypto.Lol.Cyclotomic.Tensor: entailNFDataT :: Tensor t => Tagged (t m r) ((NFData r, Fact m, TElt t r) :- (NFData (t m r)))
+ Crypto.Lol.Cyclotomic.Tensor: entailNFDataT :: Tensor t => Tagged (t m r) ((NFData r, Fact m, TElt t r) :- NFData (t m r))
- Crypto.Lol.Cyclotomic.Tensor: entailRandomT :: Tensor t => Tagged (t m r) ((Random r, Fact m, TElt t r) :- (Random (t m r)))
+ Crypto.Lol.Cyclotomic.Tensor: entailRandomT :: Tensor t => Tagged (t m r) ((Random r, Fact m, TElt t r) :- Random (t m r))
- Crypto.Lol.Cyclotomic.Tensor: entailZTT :: Tensor t => Tagged (t m r) ((ZeroTestable r, Fact m, TElt t r) :- (ZeroTestable (t m r)))
+ Crypto.Lol.Cyclotomic.Tensor: entailZTT :: Tensor t => Tagged (t m r) ((ZeroTestable r, Fact m, TElt t r) :- ZeroTestable (t m r))
- Crypto.Lol.Cyclotomic.Tensor: hasCRTFuncs :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, Fact m, TElt t r) => TaggedT (t m r) Maybe ()
+ Crypto.Lol.Cyclotomic.Tensor: hasCRTFuncs :: (Tensor t, Fact m, CRTElt t r) => TaggedT (t m r) Maybe ()
- Crypto.Lol.Cyclotomic.Tensor: l :: (Tensor t, Ring r, Fact m, TElt t r) => t m r -> t m r
+ Crypto.Lol.Cyclotomic.Tensor: l :: (Tensor t, Additive r, Fact m, TElt t r) => t m r -> t m r
- Crypto.Lol.Cyclotomic.Tensor: lInv :: (Tensor t, Ring r, Fact m, TElt t r) => t m r -> t m r
+ Crypto.Lol.Cyclotomic.Tensor: lInv :: (Tensor t, Additive r, Fact m, TElt t r) => t m r -> t m r
- Crypto.Lol.Cyclotomic.Tensor: mulGCRT :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, Fact m, TElt t r) => Maybe (t m r -> t m r)
+ Crypto.Lol.Cyclotomic.Tensor: mulGCRT :: (Tensor t, Fact m, CRTElt t r) => Maybe (t m r -> t m r)
- Crypto.Lol.Cyclotomic.Tensor: scalarCRT :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, Fact m, TElt t r) => Maybe (r -> t m r)
+ Crypto.Lol.Cyclotomic.Tensor: scalarCRT :: (Tensor t, Fact m, CRTElt t r) => Maybe (r -> t m r)
- Crypto.Lol.Cyclotomic.Tensor: scalarPow :: (Tensor t, Ring r, Fact m, TElt t r) => r -> t m r
+ Crypto.Lol.Cyclotomic.Tensor: scalarPow :: (Tensor t, Additive r, Fact m, TElt t r) => r -> t m r
- Crypto.Lol.Cyclotomic.Tensor: twaceCRT :: (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, m `Divides` m', TElt t r) => Maybe (t m' r -> t m r)
+ Crypto.Lol.Cyclotomic.Tensor: twaceCRT :: (Tensor t, m `Divides` m', CRTElt t r) => Maybe (t m' r -> t m r)
- Crypto.Lol.Cyclotomic.UCyc: crtSet :: (m `Divides` m', ZPP r, p ~ CharOf (ZPOf r), mbar ~ PFree p m, m'bar ~ PFree p m', CElt t r, CElt t (ZPOf r)) => Tagged m [UCyc t m' r]
+ Crypto.Lol.Cyclotomic.UCyc: crtSet :: (m `Divides` m', ZPP r, p ~ CharOf (ZpOf r), mbar ~ PFree p m, m'bar ~ PFree p m', UCElt t r, TElt t (ZpOf r)) => Tagged m [UCyc t m' P r]
- Crypto.Lol.Cyclotomic.UCyc: data UCyc t (m :: Factored) r
+ Crypto.Lol.Cyclotomic.UCyc: data UCyc t m rep r
- Crypto.Lol.Cyclotomic.UCyc: divG :: (Fact m, CElt t r) => UCyc t m r -> Maybe (UCyc t m r)
+ Crypto.Lol.Cyclotomic.UCyc: divG :: (Tensor t, Fact m, UCElt t r) => UCyc t m rep r -> Maybe (UCyc t m rep r)
- Crypto.Lol.Cyclotomic.UCyc: errorCoset :: (Mod zp, z ~ ModRep zp, Lift zp z, Fact m, CElt t zp, CElt t z, ToRational v, MonadRandom rnd) => v -> UCyc t m zp -> rnd (UCyc t m z)
+ Crypto.Lol.Cyclotomic.UCyc: errorCoset :: (Mod zp, z ~ ModRep zp, Lift zp z, Tensor t, Fact m, TElt t zp, TElt t z, ToRational v, MonadRandom rnd) => v -> UCyc t m D zp -> rnd (UCyc t m D z)
- Crypto.Lol.Cyclotomic.UCyc: errorRounded :: (ToInteger z, Fact m, CElt t z, ToRational v, MonadRandom rnd) => v -> rnd (UCyc t m z)
+ Crypto.Lol.Cyclotomic.UCyc: errorRounded :: (ToInteger z, Tensor t, Fact m, TElt t z, ToRational v, MonadRandom rnd) => v -> rnd (UCyc t m D z)
- Crypto.Lol.Cyclotomic.UCyc: mulG :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r
+ Crypto.Lol.Cyclotomic.UCyc: mulG :: (Tensor t, Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m rep r
- Crypto.Lol.Cyclotomic.UCyc: powBasis :: (m `Divides` m', CElt t r) => Tagged m [UCyc t m' r]
+ Crypto.Lol.Cyclotomic.UCyc: powBasis :: (Ring r, Tensor t, m `Divides` m', TElt t r) => Tagged m [UCyc t m' P r]
- Crypto.Lol.Cyclotomic.UCyc: tGaussian :: (Fact m, OrdFloat q, Random q, CElt t q, ToRational v, MonadRandom rnd) => v -> rnd (UCyc t m q)
+ Crypto.Lol.Cyclotomic.UCyc: tGaussian :: (Tensor t, Fact m, OrdFloat q, Random q, TElt t q, ToRational v, MonadRandom rnd) => v -> rnd (UCyc t m D q)
- Crypto.Lol.Factored: exponentPP :: PrimePower -> Nat
+ Crypto.Lol.Factored: exponentPP :: PrimePower -> Pos
- Crypto.Lol.Factored: exponentPPow :: (PPow pp) => Tagged pp Int
+ Crypto.Lol.Factored: exponentPPow :: PPow pp => Tagged pp Int
- Crypto.Lol.Factored: oddRadicalFact :: (Fact m) => Tagged m Int
+ Crypto.Lol.Factored: oddRadicalFact :: Fact m => Tagged m Int
- Crypto.Lol.Factored: pFree :: Nat -> Factored -> Factored
+ Crypto.Lol.Factored: pFree :: Prime -> Factored -> Factored
- Crypto.Lol.Factored: pFreeDivides :: Proxy p -> Proxy m -> Proxy m' -> ((NatC p, m `Divides` m') :- ((PFree p m) `Divides` (PFree p m')))
+ Crypto.Lol.Factored: pFreeDivides :: Proxy p -> Proxy m -> Proxy m' -> ((Prim p, m `Divides` m') :- ((PFree p m) `Divides` (PFree p m')))
- Crypto.Lol.Factored: pSplitTheorems :: Proxy p -> Proxy m -> ((NatC p, Fact m, f ~ PFree p m) :- (f `Divides` m, Coprime (PToF p) f))
+ Crypto.Lol.Factored: pSplitTheorems :: Proxy p -> Proxy m -> ((Prim p, Fact m, f ~ PFree p m) :- (f `Divides` m, Coprime (PToF p) f))
- Crypto.Lol.Factored: ppPPow :: (PPow pp) => Tagged pp PP
+ Crypto.Lol.Factored: ppPPow :: PPow pp => Tagged pp PP
- Crypto.Lol.Factored: ppsFact :: (Fact m) => Tagged m [PP]
+ Crypto.Lol.Factored: ppsFact :: Fact m => Tagged m [PP]
- Crypto.Lol.Factored: primePP :: PrimePower -> Nat
+ Crypto.Lol.Factored: primePP :: PrimePower -> Prime
- Crypto.Lol.Factored: primePPow :: (PPow pp) => Tagged pp Int
+ Crypto.Lol.Factored: primePPow :: PPow pp => Tagged pp Int
- Crypto.Lol.Factored: radicalFact :: (Fact m) => Tagged m Int
+ Crypto.Lol.Factored: radicalFact :: Fact m => Tagged m Int
- Crypto.Lol.Factored: sPpToF :: Sing t_amUY -> Sing (Apply PpToFSym0 t_amUY :: Factored)
+ Crypto.Lol.Factored: sPpToF :: Sing t_aOYC -> Sing (Apply PpToFSym0 t_aOYC :: Factored)
- Crypto.Lol.Factored: sUnF :: Sing t_agMa -> Sing (Apply UnFSym0 t_agMa :: [PrimePower])
+ Crypto.Lol.Factored: sUnF :: Sing t_aLeC -> Sing (Apply UnFSym0 t_aLeC :: [PrimePower])
- Crypto.Lol.Factored: sUnPP :: Sing t_agM7 -> Sing (Apply UnPPSym0 t_agM7 :: (Nat, Nat))
+ Crypto.Lol.Factored: sUnPP :: Sing t_aLeD -> Sing (Apply UnPPSym0 t_aLeD :: (Prime, Pos))
- Crypto.Lol.Factored: totientFact :: (Fact m) => Tagged m Int
+ Crypto.Lol.Factored: totientFact :: Fact m => Tagged m Int
- Crypto.Lol.Factored: totientPPow :: (PPow pp) => Tagged pp Int
+ Crypto.Lol.Factored: totientPPow :: PPow pp => Tagged pp Int
- Crypto.Lol.Factored: unPP :: PrimePower -> (Nat, Nat)
+ Crypto.Lol.Factored: unPP :: PrimePower -> (Prime, Pos)
- Crypto.Lol.Factored: valueFact :: (Fact m) => Tagged m Int
+ Crypto.Lol.Factored: valueFact :: Fact m => Tagged m Int
- Crypto.Lol.Factored: valueHat :: (Integral i) => i -> i
+ Crypto.Lol.Factored: valueHat :: Integral i => i -> i
- Crypto.Lol.Factored: valueHatFact :: (Fact m) => Tagged m Int
+ Crypto.Lol.Factored: valueHatFact :: Fact m => Tagged m Int
- Crypto.Lol.Factored: valuePPow :: (PPow pp) => Tagged pp Int
+ Crypto.Lol.Factored: valuePPow :: PPow pp => Tagged pp Int
- Crypto.Lol.Gadget: correct :: Correct gad u => Tagged gad [u] -> u
+ Crypto.Lol.Gadget: correct :: Correct gad u => Tagged gad [u] -> (u, [LiftOf u])
- Crypto.Lol.LatticePrelude: class (Reduce (LiftOf b) b) => Lift' b where type family LiftOf b
+ Crypto.Lol.LatticePrelude: class (Reduce (LiftOf b) b) => Lift' b
- Crypto.Lol.LatticePrelude: withWitnessT :: (Monad mon) => (SingI n => TaggedT n mon r) -> Sing n -> mon r
+ Crypto.Lol.LatticePrelude: withWitnessT :: (SingI n => TaggedT n mon r) -> Sing n -> mon r
- Crypto.Lol.Types.FiniteField: data GF fp deg
+ Crypto.Lol.Types.FiniteField: data GF fp d
- Crypto.Lol.Types.FiniteField: size :: (GFCtx fp deg) => Tagged (GF fp deg) Int
+ Crypto.Lol.Types.FiniteField: size :: (GFCtx fp d) => Tagged (GF fp d) Int
- Crypto.Lol.Types.FiniteField: trace :: (GFCtx fp deg) => GF fp deg -> fp
+ Crypto.Lol.Types.FiniteField: trace :: (GFCtx fp d) => GF fp d -> fp
- Crypto.Lol.Types.FiniteField: type PrimeField fp = (Enumerable fp, Eq fp, ZeroTestable fp, Field fp, IrreduciblePoly fp)
+ Crypto.Lol.Types.FiniteField: type PrimeField fp = (Enumerable fp, Field fp, Eq fp, ZeroTestable fp, Prim (CharOf fp), IrreduciblePoly fp)
- Crypto.Lol.Types.ZPP: class (PrimeField (ZPOf zq), Ring zq, Ring (ZPOf zq)) => ZPP zq where type family ZPOf zq
+ Crypto.Lol.Types.ZPP: class (PrimeField (ZpOf zq), Ring zq) => ZPP zq where type family ZpOf zq
- Crypto.Lol.Types.ZPP: liftZp :: ZPP zq => ZPOf zq -> zq
+ Crypto.Lol.Types.ZPP: liftZp :: ZPP zq => ZpOf zq -> zq

Files

CHANGES.md view
@@ -1,6 +1,15 @@ Changelog for lol project ================================ +0.2.0.0+-----+ * Added benchmarks+ * Better performance for C backend with RNS base ring+ * UCyc exposes bases as type for safety+ * Other safety improvements throughout+ * Easier index representation with TemplateHaskell+ * Split SymmSHE into new package lol-apps.+ 0.1.0.0 -----  * Fixed bug in Box-Muller sampling routine.
+ Crypto/Lol.hs view
@@ -0,0 +1,21 @@++-- | Re-exports primary interfaces.++module Crypto.Lol +( module Crypto.Lol.Cyclotomic.Cyc+, module Crypto.Lol.Gadget+, module Crypto.Lol.LatticePrelude++, module Crypto.Lol.Types.ZqBasic+, module Crypto.Lol.Cyclotomic.Tensor.CTensor+, module Crypto.Lol.Cyclotomic.Tensor.RepaTensor+, module Crypto.Lol.Types.IrreducibleChar2) where++import Crypto.Lol.Cyclotomic.Cyc+import Crypto.Lol.Gadget+import Crypto.Lol.LatticePrelude++import Crypto.Lol.Types.ZqBasic+import Crypto.Lol.Cyclotomic.Tensor.CTensor+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor+import Crypto.Lol.Types.IrreducibleChar2
+ Crypto/Lol/CRTrans.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE FlexibleContexts, FlexibleInstances, RebindableSyntax,
+             ScopedTypeVariables, TypeFamilies #-}
+
+-- | Classes and helper methods for the Chinese remainder transform
+-- and ring extensions.
+
+module Crypto.Lol.CRTrans
+( CRTrans(..), CRTEmbed(..)
+, CRTInfo
+, crtInfoFact, crtInfoPPow, crtInfoPrime
+, gEmbPPow, gEmbPrime
+) where
+
+import Crypto.Lol.LatticePrelude
+
+import Control.Arrow
+import Data.Singletons
+import Data.Singletons.Prelude
+
+-- | Information that characterizes the (invertible) Chinese remainder
+-- transformation over a ring @r@, namely:
+--
+--     (1) a function that returns the @i@th power of some /principal/
+--     @m@th root of unity (for any integer @i@)
+--
+--     (2) the multiplicative inverse of @\\hat{m}@ in @r@.
+
+type CRTInfo r = (Int -> r, r)
+
+-- | A ring that (possibly) supports invertible Chinese remainder
+-- transformations of various indices.
+
+-- | The values of 'crtInfo' for different indices @m@ should be
+-- consistent, in the sense that if @omega@, @omega'@ are respectively
+-- the values returned for @m@, @m'@ where @m'@ divides @m@, then it
+-- should be the case that @omega^(m/m')=omega'@.
+
+class Ring r => CRTrans r where
+
+  -- | 'CRTInfo' for a given index @m@. The method itself may be
+  -- slow, but the function it returns should be fast, e.g., via
+  -- internal memoization.  The default implementation returns
+  -- 'Nothing'.
+  crtInfo :: Int -> Maybe (CRTInfo r)
+  crtInfo = const Nothing
+
+-- | A ring with a ring embedding into some ring @CRTExt r@ that has
+-- an invertible CRT transformation for /every/ positive index @m@.
+class (Ring r, Ring (CRTExt r)) => CRTEmbed r where
+  type CRTExt r
+
+  -- | Embeds from @r@ to @CRTExt r@
+  toExt :: r -> CRTExt r
+  -- | Projects from @CRTExt r@ to @r@
+  fromExt :: CRTExt r -> r
+
+-- CRTrans instance for product rings
+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))
+
+-- CRTEmbed instance for product rings
+instance (CRTEmbed a, CRTEmbed b) => CRTEmbed (a,b) where
+  type CRTExt (a,b) = (CRTExt a, CRTExt b)
+  toExt = toExt *** toExt
+  fromExt = fromExt *** fromExt
+
+omegaPowC :: (Transcendental a) => Int -> Int -> Complex a
+omegaPowC m i = cis (2*pi*fromIntegral i / fromIntegral m)
+
+-- | 'crtInfo' wrapper for 'Fact' types.
+crtInfoFact :: (Fact m, CRTrans r) => TaggedT m Maybe (CRTInfo r)
+crtInfoFact = (tagT . crtInfo) =<< pureT valueFact
+
+-- | 'crtInfo' wrapper for 'PPow' types.
+crtInfoPPow :: (PPow pp, CRTrans r) => TaggedT pp Maybe (CRTInfo r)
+crtInfoPPow = (tagT . crtInfo) =<< pureT valuePPow
+
+-- | 'crtInfo' wrapper for 'Prime' types.
+crtInfoPrime :: (Prim p, CRTrans r) => TaggedT p Maybe (CRTInfo r)
+crtInfoPrime = (tagT . crtInfo) =<< pureT valuePrime
+
+-- | A function that returns the 'i'th embedding of @g_{p^e} = g_p@ for
+-- @i@ in @Z*_{p^e}@.
+gEmbPPow :: forall pp r . (PPow pp, CRTrans r) => TaggedT pp Maybe (Int -> r)
+gEmbPPow = tagT $ case (sing :: SPrimePower pp) of
+  (SPP (STuple2 sp _)) -> withWitnessT gEmbPrime sp
+
+-- | A function that returns the @i@th embedding of @g_p@ for @i@ in @Z*_p@,
+-- i.e., @1-omega_p^i@.
+gEmbPrime :: (Prim p, CRTrans r) => TaggedT p Maybe (Int -> r)
+gEmbPrime = do
+  (f, _) <- crtInfoPrime
+  return $ \i -> one - f i      -- not checking that i /= 0 (mod p)
+
+-- the complex numbers have roots of unity of any order
+instance (Transcendental a) => CRTrans (Complex a) where
+  crtInfo m = Just (omegaPowC m, recip $ fromIntegral $ valueHat m)
+
+-- trivial CRTEmbed instance for complex numbers
+instance (Transcendental a) => CRTEmbed (Complex a) where
+  type CRTExt (Complex a) = Complex a
+  toExt = id
+  fromExt = id
+
+-- Default CRTrans instances for real and integer types, which do
+-- not have roots of unity (except in trivial cases). These are needed
+-- to use FastCyc with these integer types.
+instance CRTrans Double
+instance CRTrans Int
+instance CRTrans Int64
+instance CRTrans Integer
+-- can also do for Int8, Int16, Int32 etc.
+
+-- CRTEmbed instances for real and integer types, embedding into
+-- Complex.  These are needed to use FastCyc with these integer types.
+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
+  -- CJP: sufficient precision?  Not in general.
+  type CRTExt Integer = Complex Double
+  toExt = fromIntegral
+  fromExt = fst . roundComplex
+ Crypto/Lol/Cyclotomic/Cyc.hs view
@@ -0,0 +1,583 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, GADTs, MultiParamTypeClasses,+             NoImplicitPrelude, PolyKinds, RankNTypes, ScopedTypeVariables,+             TypeFamilies, TypeOperators, UndecidableInstances #-}++-- | An implementation of cyclotomic rings that hides the+-- internal representations of ring elements (e.g., the choice of+-- basis), and also offers more efficient storage and operations on+-- subring elements (including elements from the base ring itself).+--+-- For an implementation that allows (and requires) the programmer to+-- control the underlying representation, see+-- 'Crypto.Lol.Cyclotomic.UCyc.UCyc'.+--+-- __WARNING:__ as with all fixed-point arithmetic, the functions+-- associated with 'Cyc' may result in overflow (and thereby+-- incorrect answers and potential security flaws) if the input+-- arguments are too close to the bounds imposed by the base type.+-- The acceptable range of inputs for each function is determined by+-- the internal linear transforms and other operations it performs.++module Crypto.Lol.Cyclotomic.Cyc+(+-- * Data type and constraints+  Cyc, CElt, U.NFElt+-- * Constructors/deconstructors+, cycPow, cycDec, cycCRT, scalarCyc+, uncycPow, uncycDec, uncycCRT, unzipCyc, unzipCElt+-- * Core cyclotomic operations+, mulG, divG, gSqNorm, liftCyc, liftPow, liftDec+-- * Representation advice+, advisePow, adviseDec, adviseCRT+-- * Error sampling+, tGaussian, errorRounded, errorCoset+-- * Sub/extension rings+, embed, twace, coeffsCyc, powBasis, crtSet+-- * Rescaling cyclotomic elements+, R.RescaleCyc(..), R.Basis(..)+) where++import qualified Algebra.Additive     as Additive (C)+import qualified Algebra.Module       as Module (C)+import qualified Algebra.Ring         as Ring (C)+import qualified Algebra.ZeroTestable as ZeroTestable (C)++import Crypto.Lol.Cyclotomic.UCyc hiding (coeffsDec, coeffsPow, crtSet,+                                   divG, errorCoset, errorRounded, gSqNorm,+                                   mulG, powBasis, tGaussian, unzipCyc)++import           Crypto.Lol.CRTrans+import qualified Crypto.Lol.Cyclotomic.RescaleCyc as R+import           Crypto.Lol.Cyclotomic.Tensor     (CRTElt, TElt, Tensor)+import qualified Crypto.Lol.Cyclotomic.UCyc       as U+import           Crypto.Lol.Gadget+import           Crypto.Lol.LatticePrelude        as LP+import           Crypto.Lol.Types.FiniteField+import           Crypto.Lol.Types.ZPP++import Control.Applicative    hiding ((*>))+import Control.Arrow+import Control.DeepSeq+import Control.Monad.Identity   -- needed for coerce+import Control.Monad.Random+import Data.Coerce+import Data.Traversable++import Test.QuickCheck++-- | Represents a cyclotomic ring such as @Z[zeta]@,+-- @Zq[zeta]@, and @Q(zeta)@ in an explicit representation: @t@ is the+-- 'Tensor' type for storing coefficient tensors; @m@ is the+-- cyclotomic index; @r@ is the base ring of the coefficients (e.g.,+-- @Z@, @Zq@).+data Cyc t m r where+  Pow :: !(UCyc t m P r) -> Cyc t m r+  Dec :: !(UCyc t m D r) -> Cyc t m r+  CRT :: !(UCyc t m C r) -> Cyc t m r+  -- super-optimized storage of scalars+  Scalar :: !r -> Cyc t m r+  -- optimized storage of subring elements+  Sub :: (l `Divides` m) => !(Cyc t l r) -> Cyc t m r+  -- CJP: someday try to merge the above two++-- | Constraints needed for many operations involving 'Cyc' data.+type CElt t r = UCElt t r++---------- Constructors / deconstructors ----------++-- | Wrap a 'UCyc' as a 'Cyc'.+cycPow :: UCyc t m P r -> Cyc t m r+cycPow = Pow+{-# INLINABLE cycPow #-}++-- | Wrap a 'UCyc' as a 'Cyc'.+cycDec :: UCyc t m D r -> Cyc t m r+cycDec = Dec+{-# INLINABLE cycDec #-}++-- | Wrap a 'UCyc' as a 'Cyc'.+cycCRT :: UCyc t m C r -> Cyc t m r+cycCRT = CRT+{-# INLINABLE cycCRT #-}++-- | Embed a scalar from the base ring as a cyclotomic element.+scalarCyc :: r -> Cyc t m r+scalarCyc = Scalar+{-# INLINABLE scalarCyc #-}++-- | Unwrap a 'Cyc' as a 'UCyc' in powerful-basis representation.+uncycPow :: (Fact m, CElt t r) => Cyc t m r -> UCyc t m P r+{-# INLINABLE uncycPow #-}+uncycPow c = let (Pow u) = toPow' c in u++-- | Unwrap a 'Cyc' as a 'UCyc' in decoding-basis representation.+uncycDec :: (Fact m, CElt t r) => Cyc t m r -> UCyc t m D r+{-# INLINABLE uncycDec #-}+uncycDec c = let (Dec u) = toDec' c in u++-- | Unwrap a 'Cyc' as a 'UCyc' in CRT-basis representation.+uncycCRT :: (Fact m, CElt t r) => Cyc t m r -> UCyc t m C r+{-# INLINABLE uncycCRT #-}+uncycCRT c = let (CRT u) = toCRT' c in u++---------- Algebraic instances ----------++instance (Fact m, CElt t r) => ZeroTestable.C (Cyc t m r) where+  isZero (Pow u) = isZero u+  isZero (Dec u) = isZero u+  isZero (CRT u) = isZero u+  isZero (Scalar c) = isZero c+  isZero (Sub c) = isZero c+  {-# INLINABLE isZero #-}++instance (Eq r, Fact m, CElt t r) => Eq (Cyc t m r) where+  -- same representations+  (Scalar c1) == (Scalar c2) = c1 == c2+  (Pow u1) == (Pow u2) = u1 == u2+  (Dec u1) == (Dec u2) = u1 == u2+  (CRT u1) == (CRT u2) = u1 == u2+  -- compare Subs in compositum+  (Sub (c1 :: Cyc t l1 r)) == (Sub (c2 :: Cyc t l2 r)) =+    (embed' c1 :: Cyc t (FLCM l1 l2) r) == embed' c2+    \\ lcmDivides (Proxy::Proxy l1) (Proxy::Proxy l2)++  -- some other relatively efficient comparisons+  (Scalar c1) == (Pow u2) = scalarPow c1 == u2+  -- (Scalar c1) == (Dec u2) = scalarDec c1 == u2+  (Pow u1) == (Scalar c2) = u1 == scalarPow c2+  -- (Dec u1) == (Scalar c2) = u1 == scalarDec c2++  -- default: compare in powerful basis+  c1 == c2 = toPow' c1 == toPow' c2++  {-# INLINABLE (==) #-}++instance (Fact m, CElt t r) => Additive.C (Cyc t m r) where+  {-# INLINABLE zero #-}+  zero = Scalar zero++  {-# INLINABLE (+) #-}+  -- optimized addition of zero+  (Scalar c1) + c2 | isZero c1 = c2+  c1 + (Scalar c2) | isZero c2 = c1++  -- SAME CONSTRUCTORS+  (Scalar c1) + (Scalar c2) = Scalar (c1+c2)+  (Pow u1) + (Pow u2) = Pow $ u1 + u2+  (Dec u1) + (Dec u2) = Dec $ u1 + u2+  (CRT u1) + (CRT u2) = CRT $ u1 + u2+  -- Sub plus Sub: work in compositum+  (Sub (c1 :: Cyc t m1 r)) + (Sub (c2 :: Cyc t m2 r)) =+    (Sub $ (embed' c1 :: Cyc t (FLCM m1 m2) r) + embed' c2)+    \\ lcm2Divides (Proxy::Proxy m1) (Proxy::Proxy m2) (Proxy::Proxy m)++  -- SCALAR PLUS SOMETHING ELSE++  (Scalar c) + (Pow u) = Pow $ scalarPow c + u+  (Scalar c) + (Dec u) = Pow $ scalarPow c + toPow u -- workaround scalarDec+  (Scalar c) + (CRT u) = CRT $ scalarCRT c + u+  (Scalar c1) + (Sub c2) = Sub $ Scalar c1 + c2 -- must re-wrap Scalar!++  (Pow u) + (Scalar c) = Pow $ u + scalarPow c+  (Dec u) + (Scalar c) = Pow $ toPow u + scalarPow c -- workaround scalarDec+  (CRT u) + (Scalar c) = CRT $ u + scalarCRT c+  (Sub c1) + (Scalar c2) = Sub $ c1 + Scalar c2++  -- SUB PLUS NON-SUB, NON-SCALAR: work in full ring+  (Sub c1) + c2 = embed' c1 + c2+  c1 + (Sub c2) = c1 + embed' c2++  -- mixed Dec and Pow: use linear-time conversions+  (Dec u1) + (Pow u2) = Pow $ toPow u1 + u2+  (Pow u1) + (Dec u2) = Pow $ u1 + toPow u2++  -- one CRT: convert other to CRT+  (CRT u1) + (Pow u2) = CRT $ u1 + toCRT u2+  (CRT u1) + (Dec u2) = CRT $ u1 + toCRT u2+  (Pow u1) + (CRT u2) = CRT $ toCRT u1 + u2+  (Dec u1) + (CRT u2) = CRT $ toCRT u1 + u2++  {-# INLINABLE negate #-}+  negate (Pow u) = Pow $ negate u+  negate (Dec u) = Dec $ negate u+  negate (CRT u) = CRT $ negate u+  negate (Scalar c) = Scalar (negate c)+  negate (Sub c) = Sub $ negate c++instance (Fact m, CElt t r) => Ring.C (Cyc t m r) where+  {-# INLINABLE one #-}+  one = Scalar one++  {-# INLINABLE fromInteger #-}+  fromInteger = Scalar . fromInteger++  {-# INLINABLE (*) #-}++  -- optimized mul-by-zero+  v1@(Scalar c1) * _ | isZero c1 = v1+  _ * v2@(Scalar c2) | isZero c2 = v2++  -- both CRT+  (CRT u1) * (CRT u2) = CRT $ u1*u2++  -- at least one Scalar+  (Scalar c1) * (Scalar c2) = Scalar $ c1*c2+  (Scalar c) * (Pow u) = Pow $ c *> u+  (Scalar c) * (Dec u) = Dec $ c *> u+  (Scalar c) * (CRT u) = CRT $ c *> u+  (Scalar c1) * (Sub c2) = Sub $ Scalar c1 * c2++  (Pow u) * (Scalar c) = Pow $ c *> u+  (Dec u) * (Scalar c) = Dec $ c *> u+  (CRT u) * (Scalar c) = CRT $ c *> u+  (Sub c1) * (Scalar c2) = Sub $ c1 * Scalar c2++  -- TWO SUBS: work in a CRT rep for compositum+  (Sub (c1 :: Cyc t m1 r)) * (Sub (c2 :: Cyc t m2 r)) =+    -- re-wrap c1, c2 as Subs of the composition, and force them to CRT+    (Sub $ (toCRT' $ Sub c1 :: Cyc t (FLCM m1 m2) r) * toCRT' (Sub c2))+    \\ lcm2Divides (Proxy::Proxy m1) (Proxy::Proxy m2) (Proxy::Proxy m)++  -- ELSE: work in appropriate CRT rep+  c1 * c2 = toCRT' c1 * toCRT' c2++instance (GFCtx fp d, Fact m, CElt t fp) => Module.C (GF fp d) (Cyc t m fp) where+  -- CJP: optimize for Scalar if we can: r *> (Scalar c) is the tensor+  -- that has the coeffs of (r*c), followed by zeros.  (This assumes+  -- that the powerful basis has 1 as its first element, and that+  -- we're using pow to define the module mult.)++  -- can use any r-basis to define module mult, but must be+  -- consistent.+  r *> (Pow v) = Pow $ r LP.*> v+  r *> x = r *> toPow' x++---------- Core cyclotomic operations ----------++advisePow, adviseDec, adviseCRT :: (Fact m, CElt t r) => Cyc t m r -> Cyc t m r+{-# INLINABLE advisePow #-}+{-# INLINABLE adviseDec #-}+{-# INLINABLE adviseCRT #-}++-- | Same as 'adviseCRT', but for the powerful-basis representation.+advisePow = toPow'++-- | Same as 'adviseCRT', but for the powerful-basis representation.+adviseDec = toDec'++-- | Yield an equivalent element that /may/ be in a CRT+-- representation.  This can serve as an optimization hint. E.g.,+-- call 'adviseCRT' prior to multiplying the same value by many+-- other values.+adviseCRT = toCRT'++-- | Multiply by the special element @g@ of the @m@th cyclotomic.+mulG :: (Fact m, CElt t r) => Cyc t m r -> Cyc t m r+{-# INLINABLE mulG #-}+mulG (Pow u) = Pow $ U.mulG u+mulG (Dec u) = Dec $ U.mulG u+mulG (CRT u) = CRT $ U.mulG u+mulG (Scalar r) = CRT $ U.mulG $ scalarCRT r+mulG (Sub c) = mulG $ embed' c   -- must go to full ring++-- | Divide by @g@, returning 'Nothing' if not evenly divisible.+-- WARNING: this implementation is not a constant-time algorithm, so+-- information about the argument may be leaked through a timing+-- channel.+divG :: (Fact m, CElt t r) => Cyc t m r -> Maybe (Cyc t m r)+{-# INLINABLE divG #-}+divG (Pow u) = Pow <$> U.divG u+divG (Dec u) = Dec <$> U.divG u+divG (CRT u) = CRT <$> U.divG u+divG (Scalar r) = CRT <$> U.divG (scalarCRT r)+divG (Sub c) = divG $ embed' c  -- must go to full ring++-- | Sample from the "tweaked" Gaussian error distribution @t*D@ in+-- the decoding basis, where @D@ has scaled variance @v@.  (Note: This+-- implementation uses Double precision to generate the Gaussian+-- sample, which may not be sufficient for rigorous proof-based+-- security.)+tGaussian :: (Fact m, OrdFloat q, Random q, Tensor t, TElt t q,+              ToRational v, MonadRandom rnd)+             => v -> rnd (Cyc t m q)+tGaussian = (Dec <$>) . U.tGaussian+{-# INLINABLE tGaussian #-}++-- | 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@ .+gSqNorm :: forall t m r . (Fact m, CElt t r) => Cyc t m r -> r+{-# INLINABLE gSqNorm #-}+gSqNorm (Pow u) = U.gSqNorm $ toDec u+gSqNorm (Dec u) = U.gSqNorm u+gSqNorm (CRT u) = U.gSqNorm $ toDec u+-- CJP: this is suboptimal (gSqNorm of scalar 1 is known)+-- also workaround scalarDec+gSqNorm (Scalar u) = U.gSqNorm (toDec $ scalarPow u :: UCyc t m D r)+gSqNorm (Sub c) = U.gSqNorm (U.embedDec $ uncycDec c :: UCyc t m D r)++-- | Generate an LWE error term with given scaled variance,+-- deterministically rounded with respect to the decoding basis.+errorRounded :: (ToInteger z, Tensor t, Fact m, TElt t z,+                 ToRational v, MonadRandom rnd) => v -> rnd (Cyc t m z)+{-# INLINABLE errorRounded #-}+errorRounded = (Dec <$>) . U.errorRounded++-- | Generate an LWE error term with given scaled variance @* p^2@ over+-- the given coset, deterministically rounded with respect to the+-- decoding basis.+errorCoset ::+  (Mod zp, z ~ ModRep zp, Lift zp z, Fact m,+   CElt t zp, TElt t z, ToRational v, MonadRandom rnd)+  => v -> Cyc t m zp -> rnd (Cyc t m z)+errorCoset v = (Dec <$>) . U.errorCoset v . uncycDec+{-# INLINABLE errorCoset #-}++---------- Inter-ring operations ----------++-- | Embed (lazily) into an extension ring.+embed :: forall t m m' r . (m `Divides` m') => Cyc t m r -> Cyc t m' r+{-# INLINABLE embed #-}+embed (Scalar c) = Scalar c           -- keep as scalar+embed (Sub (c :: Cyc t l r)) = Sub c  -- keep as subring element+  \\ transDivides (Proxy::Proxy l) (Proxy::Proxy m) (Proxy::Proxy m')+embed c = Sub c++-- | Force to a non-'Sub' constructor (for internal use only).+embed' :: forall t r l m . (l `Divides` m, CElt t r) => Cyc t l r -> Cyc t m r+{-# INLINE embed' #-}+embed' (Pow u) = Pow $ embedPow u+embed' (Dec u) = Dec $ embedDec u+embed' (CRT u) = either Pow CRT $ embedCRT u+embed' (Scalar c) = Scalar c+embed' (Sub (c :: Cyc t k r)) = embed' c+  \\ transDivides (Proxy::Proxy k) (Proxy::Proxy l) (Proxy::Proxy m)++-- | The "tweaked trace" (twace) function+-- @Tw(x) = (mhat \/ m'hat) * Tr(g' \/ g * x)@,+-- which fixes @R@ pointwise (i.e., @twace . embed == id@).+twace :: forall t m m' r . (m `Divides` m', CElt t r)+         => Cyc t m' r -> Cyc t m r+{-# INLINABLE twace #-}+twace (Pow u) = Pow $ U.twacePow u+twace (Dec u) = Dec $ U.twaceDec u+twace (CRT u) = either Pow CRT $ twaceCRT u+twace (Scalar u) = Scalar u+twace (Sub (c :: Cyc t l r)) = Sub (twace c :: Cyc t (FGCD l m) r)+                               \\ gcdDivides (Proxy::Proxy l) (Proxy::Proxy m)++-- | Return the given element's coefficient vector with respect to+-- the (relative) powerful/decoding basis of the cyclotomic+-- extension @O_m' / O_m@.+coeffsCyc :: (m `Divides` m', CElt t r) => R.Basis -> Cyc t m' r -> [Cyc t m r]+{-# INLINABLE coeffsCyc #-}+coeffsCyc R.Pow c' = Pow <$> U.coeffsPow (uncycPow c')+coeffsCyc R.Dec c' = Dec <$> U.coeffsDec (uncycDec c')++-- | The relative powerful basis of @O_m' / O_m@.+powBasis :: (m `Divides` m', CElt t r) => Tagged m [Cyc t m' r]+powBasis = (Pow <$>) <$> U.powBasis+{-# INLINABLE powBasis #-}++-- | The relative mod-@r@ CRT set of the extension.+crtSet :: (m `Divides` m', ZPP r, CElt t r, TElt t (ZpOf r))+          => Tagged m [Cyc t m' r]+crtSet = (Pow <$>) <$> U.crtSet+{-# INLINABLE crtSet #-}+++---------- Lattice operations and instances ----------++instance (Reduce a b, Fact m, CElt t a, CElt t b)+    -- CJP: need these specific constraints to get Reduce instance for Sub case+         => Reduce (Cyc t m a) (Cyc t m b) where+  {-# INLINABLE reduce #-}+  reduce (Pow u) = Pow $ reduce u+  reduce (Dec u) = Dec $ reduce u+  reduce (CRT u) = Pow $ reduce $ toPow u+  reduce (Scalar c) = Scalar $ reduce c+  reduce (Sub (c :: Cyc t l a)) = Sub (reduce c :: Cyc t l b)++type instance LiftOf (Cyc t m r) = Cyc t m (LiftOf r)++-- | Lift using the specified basis.+liftCyc :: (Lift b a, Fact m, TElt t a, CElt t b)+           => R.Basis -> Cyc t m b -> Cyc t m a+{-# INLINABLE liftCyc #-}++liftCyc R.Pow = liftPow+liftCyc R.Dec = liftDec++liftPow, liftDec :: (Lift b a, Fact m, TElt t a, CElt t b)+                    => Cyc t m b -> Cyc t m a+{-# INLINABLE liftPow #-}+{-# INLINABLE liftDec #-}++-- | Lift using the powerful basis.+liftPow (Pow u) = Pow $ lift u+liftPow (Dec u) = Pow $ lift $ toPow u+liftPow (CRT u) = Pow $ lift $ toPow u+-- optimized for subrings; these are correct for powerful basis but+-- not for decoding+liftPow (Scalar c) = Scalar $ lift c+liftPow (Sub c) = Sub $ liftPow c++-- | Lift using the decoding basis.+liftDec (Pow u) = Dec $ lift $ toDec u+liftDec (Dec u) = Dec $ lift u+liftDec (CRT u) = Dec $ lift $ toDec u+liftDec (Scalar c) = Dec $ lift $ toDec $ scalarPow c -- workaround scalarDec+liftDec (Sub c) = liftDec $ embed' c++-- | Unzip for unrestricted types.+unzipCyc :: (Tensor t, Fact m) => Cyc t m (a,b) -> (Cyc t m a, Cyc t m b)+{-# INLINABLE unzipCyc #-}+unzipCyc (Pow u) = Pow *** Pow $ U.unzipCyc u+unzipCyc (Dec u) = Dec *** Dec $ U.unzipCyc u+unzipCyc (CRT u) = CRT *** CRT $ U.unzipCyc u+unzipCyc (Scalar c) = Scalar *** Scalar $ c+unzipCyc (Sub c) = Sub *** Sub $ unzipCyc c++-- | Type-restricted (and potentially more efficient) unzip.+unzipCElt :: (Tensor t, Fact m, CElt t (a,b), CElt t a, CElt t b)+             => Cyc t m (a,b) -> (Cyc t m a, Cyc t m b)+{-# INLINABLE unzipCElt #-}+unzipCElt (Pow u) = Pow *** Pow $ U.unzipUCElt u+unzipCElt (Dec u) = Dec *** Dec $ U.unzipUCElt u+unzipCElt (CRT u) = CRT *** CRT $ U.unzipUCElt u+unzipCElt (Scalar c) = Scalar *** Scalar $ c+unzipCElt (Sub c) = Sub *** Sub $ unzipCElt c++-- generic RescaleCyc instance++instance {-# OVERLAPS #-} (Rescale a b, CElt t a, TElt t b)+    => R.RescaleCyc (Cyc t) a b where++  -- Optimized for subring constructors, for powerful basis.+  -- Analogs for decoding basis are not quite correct, because (* -1)+  -- doesn't commute with 'rescale' due to tiebreakers!+  rescaleCyc R.Pow (Scalar c) = Scalar $ rescale c+  rescaleCyc R.Pow (Sub c) = Sub $ R.rescalePow c++  rescaleCyc R.Pow c = Pow $ fmapPow rescale $ uncycPow c+  rescaleCyc R.Dec c = Dec $ fmapDec rescale $ uncycDec c+  {-# INLINABLE rescaleCyc #-}++-- specialized instance for product rings: ~2x faster algorithm+instance (Mod a, Field b, Lift a (ModRep a), Reduce (LiftOf a) b,+         CElt t (a,b), CElt t a, CElt t b, CElt t (LiftOf a))+         => R.RescaleCyc (Cyc t) (a,b) b where++  -- optimized for subrings and powerful basis (see comments in other+  -- instance for why this doesn't work for decoding basis)+  rescaleCyc R.Pow (Scalar c) = Scalar $ rescale c+  rescaleCyc R.Pow (Sub c) = Sub $ R.rescalePow c++  rescaleCyc bas c = let aval = proxy modulus (Proxy::Proxy a)+                         (a,b) = unzipCElt c+                         z = liftCyc bas a+                     in Scalar (recip (reduce aval)) * (b - reduce z)+  {-# INLINABLE rescaleCyc #-}+++instance (Gadget gad zq, Fact m, CElt t zq) => Gadget gad (Cyc t m zq) where+  gadget = (scalarCyc <$>) <$> gadget+  -- specialization fo 'encode', done efficiently+  encode s = ((* adviseCRT s) <$>) <$> gadget+  {-# INLINABLE gadget #-}+  {-# INLINABLE encode #-}++-- promote Decompose, using the powerful basis+instance (Decompose gad zq, Fact m, CElt t zq, CElt t (DecompOf zq))+         => Decompose gad (Cyc t m zq) where++  type DecompOf (Cyc t m zq) = Cyc t m (DecompOf zq)++  -- faster implementations: decompose directly in subring, which is+  -- correct because we decompose in powerful basis+  decompose (Scalar c) = pasteT $ Scalar <$> peelT (decompose c)+  decompose (Sub c) = pasteT $ Sub <$> peelT (decompose c)++  -- traverse: Traversable (UCyc t m P) and Applicative (Tagged gad ZL)+  decompose (Pow u) = fromZL $ Pow <$> traverse (toZL . decompose) u+  decompose c = decompose $ toPow' c++  {-# INLINABLE decompose #-}++toZL :: Tagged s [a] -> TaggedT s ZipList a+toZL = coerce++fromZL :: TaggedT s ZipList a -> Tagged s [a]+fromZL = coerce++-- promote Correct, using the decoding basis+instance (Correct gad zq, Fact m, CElt t zq) => Correct gad (Cyc t m zq) where+  -- sequence: Monad [] and Traversable (UCyc t m D)+  -- sequenceA: Applicative (UCyc t m D) and Traversable (TaggedT gad [])+  correct bs = Dec *** (Dec <$>) $+               second sequence $ U.unzipCyc $ (correct . pasteT) <$>+               sequenceA (uncycDec <$> peelT bs)+  {-# INLINABLE correct #-}++---------- Change of representation (internal use only) ----------++toPow', toDec', toCRT' :: (Fact m, CElt t r) => Cyc t m r -> Cyc t m r+{-# INLINE toPow' #-}+{-# INLINE toDec' #-}+{-# INLINE toCRT' #-}++-- | Force to powerful-basis representation (for internal use only).+toPow' c@(Pow _) = c+toPow' (Dec u) = Pow $ toPow u+toPow' (CRT u) = Pow $ toPow u+toPow' (Scalar c) = Pow $ scalarPow c+toPow' (Sub c) = toPow' $ embed' c++-- | Force to decoding-basis representation (for internal use only).+toDec' (Pow u) = Dec $ toDec u+toDec' c@(Dec _) = c+toDec' (CRT u) = Dec $ toDec u+toDec' (Scalar c) = Dec $ toDec $ scalarPow c -- workaround scalarDec+toDec' (Sub c) = toDec' $ embed' c++-- | Force to CRT representation (for internal use only).+toCRT' (Pow u) = CRT $ toCRT u+toCRT' (Dec u) = CRT $ toCRT u+toCRT' c@(CRT _) = c+toCRT' (Scalar c) = CRT $ scalarCRT c+-- CJP: below is the fastest algorithm for when both source and target+-- have the same CRTr/CRTe choice.  It is not the fastest when the+-- choices are different (it will do an unnecessary CRT if input is+-- non-CRT), but this is an unusual case.  Note: both toCRT' are+-- necessary in generaly, because embed' may not preserve CRT+-- representation!+toCRT' (Sub c) = toCRT' $ embed' $ toCRT' c++---------- Utility instances ----------++instance (Tensor t, Fact m, NFData r, TElt t r,+          NFData (CRTExt r), TElt t (CRTExt r)) => NFData (Cyc t m r) where+  rnf (Pow u) = rnf u+  rnf (Dec u) = rnf u+  rnf (CRT u) = rnf u+  rnf (Scalar u) = rnf u+  rnf (Sub c) = rnf c++instance (Random r, Tensor t, Fact m, CRTElt t r) => Random (Cyc t m r) where+  random g = let (u,g') = random g+             in (either Pow CRT u, g')+  {-# INLINABLE random #-}++  randomR _ = error "randomR non-sensical for Cyc"++instance (Arbitrary (UCyc t m P r)) => Arbitrary (Cyc t m r) where+  arbitrary = Pow <$> arbitrary+  shrink = shrinkNothing++instance (Show r, Show (CRTExt r), Tensor t, Fact m, TElt t r, TElt t (CRTExt r)) => Show (Cyc t m r) where+  show (Scalar c) = "Cyc Scalar: " ++ show c+  show (Pow u) = "Cyc: " ++ show u+  show (Dec u) = "Cyc: " ++ show u+  show (CRT u) = "Cyc: " ++ show u+  show (Sub c) = "Cyc Sub: " ++ show c
+ Crypto/Lol/Cyclotomic/Linear.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             GeneralizedNewtypeDeriving, KindSignatures,+             MultiParamTypeClasses, NoImplicitPrelude, RoleAnnotations,+             ScopedTypeVariables, StandaloneDeriving, TypeFamilies,+             TypeOperators, UndecidableInstances #-}++-- | Functions from one cyclotomic ring to another that are linear+-- over a common subring.++module Crypto.Lol.Cyclotomic.Linear+( Linear, ExtendLinIdx+, linearDec, evalLin, extendLin+) where++import Crypto.Lol.Cyclotomic.Cyc+import Crypto.Lol.LatticePrelude++import Algebra.Additive as Additive (C)++import Control.Applicative+import Control.DeepSeq++-- | An @E@-linear function from @R@ to @S@.++-- CJP: also have constructor for relative Pow basis of R/E?  So far+-- not needed.+newtype Linear t z (e::Factored) (r::Factored) (s::Factored) = RD [Cyc t s z]++deriving instance (NFData (Cyc t s z)) => NFData (Linear t z e r s)++-- some params are phantom but matter for safety+type role Linear representational nominal representational representational nominal++-- | Construct an @E@-linear function given a list of its output values+-- (in @S@) on the relative decoding basis of @R/E@.  The number of+-- elements in the list must not exceed the size of the basis.+linearDec :: forall t z e r s .+             (e `Divides` r, e `Divides` s, CElt t z)+             => [Cyc t s z] -> Linear t z e r s+linearDec ys = let ps = proxy powBasis (Proxy::Proxy e) `asTypeOf` ys+               in if length ys <= length ps then RD (adviseCRT <$> ys)+               else error $ "linearDec: too many entries: "+                        ++ show (length ys) ++ " versus "+                        ++ show (length ps)++-- | Evaluates the given linear function on the input.+evalLin :: forall t z e r s .+           (e `Divides` r, e `Divides` s, CElt t z)+           => Linear t z e r s -> Cyc t r z -> Cyc t s z+evalLin (RD ys) r = sum (zipWith (*) ys $+                         embed <$> (coeffsCyc Dec r :: [Cyc t e z]))++instance Additive (Cyc t s z) => Additive.C (Linear t z e r s) where+  zero = RD []++  (RD as) + (RD bs) = RD $ sumall as bs+    where sumall [] ys = ys+          sumall xs [] = xs+          sumall (x:xs) (y:ys) = x+y : sumall xs ys++  negate (RD as) = RD $ negate <$> as++instance (Reduce z zq, Fact s, CElt t z, CElt t zq)+         => Reduce (Linear t z e r s) (Linear t zq e r s) where+  reduce (RD ys) = RD $ reduce <$> ys++type instance LiftOf (Linear t zp e r s) = Linear t (LiftOf zp) e r s++instance (CElt t zp, CElt t z, z ~ LiftOf zp, Lift zp z, Fact s)+         => Lift' (Linear t zp e r s) where+  lift (RD ys) = RD $ liftCyc Pow <$> ys++-- | A convenient constraint synonym for extending a linear function+-- to larger rings.+type ExtendLinIdx e r s e' r' s' =+  (Fact r, e ~ FGCD r e', r' ~ FLCM r e', -- these imply R'=R\otimes_E E'+   e' `Divides` s', s `Divides` s') -- lcm(s,e')|s' <=> (S+E') \subseteq S'++-- | Extend an @E@-linear function @R->S@ to an @E'@-linear function+-- @R\'->S\'@.  (Mathematically, such extension only requires+-- @lcm(r,e\') | r\'@ (not equality), but this generality would+-- significantly complicate the implementation, and for our purposes+-- there's no reason to use any larger @r'@.)+extendLin :: (ExtendLinIdx e r s e' r' s', CElt t z)+           => Linear t z e r s -> Linear t z e' r' s'+-- CJP: this simple implementation works because R/E and R'/E' have+-- identical decoding bases, because R' \cong R \otimes_E E'.  If we+-- relax the constraint on E then we'd have to change the+-- implementation to something more difficult.+extendLin (RD ys) = RD (embed <$> ys)
+ Crypto/Lol/Cyclotomic/RescaleCyc.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE MultiParamTypeClasses #-}++module Crypto.Lol.Cyclotomic.RescaleCyc where++import Crypto.Lol.Factored++data Basis = Pow | Dec++-- | Represents cyclotomic rings that are rescalable over their base+-- rings.  (This is a class because it allows for more efficient+-- specialized implementations.)++class RescaleCyc c a b where+  -- | Rescale in the given basis.+  rescaleCyc :: Fact m => Basis -> c m a -> c m b++-- | Specialized convenience functions.+rescalePow, rescaleDec :: (RescaleCyc c a b, Fact m) => c m a -> c m b+{-# INLINE rescalePow #-}+{-# INLINE rescaleDec #-}+rescalePow = rescaleCyc Pow+rescaleDec = rescaleCyc Dec+
+ Crypto/Lol/Cyclotomic/Tensor.hs view
@@ -0,0 +1,447 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             NoImplicitPrelude, PolyKinds, RankNTypes, ScopedTypeVariables, +             TupleSections, TypeFamilies, TypeOperators, +             UndecidableInstances #-}++-- | Interface for cyclotomic tensors, and helper functions for tensor+-- indexing.++module Crypto.Lol.Cyclotomic.Tensor+( Tensor(..), CRTElt+-- * Top-level CRT functions+, hasCRTFuncs+, scalarCRT, mulGCRT, divGCRT, crt, crtInv, twaceCRT, embedCRT+-- * Tensor indexing+, Matrix, indexM, twCRTs+, zmsToIndexFact+, indexInfo+, extIndicesPowDec, extIndicesCRT, extIndicesCoeffs+, baseIndicesPow, baseIndicesDec, baseIndicesCRT+, digitRev+)+where++import Crypto.Lol.CRTrans+import Crypto.Lol.LatticePrelude as LP hiding (lift, (*>))+import Crypto.Lol.Types.FiniteField++import           Control.Applicative+import           Control.DeepSeq+import           Control.Monad.Random+import           Data.Constraint+import           Data.Singletons.Prelude hiding ((:-))+import           Data.Traversable+import           Data.Tuple           (swap)+import qualified Data.Vector          as V+import qualified Data.Vector.Unboxed  as U++-- | Synonym for constraints required for CRT-related functions.+type CRTElt t r = (ZeroTestable r, IntegralDomain r, CRTrans r, TElt t r)++-- | 'Tensor' encapsulates all the core linear transformations needed+-- for cyclotomic ring arithmetic.++-- | The type @t m r@ represents a cyclotomic coefficient tensor of+-- index @m@ over base ring @r@.  Most of the methods represent linear+-- transforms corresponding to operations in particular bases.+-- CRT-related methods are wrapped in 'Maybe' because they are+-- well-defined only when a CRT basis exists over the ring @r@ for+-- index @m@.++-- | The superclass constraints are for convenience, to ensure that we+-- can sample error tensors of 'Double's.++-- | __WARNING:__ as with all fixed-point arithmetic, the methods+-- in 'Tensor' may result in overflow (and thereby incorrect answers+-- and potential security flaws) if the input arguments are too close+-- to the bounds imposed by the base type.  The acceptable range of+-- inputs for each method is determined by the linear transform it+-- implements.++class (TElt t Double, TElt t (Complex Double))+      => Tensor (t :: Factored -> * -> *) where++  -- | Constraints needed by @t@ to hold type @r@.+  type TElt t r :: Constraint++  -- | Properties that hold for any index. Use with '\\'.+  entailIndexT :: Tagged (t m r)+                  (Fact m :- (Applicative (t m), Traversable (t m)))+  +  -- | Properties that hold for any (legal) fully-applied tensor. Use+  -- with '\\'.+  entailEqT :: Tagged (t m r)+               ((Eq r, Fact m, TElt t r) :- Eq (t m r))+  entailZTT :: Tagged (t m r)+               ((ZeroTestable r, Fact m, TElt t r) :- ZeroTestable (t m r))+  entailNFDataT :: Tagged (t m r)+                   ((NFData r, Fact m, TElt t r) :- NFData (t m r))+  entailRandomT :: Tagged (t m r)+                   ((Random r, Fact m, TElt t r) :- Random (t m r))+  entailShowT :: Tagged (t m r)+                 ((Show r, Fact m, TElt t r) :- (Show (t m r)))+  entailModuleT :: Tagged (GF fp d, t m fp)+                   ((GFCtx fp d, Fact m, TElt t fp) :- Module (GF fp d) (t m fp))++  -- | Convert a scalar to a tensor in the powerful basis.+  scalarPow :: (Additive r, Fact m, TElt t r) => r -> t m r++  {- CJP: suppressed to do annoyingly complicated algorithm++  -- | Convert a scalar to a tensor in the decoding basis.+  scalarDec :: (Additive r, Fact m, TElt t r) => r -> t m r+  -}++  -- | 'l' converts from decoding-basis representation to+  -- powerful-basis representation; 'lInv' is its inverse.+  l, lInv :: (Additive r, Fact m, TElt t r) => t m r -> t m r++  -- | Multiply by @g@ in the powerful/decoding basis+  mulGPow, mulGDec :: (Ring r, Fact m, TElt t r) => t m r -> t m r++  -- | Divide by @g@ in the powerful/decoding basis.  The 'Maybe'+  -- output indicates that the operation may fail, which happens+  -- exactly when the input is not divisible by @g@.+  divGPow, divGDec :: (ZeroTestable r, IntegralDomain r, Fact m, TElt t r)+                      => t m r -> Maybe (t m r)++  -- | A tuple of all the operations relating to the CRT basis, in a+  -- single 'Maybe' value for safety.  Clients should typically not+  -- use this method directly, but instead call the corresponding+  -- top-level functions: the elements of the tuple correpond to the+  -- functions 'scalarCRT', 'mulGCRT', 'divGCRT', 'crt', 'crtInv'.+  crtFuncs :: (Fact m, CRTElt t r) =>+              Maybe (    r -> t m r, -- scalarCRT+                     t m r -> t m r, -- mulGCRT+                     t m r -> t m r, -- divGCRT+                     t m r -> t m r, -- crt+                     t m r -> t m r) -- crtInv++  -- | Sample from the "tweaked" Gaussian error distribution @t*D@+  -- in the decoding basis, where @D@ has scaled variance @v@.+  tGaussianDec :: (OrdFloat q, Random q, TElt t q,+                   ToRational v, Fact m, MonadRandom rnd)+                  => v -> rnd (t m q)++  -- | Given the coefficient tensor of @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 :: (Ring r, Fact m, TElt t r) => t m r -> r++  -- | The @twace@ linear transformation, which is the same in both the+  -- powerful and decoding bases.+  twacePowDec :: (Ring r, m `Divides` m', TElt t r) => t m' r -> t m r++  -- | The @embed@ linear transformations, for the powerful and+  -- decoding bases.+  embedPow, embedDec :: (Additive r, m `Divides` m', TElt t r)+                        => t m r -> t m' r++  -- | A tuple of all the extension-related operations involving the+  -- CRT bases, for safety.  Clients should typically not use this+  -- method directly, but instead call the corresponding top-level+  -- functions: the elements of the tuple correpond to the functions+  -- 'twaceCRT', 'embedCRT'.+  crtExtFuncs :: (m `Divides` m', CRTElt t r) =>+                 Maybe (t m' r -> t m  r, -- twaceCRT+                        t m  r -> t m' r) -- embedCRT++  -- | Map a tensor in the powerful\/decoding\/CRT basis, representing+  -- an @O_m'@ element, to a vector of tensors representing @O_m@+  -- elements in the same kind of basis.+  coeffs :: (Ring r, m `Divides` m', TElt t r) => t m' r -> [t m r]++  -- | The powerful extension basis w.r.t. the powerful basis.+  powBasisPow :: (Ring r, TElt t r, m `Divides` m') => Tagged m [t m' r]++  -- | A list of tensors representing the mod-@p@ CRT set of the+  -- extension.+  crtSetDec :: (m `Divides` m', PrimeField fp, Coprime (PToF (CharOf fp)) m',+                TElt t fp)+               => Tagged m [t m' fp]++  -- | Potentially optimized version of 'fmap' when the input and+  -- output element types satisfy 'TElt'.+  fmapT :: (Fact m, TElt t a, TElt t b) => (a -> b) -> t m a -> t m b+  -- | Potentially optimized monadic 'fmap'.+  fmapTM :: (Monad mon, Fact m, TElt t a, TElt t b)+             => (a -> mon b) -> t m a -> mon (t m b)++  -- | Potentially optimized 'zipWith'.+  zipWithT :: (Fact m, TElt t a, TElt t b, TElt t c)+              => (a -> b -> c) -> t m a -> t m b -> t m c++  -- | Unzip for types that satisfy 'TElt'.+  unzipTElt :: (Fact m, TElt t (a,b), TElt t a, TElt t b) +               => t m (a,b) -> (t m a, t m b)+  -- | Unzip for arbitrary types.+  unzipT :: (Fact m) => t m (a,b) -> (t m a, t m b)++-- | Convenience value indicating whether 'crtFuncs' exists.+hasCRTFuncs :: forall t m r . (Tensor t, Fact m, CRTElt t r)+               => TaggedT (t m r) Maybe ()+{-# INLINABLE hasCRTFuncs #-}+hasCRTFuncs = tagT $ do+  (_ :: r -> t m r,_,_,_,_) <- crtFuncs+  return ()++-- | Yield a tensor for a scalar in the CRT basis.  (This function is+-- simply an appropriate entry from 'crtFuncs'.)+scalarCRT :: (Tensor t, Fact m, CRTElt t r) => Maybe (r -> t m r)+{-# INLINABLE scalarCRT #-}+scalarCRT = (\(f,_,_,_,_) -> f) <$> crtFuncs+++mulGCRT, divGCRT, crt, crtInv ::+  (Tensor t, Fact m, CRTElt t r) => Maybe (t m r -> t m r)+{-# INLINABLE mulGCRT #-}+{-# INLINABLE divGCRT #-}+{-# INLINABLE crt #-}+{-# INLINABLE crtInv #-}++-- | Multiply by @g@ in the CRT basis. (This function is simply an+-- appropriate entry from 'crtFuncs'.)+mulGCRT = (\(_,f,_,_,_) -> f) <$> crtFuncs+-- | Divide by @g@ in the CRT basis.  (This function is simply an+-- appropriate entry from 'crtFuncs'.)+divGCRT = (\(_,_,f,_,_) -> f) <$> crtFuncs+-- | The CRT transform.  (This function is simply an appropriate entry+-- from 'crtFuncs'.)+crt = (\(_,_,_,f,_) -> f) <$> crtFuncs+-- | The inverse CRT transform.  (This function is simply an+-- appropriate entry from 'crtFuncs'.)+crtInv = (\(_,_,_,_,f) -> f) <$> crtFuncs++-- | The "tweaked trace" function for tensors in the CRT basis:+-- For cyclotomic indices m | m',+-- @Tw(x) = (mhat\/m\'hat) * Tr(g\'\/g * x)@.+-- (This function is simply an appropriate entry from 'crtExtFuncs'.)+twaceCRT :: forall t r m m' . (Tensor t, m `Divides` m', CRTElt t r)+            => Maybe (t m' r -> t m r)+twaceCRT = proxyT hasCRTFuncs (Proxy::Proxy (t m' r)) *>+           proxyT hasCRTFuncs (Proxy::Proxy (t m  r)) *>+           (fst <$> crtExtFuncs)++-- | Embed a tensor with index @m@ in the CRT basis to a tensor with+-- index @m'@ in the CRT basis.+-- (This function is simply an appropriate entry from 'crtExtFuncs'.)+embedCRT :: forall t r m m' . (Tensor t, m `Divides` m', CRTElt t r)+            => Maybe (t m r -> t m' r)+embedCRT = proxyT hasCRTFuncs (Proxy::Proxy (t m' r)) *>+           proxyT hasCRTFuncs (Proxy::Proxy (t m  r)) *>+           (snd <$> crtExtFuncs)++fMatrix :: forall m r mon . (Fact m, Monad mon, Ring r)+           => (forall pp . (PPow pp) => TaggedT pp mon (MatrixC r))+           -> TaggedT m mon (Matrix r)+fMatrix mat = tagT $ go $ sUnF (sing :: SFactored m)+  where go :: Sing (pplist :: [PrimePower]) -> mon (Matrix r)+        go spps = case spps of+          SNil -> return MNil+          (SCons spp rest) -> do+            rest' <- go rest+            mat' <- withWitnessT mat spp+            return $ MKron rest' mat'++-- deeply embedded DSL for Kronecker products of matrices++data MatrixC r = +  MC (Int -> Int -> r)           -- yields element i,j+  Int Int                        -- dims++-- | A Kronecker product of zero of more matrices over @r@.+data Matrix r = MNil | MKron (Matrix r) (MatrixC r)++-- | Extract the @(i,j)@ element of a 'Matrix'.+indexM :: Ring r => Matrix r -> Int -> Int -> r+indexM MNil 0 0 = LP.one+indexM (MKron m (MC mc r c)) i j =+  let (iq,ir) = i `divMod` r+      (jq,jr) = j `divMod` c+      in indexM m iq jq * mc ir jr++-- | The "tweaked" CRT^* matrix: @CRT^* . diag(sigma(g_m))@.+twCRTs :: (Fact m, CRTrans r) => TaggedT m Maybe (Matrix r)+twCRTs = fMatrix twCRTsPPow++-- | The "tweaked" CRT^* matrix (for prime powers): @CRT^* * diag(sigma(g_p))@.+twCRTsPPow :: (PPow pp, CRTrans r) => TaggedT pp Maybe (MatrixC r)+twCRTsPPow = do+  phi    <- pureT totientPPow+  iToZms <- pureT indexToZmsPPow+  jToPow <- pureT indexToPowPPow+  (wPow, _) <- crtInfoPPow+  gEmb <- gEmbPPow++  return $ MC (\j i -> let i' = iToZms i+                       in wPow (jToPow j * negate i') * gEmb i') phi phi++-- Reindexing functions++-- | Base-p digit reversal; input and output are in @[p^e]@.+digitRev :: PP -> Int -> Int+digitRev (_,0) 0 = 0+-- CJP: use accumulator to avoid multiple exponentiations?+digitRev (p,e) j +  | e >= 1 = let (q,r) = j `divMod` p+             in r * (p^(e-1)) + digitRev (p,e-1) q++indexToPowPPow, indexToZmsPPow :: PPow pp => Tagged pp (Int -> Int)+indexToPowPPow = indexToPow <$> ppPPow+indexToZmsPPow = indexToZms <$> ppPPow++-- | Convert a @Z_m^*@ index to a linear tensor index in @[m]@.+zmsToIndexFact :: Fact m => Tagged m (Int -> Int)+zmsToIndexFact = zmsToIndex <$> ppsFact++-- | For a prime power @p^e@, map a tensor index to the corresponding+-- power j in @[phi(p^e)]@, as in the powerful basis.+indexToPow :: PP -> Int -> Int+-- CJP: use accumulator to avoid multiple exponentiations?+indexToPow (p,e) j = let (jq,jr) = j `divMod` (p-1)+                     in p^(e-1)*jr + digitRev (p,e-1) jq++-- | For a prime power @p^e@, map a tensor index to the corresponding+-- element i in @Z_{p^e}^*@.+indexToZms :: PP -> Int -> Int+indexToZms (p,_) i = let (i1,i0) = i `divMod` (p-1)+                       in p*i1 + i0 + 1 ++-- | Convert a Z_m^* index to a linear tensor index.+zmsToIndex :: [PP] -> Int -> Int+zmsToIndex [] _ = 0+zmsToIndex (pp:rest) i = zmsToIndexPP pp (i `mod` valuePP pp)+                         + (totientPP pp) * zmsToIndex rest i++-- | Inverse of 'indexToZms'.+zmsToIndexPP :: PP -> Int -> Int+zmsToIndexPP (p,_) i = let (i1,i0) = i `divMod` p+                       in (p-1)*i1 + i0 - 1++-- Index correspondences for ring extensions++-- | Correspondences between the linear indexes into a basis of O_m',+-- and pair indices into (extension basis) \otimes (basis of O_m).+-- The work the same for Pow,Dec,CRT bases because all these bases+-- have that factorization.  The first argument is the list of+-- @(phi(m),phi(m'))@ pairs for the (merged) prime powers of @m@,@m'@.+toIndexPair :: [(Int,Int)] -> Int -> (Int,Int)+fromIndexPair :: [(Int,Int)] -> (Int,Int) -> Int++toIndexPair [] 0 = (0,0)+toIndexPair ((phi,phi'):rest) i' =+  let (i'q,i'r) = i' `divMod` phi'+      (i'rq,i'rr) = i'r `divMod` phi+      (i'q1,i'q0) = toIndexPair rest i'q+  in (i'rq + i'q1*(phi' `div` phi), i'rr + i'q0*phi)++fromIndexPair [] (0,0) = 0+fromIndexPair ((phi,phi'):rest) (i1,i0) =+  let (i0q,i0r) = i0 `divMod` phi+      (i1q,i1r) = i1 `divMod` (phi' `div` phi)+      i = fromIndexPair rest (i1q,i0q)+  in (i0r + i1r*phi) + i*phi'++-- | A collection of useful information for working with tensor+-- extensions.  The first component is a list of triples @(p,e,e')@+-- where @e@, @e'@ are respectively the exponents of prime @p@ in @m@,+-- @m'@.  The next two components are @phi(m)@ and @phi(m')@.  The+-- final component is a pair @(phi(p^e), phi(p^e'))@ for each triple+-- in the first component.+indexInfo :: forall m m' . (m `Divides` m')+             => Tagged '(m, m') ([(Int,Int,Int)], Int, Int, [(Int,Int)])+indexInfo = let pps = proxy ppsFact (Proxy::Proxy m)+                pps' = proxy ppsFact (Proxy::Proxy m')+                mpps = mergePPs pps pps'+                phi = totientPPs pps+                phi' = totientPPs pps'+                tots = totients mpps+            in tag (mpps, phi, phi', tots)++-- | A vector of @phi(m)@ entries, where the @i@th entry is the index+-- into the powerful\/decoding basis of @O_m'@ of the+-- @i@th entry of the powerful\/decoding basis of @O_m@.+extIndicesPowDec :: (m `Divides` m') => Tagged '(m, m') (U.Vector Int)+extIndicesPowDec = do+  (_, phi, _, tots) <- indexInfo+  return $ U.generate phi (fromIndexPair tots . (0,))++-- | A vector of @phi(m)@ blocks of @phi(m')\/phi(m)@ consecutive+-- entries. Each block contains all those indices into the CRT basis+-- of @O_m'@ that "lie above" the corresponding index into the CRT+-- basis of @O_m@.+extIndicesCRT :: forall m m' . (m `Divides` m')+                 => Tagged '(m, m') (U.Vector Int)+extIndicesCRT = do+  (_, phi, phi', tots) <- indexInfo+  return $ U.generate phi'+           (fromIndexPair tots . swap . (`divMod` (phi' `div` phi)))++baseWrapper :: forall m m' a . (m `Divides` m', U.Unbox a)+               => ([(Int,Int,Int)] -> Int -> a)+               -> Tagged '(m, m') (U.Vector a)+baseWrapper f = do+  (mpps, _, phi', _) <- indexInfo+  return $ U.generate phi' (f mpps)++-- | A lookup table for 'toIndexPair' applied to indices @[phi(m')]@.+baseIndicesPow :: forall m m' . (m `Divides` m')+                  => Tagged '(m, m') (U.Vector (Int,Int))+-- | A lookup table for 'baseIndexDec' applied to indices @[phi(m')]@.+baseIndicesDec :: forall m m' . (m `Divides` m')+                  => Tagged '(m, m') (U.Vector (Maybe (Int,Bool)))++-- | Same as 'baseIndicesPow', but only includes the second component+-- of each pair.+baseIndicesCRT :: forall m m' . (m `Divides` m')+                  => Tagged '(m, m') (U.Vector Int)++baseIndicesPow = baseWrapper (toIndexPair . totients)++-- this one is more complicated; requires the prime powers+baseIndicesDec = baseWrapper baseIndexDec++baseIndicesCRT =+  baseWrapper (\pps -> snd . toIndexPair (totients pps))+++-- | The @i0@th entry of the @i1@th vector is 'fromIndexPair' @(i1,i0)@.+extIndicesCoeffs :: forall m m' . (m `Divides` m')+                    => Tagged '(m, m') (V.Vector (U.Vector Int))+extIndicesCoeffs = do+  (_, phi, phi', tots) <- indexInfo+  return $ V.generate (phi' `div` phi)+           (\i1 -> U.generate phi (\i0 -> fromIndexPair tots (i1,i0)))++-- | Convenient reindexing functions++-- | Maps an index of the extension ring array to its corresponding+-- index in the base ring array (if it exists), with sign, under the+-- decoding basis.+baseIndexDec :: [(Int,Int,Int)] -> Int -> Maybe (Int, Bool)+baseIndexDec [] 0 = Just (0,False)+baseIndexDec ((p,e,e'):rest) i'+   = let (i'q, i'r) = i' `divMod` totientPP (p,e')+         phi = totientPP (p,e)+         curr+           | p>2 && e==0 && e' > 0 = case i'r of+               0 -> Just (0,False)+               1 -> Just (0,True)+               _ -> Nothing+           | otherwise = if i'r < phi then Just (i'r,False) else Nothing+     in do+       (i,b) <- curr+       (j,b') <- baseIndexDec rest i'q+       return (i + phi*j, b /= b')++-- the first list of pps must "divide" the other.  result is a list of+-- all (prime, min e, max e).+mergePPs :: [PP] -> [PP] -> [(Int,Int,Int)]+mergePPs [] pps = LP.map (\(p,e) -> (p,0,e)) pps+mergePPs allpps@((p,e):pps) ((p',e'):pps')+  | p == p' && e <= e' = (p,  e, e') : mergePPs pps pps'+  | p > p'  = (p', 0, e') : mergePPs allpps pps'++totients :: [(Int, Int, Int)] -> [(Int,Int)]+totients = LP.map (\(p,e,e') -> (totientPP (p,e), totientPP (p,e')))
+ Crypto/Lol/Cyclotomic/Tensor/CTensor.hs view
@@ -0,0 +1,474 @@+{-# LANGUAGE ConstraintKinds, DataKinds, GADTs,+             FlexibleContexts, FlexibleInstances, TypeOperators, PolyKinds,+             GeneralizedNewtypeDeriving, InstanceSigs, RoleAnnotations,+             MultiParamTypeClasses, NoImplicitPrelude, StandaloneDeriving,+             ScopedTypeVariables, TupleSections, TypeFamilies, RankNTypes,+             TypeSynonymInstances, UndecidableInstances,+             RebindableSyntax #-}++-- | Wrapper for a C implementation of the 'Tensor' interface.++module Crypto.Lol.Cyclotomic.Tensor.CTensor+( CT ) where++import Algebra.Additive     as Additive (C)+import Algebra.Module       as Module (C)+import Algebra.ZeroTestable as ZeroTestable (C)++import Control.Applicative hiding ((*>))+import Control.Arrow ((***))+import Control.DeepSeq+import Control.Monad (liftM)+import Control.Monad.Identity (Identity(..), runIdentity)+import Control.Monad.Random+import Control.Monad.Trans (lift)++import Data.Coerce+import Data.Constraint  hiding ((***))+import Data.Foldable as F+import Data.Int+import Data.Maybe+import Data.Traversable as T+import Data.Vector.Generic           as V (zip, unzip, fromList, toList)+import Data.Vector.Storable          as SV (Vector, (!), replicate, replicateM, thaw, convert, foldl',+                                            unsafeSlice, mapM, fromList, toList,+                                            generate, foldl1',+                                            unsafeWith, zipWith, map, length, unsafeFreeze, thaw)+import Data.Vector.Storable.Internal (getPtr)+import Data.Vector.Storable.Mutable  as SM hiding (replicate)++import Foreign.Marshal.Utils (with)+import Foreign.Ptr+import Foreign.Storable        (Storable (..))+import Test.QuickCheck         hiding (generate)++import Crypto.Lol.CRTrans+import Crypto.Lol.Cyclotomic.Tensor+import Crypto.Lol.Cyclotomic.Tensor.CTensor.Backend+import Crypto.Lol.Cyclotomic.Tensor.CTensor.Extension+import Crypto.Lol.GaussRandom+import Crypto.Lol.LatticePrelude as LP hiding (replicate, unzip, zip, lift)+import Crypto.Lol.Reflects+import Crypto.Lol.Types.FiniteField+import Crypto.Lol.Types.IZipVector+import Crypto.Lol.Types.ZqBasic++import System.IO.Unsafe (unsafePerformIO)++-- | Newtype wrapper around a Vector.+newtype CT' (m :: Factored) r = CT' { unCT :: Vector r } +                              deriving (Show, Eq, NFData)++-- the first argument, though phantom, affects representation+type role CT' representational nominal++-- GADT wrapper that distinguishes between Unbox and unrestricted+-- element types++-- | An implementation of 'Tensor' backed by C code.+data CT (m :: Factored) r where +  CT :: Storable r => CT' m r -> CT m r+  ZV :: IZipVector m r -> CT m r++instance Eq r => Eq (CT m r) where+  (ZV x) == (ZV y) = x == y+  (CT x) == (CT y) = x == y+  x@(CT _) == y = x == toCT y+  y == x@(CT _) = x == toCT y++deriving instance Show r => Show (CT m r)++toCT :: (Storable r) => CT m r -> CT m r+toCT v@(CT _) = v+toCT (ZV v) = CT $ zvToCT' v++toZV :: (Fact m) => CT m r -> CT m r+toZV (CT (CT' v)) = ZV $ fromMaybe (error "toZV: internal error") $+                    iZipVector $ convert v+toZV v@(ZV _) = v++zvToCT' :: forall m r . (Storable r) => IZipVector m r -> CT' m r+zvToCT' v = coerce (convert $ unIZipVector v :: Vector r)++wrap :: (Storable r) => (CT' l r -> CT' m r) -> (CT l r -> CT m r)+wrap f (CT v) = CT $ f v+wrap f (ZV v) = CT $ f $ zvToCT' v++wrapM :: (Storable r, Monad mon) => (CT' l r -> mon (CT' m r))+         -> (CT l r -> mon (CT m r))+wrapM f (CT v) = CT <$> f v+wrapM f (ZV v) = CT <$> f (zvToCT' v)++-- convert an CT' *twace* signature to Tagged one+type family Tw (r :: *) :: * where+  Tw (CT' m' r -> CT' m r) = Tagged '(m,m') (Vector r -> Vector r)+  Tw (Maybe (CT' m' r -> CT' m r)) = TaggedT '(m,m') Maybe (Vector r -> Vector r)++type family Em r where+  Em (CT' m r -> CT' m' r) = Tagged '(m,m') (Vector r -> Vector r)+  Em (Maybe (CT' m r -> CT' m' r)) = TaggedT '(m,m') Maybe (Vector r -> Vector r)+++---------- NUMERIC PRELUDE INSTANCES ----------++-- CJP: Additive, Ring are not necessary when we use zipWithT+-- EAC: This has performance implications for the CT backend,+--      which used a C function for zipWith (*)++instance (Additive r, Storable r, Fact m, Dispatch r)+  => Additive.C (CT m r) where+  (CT a@(CT' _)) + (CT b@(CT' _)) = CT $ (untag $ cZipDispatch dadd) a b+  a + b = (toCT a) + (toCT b)+  negate (CT (CT' a)) = CT $ CT' $ SV.map negate a -- EAC: This probably should be converted to C code+  negate a = negate $ toCT a++  zero = CT $ repl zero++{-+instance (Fact m, Ring r, Storable r, Dispatch r)+  => Ring.C (CT m r) where+  (CT a@(CT' _)) * (CT b@(CT' _)) = CT $ (untag $ cZipDispatch dmul) a b++  fromInteger = CT . repl . fromInteger+-}++instance (ZeroTestable r, Storable r, Fact m)+         => ZeroTestable.C (CT m r) where+  --{-# INLINABLE isZero #-} +  isZero (CT (CT' a)) = SV.foldl' (\ b x -> b && isZero x) True a+  isZero (ZV v) = isZero v++instance (GFCtx fp d, Fact m, Additive (CT m fp))+    => Module.C (GF fp d) (CT m fp) where++  r *> v = case v of+    CT (CT' arr) -> CT $ CT' $ SV.fromList $ unCoeffs $ r *> Coeffs $ SV.toList arr+    ZV zv -> ZV $ fromJust $ iZipVector $ V.fromList $ unCoeffs $ r *> Coeffs $ V.toList $ unIZipVector zv++---------- Category-theoretic instances ----------++instance Fact m => Functor (CT m) where+  -- Functor instance is implied by Applicative laws+  fmap f x = pure f <*> x++instance Fact m => Applicative (CT m) where+  pure = ZV . pure++  (ZV f) <*> (ZV a) = ZV (f <*> a)+  f@(ZV _) <*> v@(CT _) = f <*> toZV v++instance Fact m => Foldable (CT m) where+  -- Foldable instance is implied by Traversable+  foldMap = foldMapDefault++instance Fact m => Traversable (CT m) where+  traverse f r@(CT _) = T.traverse f $ toZV r+  traverse f (ZV v) = ZV <$> T.traverse f v++instance Tensor CT where++  type TElt CT r = (Storable r, Dispatch r)++  entailIndexT = tag $ Sub Dict+  entailEqT = tag $ Sub Dict+  entailZTT = tag $ Sub Dict+  -- entailRingT = tag $ Sub Dict+  entailNFDataT = tag $ Sub Dict+  entailRandomT = tag $ Sub Dict+  entailShowT = tag $ Sub Dict+  entailModuleT = tag $ Sub Dict++  scalarPow = CT . scalarPow' -- Vector code++  l = wrap $ untag $ basicDispatch dl+  lInv = wrap $ untag $ basicDispatch dlinv++  mulGPow = wrap mulGPow'+  mulGDec = wrap $ untag $ basicDispatch dmulgdec++  divGPow = wrapM divGPow'+  -- we divide by p in the C code (for divGDec only(?)), do NOT call checkDiv!+  divGDec = wrapM $ Just . untag (basicDispatch dginvdec)++  crtFuncs = (,,,,) <$>+    Just (CT . repl) <*>+    (wrap <$> untag (cZipDispatch dmul) <$> untagT gCoeffsCRT) <*>+    (wrap <$> untag (cZipDispatch dmul) <$> untagT gInvCoeffsCRT) <*>+    (wrap <$> untagT ctCRT) <*>+    (wrap <$> untagT ctCRTInv) ++  twacePowDec = wrap $ runIdentity $ coerceTw twacePowDec'+  embedPow = wrap $ runIdentity $ coerceEm embedPow'+  embedDec = wrap $ runIdentity $ coerceEm embedDec'++  tGaussianDec v = CT <$> cDispatchGaussian v+  --tGaussianDec v = CT <$> coerceT' (gaussianDec v)++  -- we do not wrap this function because (currently) it can only be called on lifted types+  gSqNormDec (CT v) = untag gSqNormDec' v+  gSqNormDec (ZV v) = gSqNormDec (CT $ zvToCT' v)++  crtExtFuncs = (,) <$> (wrap <$> coerceTw twaceCRT')+                    <*> (wrap <$> coerceEm embedCRT')++  coeffs = wrapM $ coerceCoeffs coeffs'++  powBasisPow = (CT <$>) <$> coerceBasis powBasisPow'++  crtSetDec = (CT <$>) <$> coerceBasis crtSetDec'++  fmapT f (CT v) = CT $ coerce (SV.map f) v+  fmapT f v@(ZV _) = fmapT f $ toCT v++  fmapTM f (CT (CT' v)) = (CT . CT') <$> SV.mapM f v+  fmapTM f v@(ZV _) = fmapTM f $ toCT v++  zipWithT f (CT (CT' v1)) (CT (CT' v2)) = CT $ CT' $ SV.zipWith f v1 v2+  zipWithT f v1 v2 = zipWithT f (toCT v1) (toCT v2)++  unzipTElt (CT (CT' v)) = (CT . CT') *** (CT . CT') $ unzip v+  unzipTElt v = unzipTElt $ toCT v++  unzipT v@(CT _) = unzipT $ toZV v+  unzipT (ZV v) = ZV *** ZV $ unzipIZV v++  {-# INLINABLE entailIndexT #-}+  {-# INLINABLE entailEqT #-}+  {-# INLINABLE entailZTT #-}+  {-# INLINABLE entailNFDataT #-}+  {-# INLINABLE entailRandomT #-}+  {-# INLINABLE entailShowT #-}+  {-# INLINABLE scalarPow #-}+  {-# INLINABLE l #-}+  {-# INLINABLE lInv #-}+  {-# INLINABLE mulGPow #-}+  {-# INLINABLE mulGDec #-}+  {-# INLINABLE divGPow #-}+  {-# INLINABLE divGDec #-}+  {-# INLINABLE crtFuncs #-}+  {-# INLINABLE twacePowDec #-}+  {-# INLINABLE embedPow #-}+  {-# INLINABLE embedDec #-}+  {-# INLINABLE tGaussianDec #-}+  {-# INLINABLE gSqNormDec #-}+  {-# INLINABLE crtExtFuncs #-}+  {-# INLINABLE coeffs #-}+  {-# INLINABLE powBasisPow #-}+  {-# INLINABLE crtSetDec #-}+  {-# INLINABLE fmapT #-}+  {-# INLINABLE fmapTM #-}+  {-# INLINABLE zipWithT #-}+  {-# INLINABLE unzipTElt #-}+  {-# INLINABLE unzipT #-}+++coerceTw :: (Functor mon) => TaggedT '(m, m') mon (Vector r -> Vector r) -> mon (CT' m' r -> CT' m r)+coerceTw = (coerce <$>) . untagT++coerceEm :: (Functor mon) => TaggedT '(m, m') mon (Vector r -> Vector r) -> mon (CT' m r -> CT' m' r)+coerceEm = (coerce <$>) . untagT++-- | Useful coersion for defining @coeffs@ in the @Tensor@+-- interface. Using 'coerce' alone is insufficient for type inference.+coerceCoeffs :: (Fact m, Fact m') +  => Tagged '(m,m') (Vector r -> [Vector r]) -> CT' m' r -> [CT' m r]+coerceCoeffs = coerce++-- | Useful coersion for defining @powBasisPow@ and @crtSetDec@ in the @Tensor@+-- interface. Using 'coerce' alone is insufficient for type inference.+coerceBasis :: +  (Fact m, Fact m')+  => Tagged '(m,m') [Vector r] -> Tagged m [CT' m' r]+coerceBasis = coerce++mulGPow' :: (TElt CT r, Fact m, Additive r) => CT' m r -> CT' m r+mulGPow' = untag $ basicDispatch dmulgpow++divGPow' :: forall m r . (TElt CT r, Fact m, IntegralDomain r, ZeroTestable r) => CT' m r -> Maybe (CT' m r)+divGPow' = untag $ checkDiv $ basicDispatch dginvpow++withBasicArgs :: forall m r . (Fact m, Storable r) +  => (Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()) +     -> CT' m r -> IO (CT' m r)+withBasicArgs f =+  let factors = proxy (marshalFactors <$> ppsFact) (Proxy::Proxy m)+      totm = proxy (fromIntegral <$> totientFact) (Proxy::Proxy m)+      numFacts = fromIntegral $ SV.length factors+  in \(CT' x) -> do+    yout <- SV.thaw x+    SM.unsafeWith yout (\pout ->+      SV.unsafeWith factors (\pfac ->+        f pout totm pfac numFacts))+    CT' <$> unsafeFreeze yout++basicDispatch :: forall m r .+     (Storable r, Fact m, Additive r)+      => (Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ())+         -> Tagged m (CT' m r -> CT' m r)+basicDispatch f = return $ unsafePerformIO . withBasicArgs f++gSqNormDec' :: forall m r .+     (Storable r, Fact m, Additive r, Dispatch r)+      => Tagged m (CT' m r -> r)+gSqNormDec' = return $ (!0) . unCT . unsafePerformIO . withBasicArgs dnorm++ctCRT :: forall m r . (Storable r, CRTrans r, Dispatch r,+          Fact m)+         => TaggedT m Maybe (CT' m r -> CT' m r)+ctCRT = do -- in TaggedT m Maybe+  ru' <- ru+  return $ \x -> unsafePerformIO $ +    withPtrArray ru' (flip withBasicArgs x . dcrt)++-- CTensor CRT^(-1) functions take inverse rus+ctCRTInv :: (Storable r, CRTrans r, Dispatch r,+          Fact m)+         => TaggedT m Maybe (CT' m r -> CT' m r)+ctCRTInv = do -- in Maybe+  mhatInv <- snd <$> crtInfoFact+  ruinv' <- ruInv+  return $ \x -> unsafePerformIO $ +    withPtrArray ruinv' (\ruptr -> with mhatInv (flip withBasicArgs x . dcrtinv ruptr))++checkDiv :: forall m r . +  (IntegralDomain r, Storable r, ZeroTestable r, +   Fact m)+    => Tagged m (CT' m r -> CT' m r) -> Tagged m (CT' m r -> Maybe (CT' m r))+checkDiv f = do+  f' <- f+  oddRad' <- fromIntegral <$> oddRadicalFact+  return $ \x -> +    let (CT' y) = f' x+    in CT' <$> SV.mapM (`divIfDivis` oddRad') y++divIfDivis :: (IntegralDomain r, ZeroTestable r) => r -> r -> Maybe r+divIfDivis num den = let (q,r) = num `divMod` den+                     in if isZero r then Just q else Nothing++cZipDispatch :: (Storable r, Fact m, Additive r)+  => (Ptr r -> Ptr r -> Int64 -> IO ())+     -> Tagged m (CT' m r -> CT' m r -> CT' m r)+cZipDispatch f = do -- in Tagged m+  totm <- fromIntegral <$> totientFact+  return $ coerce $ \a b -> unsafePerformIO $ do+    yout <- SV.thaw a+    SM.unsafeWith yout (\pout ->+      SV.unsafeWith b (\pin ->+        f pout pin totm))+    unsafeFreeze yout++cDispatchGaussian :: forall m r var rnd .+         (Storable r, Transcendental r, Dispatch r, Ord r,+          Fact m, ToRational var, Random r, MonadRandom rnd)+         => var -> rnd (CT' m r)+cDispatchGaussian var = flip proxyT (Proxy::Proxy m) $ do -- in TaggedT m rnd+  -- get rus for (Complex r)+  ruinv' <- mapTaggedT (return . fromMaybe (error "complexGaussianRoots")) ruInv+  totm <- pureT totientFact+  m <- pureT valueFact+  rad <- pureT radicalFact+  yin <- lift $ realGaussians (var * fromIntegral (m `div` rad)) totm+  return $ unsafePerformIO $ +    withPtrArray ruinv' (\ruptr -> withBasicArgs (dgaussdec ruptr) (CT' yin))++instance (Arbitrary r, Fact m, Storable r) => Arbitrary (CT' m r) where+  arbitrary = replM arbitrary+  shrink = shrinkNothing++instance (Storable r, Arbitrary (CT' m r)) => Arbitrary (CT m r) where+  arbitrary = CT <$> arbitrary++instance (Storable r, Random r, Fact m) => Random (CT' m r) where+  --{-# INLINABLE random #-}+  random = runRand $ replM (liftRand random)++  randomR = error "randomR nonsensical for CT'"++instance (Storable r, Random (CT' m r)) => Random (CT m r) where+  --{-# INLINABLE random #-}+  random = runRand $ CT <$> liftRand random++  randomR = error "randomR nonsensical for CT"++instance (NFData r) => NFData (CT m r) where+  rnf (CT v) = rnf v+  rnf (ZV v) = rnf v++repl :: forall m r . (Fact m, Storable r) => r -> CT' m r+repl = let n = proxy totientFact (Proxy::Proxy m)+       in coerce . SV.replicate n++replM :: forall m r mon . (Fact m, Storable r, Monad mon) +         => mon r -> mon (CT' m r)+replM = let n = proxy totientFact (Proxy::Proxy m)+        in fmap coerce . SV.replicateM n++--{-# INLINE scalarPow' #-}+scalarPow' :: forall m r . (Fact m, Additive r, Storable r) => r -> CT' m r+-- constant-term coefficient is first entry wrt powerful basis+scalarPow' = +  let n = proxy totientFact (Proxy::Proxy m)+  in \r -> CT' $ generate n (\i -> if i == 0 then r else zero)++ru, ruInv :: forall r m . +   (CRTrans r, Fact m, Storable r)+   => TaggedT m Maybe [Vector r]+--{-# INLINE ru #-}+ru = do+  mval <- pureT valueFact+  wPow <- fst <$> crtInfoFact+  LP.map+    (\(p,e) -> do+        let pp = p^e+            pow = mval `div` pp+        generate pp (wPow . (*pow))) <$>+      pureT ppsFact++--{-# INLINE ruInv #-}+ruInv = do+  mval <- pureT valueFact+  wPow <- fst <$> crtInfoFact+  LP.map+    (\(p,e) -> do+        let pp = p^e+            pow = mval `div` pp+        generate pp (\i -> wPow $ -i*pow)) <$>+      pureT ppsFact++gCoeffsCRT, gInvCoeffsCRT :: (TElt CT r, CRTrans r, Fact m, ZeroTestable r, IntegralDomain r)+  => TaggedT m Maybe (CT' m r)+gCoeffsCRT = ctCRT <*> return (mulGPow' $ scalarPow' LP.one)+-- It's necessary to call 'fromJust' here: otherwise +-- sequencing functions in 'crtFuncs' relies on 'divGPow' having an+-- implementation in C, which is not true for all types which have a C+-- implementation of, e.g. 'crt'. In particular, 'Complex Double' has C support+-- for 'crt', but not for 'divGPow'.+-- This really breaks the contract of Tensor, so it's probably a bad idea.+--   Someone can get the "crt" and can even pull the function "divGCRT" from Tensor,+--   but it will fail when they try to apply it.+-- As an implementation note if I ever do fix this: the division by rad(m) can be+-- tricky for Double/Complex Doubles, so be careful! This is why we have a custom+-- Complex wrapper around NP.Complex.+gInvCoeffsCRT = ($ fromJust $ divGPow' $ scalarPow' LP.one) <$> ctCRT++-- we can't put this in Extension with the rest of the twace/embed fucntions because it needs access to +-- the C backend+twaceCRT' :: forall m m' r .+             (TElt CT r, CRTrans r, m `Divides` m', ZeroTestable r, IntegralDomain r)+             => TaggedT '(m, m') Maybe (Vector r -> Vector r)+twaceCRT' = tagT $ do -- Maybe monad+  (CT' g') <- proxyT gCoeffsCRT (Proxy::Proxy m')+  (CT' gInv) <- proxyT gInvCoeffsCRT (Proxy::Proxy m)+  embed <- proxyT embedCRT' (Proxy::Proxy '(m,m'))+  indices <- pure $ proxy extIndicesCRT (Proxy::Proxy '(m,m'))+  (_, m'hatinv) <- proxyT crtInfoFact (Proxy::Proxy m')+  let phi = proxy totientFact (Proxy::Proxy m)+      phi' = proxy totientFact (Proxy::Proxy m')+      mhat = fromIntegral $ proxy valueHatFact (Proxy::Proxy m)+      hatRatioInv = m'hatinv * mhat+      reltot = phi' `div` phi+      -- tweak = mhat * g' / (m'hat * g)+      tweak = SV.map (* hatRatioInv) $ SV.zipWith (*) (embed gInv) g'+  return $ \ arr -> -- take true trace after mul-by-tweak+    let v = backpermute' indices (SV.zipWith (*) tweak arr)+    in generate phi $ \i -> foldl1' (+) $ SV.unsafeSlice (i*reltot) reltot v
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/Backend.hs view
@@ -0,0 +1,304 @@+{-# LANGUAGE ConstraintKinds, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, +             PolyKinds, ScopedTypeVariables, TypeFamilies, UndecidableInstances #-}++module Crypto.Lol.Cyclotomic.Tensor.CTensor.Backend+(Dispatch+,dcrt+,dcrtinv+,dgaussdec+,dl+,dlinv+,dnorm+,dmulgpow+,dmulgdec+,dginvpow+,dginvdec+,dadd+,dmul+,marshalFactors+,CPP+,withArray+,withPtrArray+) where++import Control.Applicative+import Control.Monad++import Crypto.Lol.LatticePrelude as LP (Complex, Proxy(..), proxy, (++), map, mapM_, PP, Tagged, tag)+import Crypto.Lol.Reflects+import Crypto.Lol.Types.ZqBasic++import Data.Int+import Data.Vector.Storable          as SV (Vector, (!), replicate, replicateM, thaw, convert, foldl',+                                            unsafeToForeignPtr0, unsafeSlice, mapM, fromList,+                                            generate, foldl1',+                                            unsafeWith, zipWith, map, length, unsafeFreeze, thaw)+import Data.Vector.Storable.Internal (getPtr)++import           Foreign.ForeignPtr (touchForeignPtr)+import           Foreign.Marshal.Array (withArray)+import           Foreign.Marshal.Utils (with)+import           Foreign.Ptr (plusPtr, castPtr, Ptr)+import           Foreign.Storable        (Storable (..))+import qualified Foreign.Storable.Record as Store++marshalFactors :: [PP] -> Vector CPP+marshalFactors = SV.fromList . LP.map (\(p,e) -> CPP (fromIntegral p) (fromIntegral e))++-- http://stackoverflow.com/questions/6517387/vector-vector-foo-ptr-ptr-foo-io-a-io-a+withPtrArray :: (Storable a) => [Vector a] -> (Ptr (Ptr a) -> IO b) -> IO b+withPtrArray v f = do+  let vs = LP.map SV.unsafeToForeignPtr0 v+      ptrV = LP.map (\(fp,_) -> getPtr fp) vs+  res <- withArray ptrV f+  LP.mapM_ (\(fp,_) -> touchForeignPtr fp) vs+  return res++data CPP = CPP {p' :: !Int32, e' :: !Int16}+-- stolen from http://hackage.haskell.org/packages/archive/numeric-prelude/0.4.0.3/doc/html/src/Number-Complex.html#T+-- the NumericPrelude Storable instance for complex numbers+instance Storable CPP where+   sizeOf    = Store.sizeOf store+   alignment = Store.alignment store+   peek      = Store.peek store+   poke      = Store.poke store++store :: Store.Dictionary CPP+store = Store.run $+   liftA2 CPP+      (Store.element p')+      (Store.element e')++instance Show CPP where+    show (CPP p e) = "(" LP.++ show p LP.++ "," LP.++ show e LP.++ ")"++instance (Storable a, Storable b,+          CTypeOf a ~ CTypeOf b) +  -- enforces right associativity and that each type of +  -- the tuple has the same C repr, so using an array repr is safe+  => Storable (a,b) where+  sizeOf _ = (sizeOf (undefined :: a)) + (sizeOf (undefined :: b))+  alignment _ = max (alignment (undefined :: a)) (alignment (undefined :: b))+  peek p = do+    a <- peek (castPtr p :: Ptr a)+    b <- peek (castPtr (plusPtr p (sizeOf a)) :: Ptr b)+    return (a,b)+  poke p (a,b) = do+    poke (castPtr p :: Ptr a) a+    poke (castPtr (plusPtr p (sizeOf a)) :: Ptr b) b++++++data ZqB64D -- for type safety purposes+data ComplexD+data DoubleD+data Int64D++type family CTypeOf x where+  CTypeOf (a,b) = CTypeOf a+  CTypeOf (ZqBasic (q :: k) Int64) = ZqB64D+  CTypeOf Double = DoubleD+  CTypeOf Int64 = Int64D+  CTypeOf (Complex Double) = ComplexD++-- returns the modulus as a nested list of moduli+class (Tuple a) => ZqTuple a where+  type ModPairs a+  getModuli :: Tagged a (ModPairs a)++instance (Reflects q Int64) => ZqTuple (ZqBasic q Int64) where+  type ModPairs (ZqBasic q Int64) = Int64+  getModuli = tag $ proxy value (Proxy::Proxy q)++instance (ZqTuple a, ZqTuple b) => ZqTuple (a, b) where+  type ModPairs (a,b) = (ModPairs a, ModPairs b)+  getModuli = +    let as = proxy getModuli (Proxy::Proxy a)+        bs = proxy getModuli (Proxy :: Proxy b)+    in tag (as,bs)++-- counts components in a nested tuple+class Tuple a where+  numComponents :: Tagged a Int16++instance {-# Overlappable #-} Tuple a where+  numComponents = tag 1++instance (Tuple a, Tuple b) => Tuple (a,b) where+  numComponents = tag $ (proxy numComponents (Proxy::Proxy a)) + (proxy numComponents (Proxy::Proxy b))++type Dispatch r = (Dispatch' (CTypeOf r) r)++-- | Class to safely match Haskell types with the appropriate C function.+class (repr ~ CTypeOf r) => Dispatch' repr r where+  dcrt      :: Ptr (Ptr r) ->           Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dcrtinv   :: Ptr (Ptr r) -> Ptr r ->  Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dgaussdec :: Ptr (Ptr (Complex r)) -> Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()++  dl        :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dlinv     :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dnorm     :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dmulgpow  :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dmulgdec  :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dginvpow  :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  dginvdec  :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()+  +  dadd :: Ptr r -> Ptr r -> Int64 -> IO ()+  dmul :: Ptr r -> Ptr r -> Int64 -> IO ()++instance (ZqTuple r, Storable (ModPairs r),+          CTypeOf r ~ ZqB64D)+  => Dispatch' ZqB64D r where+  dcrt ruptr pout totm pfac numFacts = +    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorCRTRq numPairs (castPtr pout) totm pfac numFacts (castPtr ruptr) (castPtr qsptr)+  dcrtinv ruptr minv pout totm pfac numFacts =+    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorCRTInvRq numPairs (castPtr pout) totm pfac numFacts (castPtr ruptr) (castPtr minv) (castPtr qsptr)+  dl pout totm pfac numFacts = +    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorLRq numPairs (castPtr pout) totm pfac numFacts (castPtr qsptr)+  dlinv pout totm pfac numFacts = +    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorLInvRq numPairs (castPtr pout) totm pfac numFacts (castPtr qsptr)+  dnorm = error "cannot call CT normSq on type ZqBasic"+  dmulgpow pout totm pfac numFacts =+    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorGPowRq numPairs (castPtr pout) totm pfac numFacts (castPtr qsptr)+  dmulgdec pout totm pfac numFacts =+    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorGDecRq numPairs (castPtr pout) totm pfac numFacts (castPtr qsptr)+  dginvpow pout totm pfac numFacts =+    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorGInvPowRq numPairs (castPtr pout) totm pfac numFacts (castPtr qsptr)+  dginvdec pout totm pfac numFacts =+    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        tensorGInvDecRq numPairs (castPtr pout) totm pfac numFacts (castPtr qsptr)+  dadd aout bout totm = +    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        addRq numPairs (castPtr aout) (castPtr bout) totm (castPtr qsptr)+  dmul aout bout totm = +    let qs = proxy getModuli (Proxy::Proxy r)+        numPairs = proxy numComponents (Proxy::Proxy r)+    in with qs $ \qsptr ->+        mulRq numPairs (castPtr aout) (castPtr bout) totm (castPtr qsptr)+  dgaussdec = error "cannot call CT gaussianDec on type ZqBasic"++instance (Tuple r, CTypeOf r ~ ComplexD) => Dispatch' ComplexD r where+  dcrt ruptr pout totm pfac numFacts = +    tensorCRTC (proxy numComponents (Proxy::Proxy r)) (castPtr pout) totm pfac numFacts (castPtr ruptr)+  dcrtinv ruptr minv pout totm pfac numFacts = +    tensorCRTInvC (proxy numComponents (Proxy::Proxy r)) (castPtr pout) totm pfac numFacts (castPtr ruptr) (castPtr minv)+  dl pout = +    tensorLC (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dlinv pout = +    tensorLInvC (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dnorm = error "cannot call CT normSq on type Complex Double"+  dmulgpow pout = +    tensorGPowC (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dmulgdec = error "cannot call CT mulGDec on type Complex Double"+  dginvpow pout = +    tensorGInvPowC (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dginvdec = error "cannot call CT divGDec on type Complex Double"+  dadd aout bout = +    addC (proxy numComponents (Proxy::Proxy r)) (castPtr aout) (castPtr bout)+  dmul aout bout = +    mulC (proxy numComponents (Proxy::Proxy r)) (castPtr aout) (castPtr bout)+  dgaussdec = error "cannot call CT gaussianDec on type Comple Double"++instance (Tuple r, CTypeOf r ~ DoubleD) => Dispatch' DoubleD r where+  dcrt = error "cannot call CT Crt on type Double"+  dcrtinv = error "cannot call CT CrtInv on type Double"+  dl pout = +    tensorLDouble (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dlinv pout = +    tensorLInvDouble (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dnorm = error "cannot call CT normSq on type Double"+  dmulgpow = error "cannot call CT mulGPow on type Double"+  dmulgdec = error "cannot call CT mulGDec on type Double"+  dginvpow = error "cannot call CT divGPow on type Double"+  dginvdec = error "cannot call CT divGDec on type Double"+  dadd aout bout = +    addD (proxy numComponents (Proxy::Proxy r)) (castPtr aout) (castPtr bout)+  dmul = error "cannot call CT (*) on type Double"+  dgaussdec ruptr pout totm pfac numFacts = +    tensorGaussianDec (proxy numComponents (Proxy::Proxy r)) (castPtr pout) totm pfac numFacts (castPtr ruptr)++instance (Tuple r, CTypeOf r ~ Int64D) => Dispatch' Int64D r where+  dcrt = error "cannot call CT Crt on type Int64"+  dcrtinv = error "cannot call CT CrtInv on type Int64"+  dl pout = +    tensorLR (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dlinv pout = +    tensorLInvR (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dnorm pout = +    tensorNormSqR (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dmulgpow pout = +    tensorGPowR (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dmulgdec pout = +    tensorGDecR (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dginvpow pout = +    tensorGInvPowR (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dginvdec pout = +    tensorGInvDecR (proxy numComponents (Proxy::Proxy r)) (castPtr pout)+  dadd aout bout = +    addR (proxy numComponents (Proxy::Proxy r)) (castPtr aout) (castPtr bout)+  dmul = error "cannot call CT (*) on type Int64"+  dgaussdec = error "cannot call CT gaussianDec on type Int64"++foreign import ccall unsafe "tensorLR" tensorLR ::                  Int16 -> Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorLInvR" tensorLInvR ::            Int16 -> Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorLRq" tensorLRq ::                Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr Int64 -> IO ()+foreign import ccall unsafe "tensorLInvRq" tensorLInvRq ::          Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr Int64 -> IO ()+foreign import ccall unsafe "tensorLDouble" tensorLDouble ::       Int16 -> Ptr Double -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorLInvDouble" tensorLInvDouble :: Int16 -> Ptr Double -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorLC" tensorLC ::       Int16 -> Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorLInvC" tensorLInvC :: Int16 -> Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16          -> IO ()++foreign import ccall unsafe "tensorNormSqR" tensorNormSqR ::     Int16 -> Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()++foreign import ccall unsafe "tensorGPowR" tensorGPowR ::         Int16 -> Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorGPowRq" tensorGPowRq ::       Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr Int64 -> IO ()+foreign import ccall unsafe "tensorGPowC" tensorGPowC ::         Int16 -> Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorGDecR" tensorGDecR ::         Int16 -> Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorGDecRq" tensorGDecRq ::       Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr Int64 -> IO ()+foreign import ccall unsafe "tensorGInvPowR" tensorGInvPowR ::   Int16 -> Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorGInvPowRq" tensorGInvPowRq :: Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr Int64 -> IO ()+foreign import ccall unsafe "tensorGInvPowC" tensorGInvPowC ::   Int16 -> Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorGInvDecR" tensorGInvDecR ::   Int16 -> Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()+foreign import ccall unsafe "tensorGInvDecRq" tensorGInvDecRq :: Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr Int64 -> IO ()++foreign import ccall unsafe "tensorCRTRq" tensorCRTRq ::         Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (ZqBasic q Int64)) -> Ptr Int64 -> IO ()+foreign import ccall unsafe "tensorCRTC" tensorCRTC ::           Int16 -> Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) -> IO ()+foreign import ccall unsafe "tensorCRTInvRq" tensorCRTInvRq ::   Int16 -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (ZqBasic q Int64)) -> Ptr (ZqBasic q Int64) -> Ptr Int64 -> IO ()+foreign import ccall unsafe "tensorCRTInvC" tensorCRTInvC ::     Int16 -> Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) -> Ptr (Complex Double) -> IO ()++foreign import ccall unsafe "tensorGaussianDec" tensorGaussianDec :: Int16 -> Ptr Double -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) ->  IO ()++foreign import ccall unsafe "mulRq" mulRq :: Int16 -> Ptr (ZqBasic q Int64) -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr Int64 -> IO ()+foreign import ccall unsafe "mulC" mulC :: Int16 -> Ptr (Complex Double) -> Ptr (Complex Double) -> Int64 -> IO ()++foreign import ccall unsafe "addRq" addRq :: Int16 -> Ptr (ZqBasic q Int64) -> Ptr (ZqBasic q Int64) -> Int64 -> Ptr Int64 -> IO ()+foreign import ccall unsafe "addR" addR :: Int16 -> Ptr Int64 -> Ptr Int64 -> Int64 -> IO ()+foreign import ccall unsafe "addC" addC :: Int16 -> Ptr (Complex Double) -> Ptr (Complex Double) -> Int64 -> IO ()+foreign import ccall unsafe "addD" addD :: Int16 -> Ptr Double -> Ptr Double -> Int64 -> IO ()
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/Extension.hs view
@@ -0,0 +1,121 @@+{-# 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 <a,b,c,d> <0,3,2,3,1,0> = <a,d,c,d,b,a>+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
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/basic.c view
@@ -0,0 +1,175 @@+#include "tensorTypes.h"+#ifdef CINTRIN+#include <immintrin.h>+#endif++#ifdef STATS+int mulCtr = 0;+struct timespec mulTime = {0,0};++int addCtr = 0;+struct timespec addTime = {0,0};+#endif++//a = zipWith (*) a b+void mulRq (hShort_t tupSize, hInt_t* a, hInt_t* b, hDim_t totm, hInt_t* qs) {+#ifdef STATS+    mulCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+        hInt_t q = qs[tupIdx];+        for(int i = 0; i < totm; i++) {+            a[i*tupSize+tupIdx] = (a[i*tupSize+tupIdx]*b[i*tupSize+tupIdx])%q;+        }+    }+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    mulTime = tsAdd(mulTime, tsSubtract(t1,s1));+#endif+}+/*+void mulMq (hShort_t tupSize, hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q) {+#ifdef STATS+    mulCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+    hInt_t mask = (1<<logr)-1; // R-1++    for(int i = 0; i < totm; i++) {+        hInt_t x = a[i]*b[i];+        hInt_t s = k*(x & mask);+        hInt_t m = s & mask;+        a[i] = (x+m*q)>>logr;+    }++#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    mulTime = tsAdd(mulTime, tsSubtract(t1,s1));+#endif+}+*/+void mulC (hShort_t tupSize, complex_t* a, complex_t* b, hDim_t totm) {+#ifdef STATS+    mulCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+    for(int i = 0; i < totm*tupSize; i++)+    {+        CMPLX_IMUL(a[i],b[i]);+    }+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    mulTime = tsAdd(mulTime, tsSubtract(t1,s1));+#endif+}++//a = zipWith (+) a b+void addRq (hShort_t tupSize, hInt_t* a, const hInt_t* b, const hDim_t totm, const hInt_t* qs) {+#ifdef STATS+    addCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+/*+need to check this code more carefully when tupSize > 1+#ifdef CINTRIN++    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+        hInt_t q = qs[tupIdx];+        __m128i qss = _mm_set1_epi64x(q);+        for(int i = 0; i < totm; i+=2) {+            __m128i xs = _mm_load_si128((const __m128i*)(a+(i*tupSize+tupIdx)));+            __m128i ys = _mm_load_si128((const __m128i*)(b+(i*tupSize+tupIdx)));+            __m128i zs = _mm_add_epi64(xs,ys);+            zs = _mm_rem_epi64(zs,qss);+            _mm_store_si128((__m128i*)(a+(i*tupSize+tupIdx)),zs);+        }+    }+#else+*/+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+        hInt_t q = qs[tupIdx];+        for(int i = 0; i < totm; i++) {+            hInt_t temp = a[i*tupSize+tupIdx]+b[i*tupSize+tupIdx];+            if (temp >= q) a[i*tupSize+tupIdx]=temp-q;+            else a[i*tupSize+tupIdx] = temp;+        }+    }+//#endif+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    addTime = tsAdd(addTime, tsSubtract(t1,s1));+#endif+}+/*+void addMq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q) {+#ifdef STATS+    addCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+    hInt_t twoq = q<<1;+    for(int i = 0; i < totm; i++) {+        hInt_t temp = (a[i]+b[i]);+        if (temp >= twoq) a[i]=temp-twoq;+        else a[i] = temp;+    }++#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    addTime = tsAdd(addTime, tsSubtract(t1,s1));+#endif+}+*/+//a = zipWith (+) a b+void addR (hShort_t tupSize, hInt_t* a, hInt_t* b, hDim_t totm) {+#ifdef STATS+    addCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+    for(int i = 0; i < totm*tupSize; i++)    {+        a[i] += b[i];+    }+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    addTime = tsAdd(addTime, tsSubtract(t1,s1));+#endif+}++void addC (hShort_t tupSize, complex_t* a, complex_t* b, hDim_t totm) {+#ifdef STATS+    addCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+    for(int i = 0; i < totm*tupSize; i++)+    {+        CMPLX_IADD(a[i],b[i]);+    }+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    addTime = tsAdd(addTime, tsSubtract(t1,s1));+#endif+}++void addD (hShort_t tupSize, double* a, double* b, hDim_t totm) {+#ifdef STATS+    addCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+    for(int i = 0; i < totm*tupSize; i++)+    {+        a[i]+=b[i];+    }+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    addTime = tsAdd(addTime, tsSubtract(t1,s1));+#endif+}+
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/crt.c view
@@ -0,0 +1,1386 @@+#include "tensorTypes.h"+#include <time.h>+#include <stdlib.h>++// there should be a special cases that do NOT require temp space to be allocated for all primes *smaller* than DFTP_GENERIC_SIZE+#define DFTP_GENERIC_SIZE 11++#ifdef STATS+int crtRqCtr = 0;+int crtInvRqCtr = 0;+int crtCCtr = 0;+int crtInvCCtr = 0;++struct timespec crttime1 = {0,0};+struct timespec crttime2 = {0,0};+struct timespec crttime3 = {0,0};+struct timespec crttime4 = {0,0};++struct timespec crtInvRqTime = {0,0};+struct timespec crtCTime = {0,0};+struct timespec crtInvCTime = {0,0};+#endif++hDim_t bitrev (PrimeExponent pe, hDim_t j) {+    hShort_t e;+    hDim_t p = pe.prime;+    hDim_t tempj = j;+    hDim_t acc = 0;++    for(e = pe.exponent-1; e >= 0; e--) {+        div_t qr = div(tempj,p);+        acc += qr.rem * ipow(p,e);+        tempj = qr.quot;+    }+    return acc;+}++void crtTwiddleRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +                   PrimeExponent pe, hInt_t* ru, hInt_t q)+{+    hDim_t p = pe.prime;+    hShort_t e = pe.exponent;+    +#ifdef DEBUG_MODE+    ASSERT(e != 0);+#endif+    pe.exponent -= 1; // used for an argument to bitrev+    +    if(p == 2)+    {+        hDim_t mprime = 1<<(e-1);+        hDim_t blockDim = rts*mprime; // size of block in block diagonal tensor matrix++        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0+        {+            hDim_t temp2 = i0*rts;+            hInt_t twid = ru[bitrev(pe, i0)*tupSize];++            for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)+            {+                hDim_t temp3 = blockIdx*blockDim + temp2;+                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                {+                    hDim_t idx = (temp3 + modOffset)*tupSize;+                    y[idx] = (y[idx]*twid) % q;+                }+            }+        }+    }+    else // This loop is faster, probably due to the division in the loop above.+    // cilk also slows it down+    {+        hDim_t mprime = ipow(p,e-1);+        hDim_t blockDim = rts*(p-1)*mprime; // size of block in block diagonal tensor matrix+        +        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0+        {+            hDim_t temp1 = i0*(p-1);+            for(hDim_t i1 = 0; i1 < (p-1); i1++) // loops over i%(p-1) for i = 0..(m'-1)+            {        +                hDim_t temp2 = (temp1+i1)*rts;+                hInt_t twid = ru[bitrev(pe, i0)*(i1+1)*tupSize];++                for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)+                {+                    hDim_t temp3 = blockIdx*blockDim + temp2;+                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                    {+                        hDim_t idx = (temp3 + modOffset)*tupSize;+                        y[idx] = (y[idx]*twid) % q;+                    }+                }+            }+        }+    }+}++// dim is power of p+void dftptwidRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +                 PrimeExponent pe, hDim_t dim, hDim_t rustride, hInt_t* ru, hInt_t q)+{+    hDim_t idx;+    hDim_t p = pe.prime;++    pe.exponent -= 1; // used for an argument to bitrev++    if(p == 2) {+        hDim_t mprime = dim>>1; // divides evenly+        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset+        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0+        {+            hDim_t temp3 = rts*(i0*p+1);+            hInt_t twid = ru[bitrev(pe,i0)*rustride*tupSize];++            for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+            {+                hDim_t temp2 = blockOffset*temp1 + temp3;+                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                {+                    idx = (temp2 + modOffset)*tupSize;+                    y[idx] = (y[idx]*twid) % q;+                }+            }+        }+    }+    else+    {+        hDim_t mprime = dim/p; // divides evenly+        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset+        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0+        {+            for(hDim_t i1 = 1; i1 < p; i1++) // loops over i%p for i = 0..(dim-1), but we skip i1=0+            {+                hDim_t temp3 = rts*(i0*p+i1);+                hInt_t twid = ru[bitrev(pe,i0)*i1*rustride*tupSize];++                for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+                {+                    hDim_t temp2 = blockOffset*temp1 + temp3;+                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                    {+                        idx = (temp2 + modOffset)*tupSize;+                        y[idx] = (y[idx]*twid) % q;+                    }+                }+            }+        }+    }+}++//implied length of ru is rustride*p+//implied length of tempSpace is p, if p is not a special case+// temp is allowed to be NULL if p < DFTP_GENERIC_SIZE+void dftpRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +             hDim_t p, hDim_t rustride, hInt_t* ru, hInt_t* tempSpace, hInt_t q)+{+    hDim_t tensorOffset;++    if(p == 2)+    {+        hDim_t temp1 = rts<<1;++        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hInt_t u = y[tensorOffset*tupSize];+                hInt_t t = y[(tensorOffset+rts)*tupSize];+                y[tensorOffset*tupSize] = (u + t) % q;+                y[(tensorOffset+rts)*tupSize] = (u - t) % q;+            }+        }+    }+    else if(p == 3)+    {+        hInt_t ru1 = ru[rustride*tupSize];+        hInt_t ru2 = ru[(rustride<<1)*tupSize];+        hDim_t temp1 = rts*3;++        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hInt_t y1, y2, y3;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                //q is <32 bits, so we can do 3 additions without overflow+                y[tensorOffset*tupSize]          = (y1 + y2 + y3) % q;+                y[(tensorOffset+rts)*tupSize]      = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q)) % q;+                y[(tensorOffset+(rts<<1))*tupSize] = (y1 + ((ru2*y2) % q) + ((ru1*y3) % q)) % q;+            }   +        }++    }+    else if(p == 5)+    {+        hDim_t temp1 = rts*5;+        hInt_t ru1 = ru[rustride*tupSize];+        hInt_t ru2 = ru[(rustride<<1)*tupSize];+        hInt_t ru3 = ru[(rustride*3)*tupSize];+        hInt_t ru4 = ru[(rustride<<2)*tupSize];++        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hInt_t y1, y2, y3, y4, y5;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];+                y5 = y[(tensorOffset+(rts<<2))*tupSize];+                y[tensorOffset*tupSize]          = (y1 + y2 + y3 + y4 + y5) % q;+                y[(tensorOffset+rts)*tupSize]      = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q) + ((ru4*y5) % q)) % q;+                y[(tensorOffset+(rts<<1))*tupSize] = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru1*y4) % q) + ((ru3*y5) % q)) % q;+                y[(tensorOffset+rts*3)*tupSize]    = (y1 + ((ru3*y2) % q) + ((ru1*y3) % q) + ((ru4*y4) % q) + ((ru2*y5) % q)) % q;+                y[(tensorOffset+(rts<<2))*tupSize] = (y1 + ((ru4*y2) % q) + ((ru3*y3) % q) + ((ru2*y4) % q) + ((ru1*y5) % q)) % q;+            }+        }+    }+    else if(p == 7)+    {+        hDim_t temp1 = rts*7;+        hInt_t ru1 = ru[rustride*tupSize];+        hInt_t ru2 = ru[(rustride<<1)*tupSize];+        hInt_t ru3 = ru[(rustride*3)*tupSize];+        hInt_t ru4 = ru[(rustride<<2)*tupSize];+        hInt_t ru5 = ru[(rustride*5)*tupSize];+        hInt_t ru6 = ru[(rustride*6)*tupSize];++        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hInt_t y1, y2, y3, y4, y5, y6, y7;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];+                y5 = y[(tensorOffset+(rts<<2))*tupSize];+                y6 = y[(tensorOffset+rts*5)*tupSize];+                y7 = y[(tensorOffset+rts*6)*tupSize];+                y[tensorOffset*tupSize]          = (y1 +     y2 +     y3 +     y4 +     y5 +     y6 +     y7) % q;+                y[(tensorOffset+rts)*tupSize]      = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q) + ((ru4*y5) % q) + ((ru5*y6) % q) + ((ru6*y7) % q)) % q;+                y[(tensorOffset+(rts<<1))*tupSize] = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru6*y4) % q) + ((ru1*y5) % q) + ((ru3*y6) % q) + ((ru5*y7) % q)) % q;+                y[(tensorOffset+rts*3)*tupSize]    = (y1 + ((ru3*y2) % q) + ((ru6*y3) % q) + ((ru2*y4) % q) + ((ru5*y5) % q) + ((ru1*y6) % q) + ((ru4*y7) % q)) % q;+                y[(tensorOffset+(rts<<2))*tupSize] = (y1 + ((ru4*y2) % q) + ((ru1*y3) % q) + ((ru5*y4) % q) + ((ru2*y5) % q) + ((ru6*y6) % q) + ((ru3*y7) % q)) % q;+                y[(tensorOffset+rts*5)*tupSize]    = (y1 + ((ru5*y2) % q) + ((ru3*y3) % q) + ((ru1*y4) % q) + ((ru6*y5) % q) + ((ru4*y6) % q) + ((ru2*y7) % q)) % q;+                y[(tensorOffset+rts*6)*tupSize]    = (y1 + ((ru6*y2) % q) + ((ru5*y3) % q) + ((ru4*y4) % q) + ((ru3*y5) % q) + ((ru2*y6) % q) + ((ru1*y7) % q)) % q;+            }   +        }+    }+    else+    {+        hDim_t temp1 = rts*p;+        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;                +                for(hDim_t row = 0; row < p; row++)+                {+                    hInt_t acc = 0;+                    //p is small (<< 30 bits), so we can do p additions of mod-q values without overflow+                    for(hDim_t col = 0; col < p; col++)+                    {+                        acc += ((y[(tensorOffset+col*rts)*tupSize]*ru[((col*row) % p)*rustride*tupSize])%q);+                    }+                    tempSpace[row] = acc % q;+                }+                +                for(hDim_t row = 0; row < p; row++)+                {+                    y[(tensorOffset+rts*row)*tupSize] = tempSpace[row];+                }+            }+        }+    }+}++void crtpRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +             hDim_t p, hDim_t rustride, hInt_t* ru, hInt_t q)+{+    hDim_t tensorOffset;+    if(p == 2)+    {+        return;+    }+    else if(p == 3)+    {+        hDim_t temp1 = rts*2;+        hInt_t ru1 = ru[rustride*tupSize];+        hInt_t ru2 = ru[(rustride<<1)*tupSize];++        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hInt_t y1, y2;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y[tensorOffset*tupSize]     = (y1 + ((ru1*y2)%q)) % q;+                y[(tensorOffset+rts)*tupSize] = (y1 + ((ru2*y2)%q)) % q;+            }   +        }+    }+    else if(p == 5)+    {+        hDim_t temp1 = rts*4;+        hInt_t ru1 = ru[rustride*tupSize];+        hInt_t ru2 = ru[(rustride<<1)*tupSize];+        hInt_t ru3 = ru[(rustride*3)*tupSize];+        hInt_t ru4 = ru[(rustride<<2)*tupSize];++        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hInt_t y1, y2, y3, y4;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];++                y[tensorOffset*tupSize]          = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q)) % q;+                y[(tensorOffset+rts)*tupSize]      = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru1*y4) % q)) % q;+                y[(tensorOffset+(rts<<1))*tupSize] = (y1 + ((ru3*y2) % q) + ((ru1*y3) % q) + ((ru4*y4) % q)) % q;+                y[(tensorOffset+rts*3)*tupSize]    = (y1 + ((ru4*y2) % q) + ((ru3*y3) % q) + ((ru2*y4) % q)) % q;+            }   +        }+    }+    else if(p == 7)+    {+        hDim_t temp1 = rts*6;+        hInt_t ru1 = ru[rustride*tupSize];+        hInt_t ru2 = ru[(rustride<<1)*tupSize];+        hInt_t ru3 = ru[(rustride*3)*tupSize];+        hInt_t ru4 = ru[(rustride<<2)*tupSize];+        hInt_t ru5 = ru[(rustride*5)*tupSize];+        hInt_t ru6 = ru[(rustride*6)*tupSize];+        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hInt_t y1, y2, y3, y4, y5, y6;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];+                y5 = y[(tensorOffset+(rts<<2))*tupSize];+                y6 = y[(tensorOffset+rts*5)*tupSize];+                y[tensorOffset*tupSize]          = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q) + ((ru4*y5) % q) + ((ru5*y6) % q)) % q;+                y[(tensorOffset+rts)*tupSize]      = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru6*y4) % q) + ((ru1*y5) % q) + ((ru3*y6) % q)) % q;+                y[(tensorOffset+(rts<<1))*tupSize] = (y1 + ((ru3*y2) % q) + ((ru6*y3) % q) + ((ru2*y4) % q) + ((ru5*y5) % q) + ((ru1*y6) % q)) % q;+                y[(tensorOffset+rts*3)*tupSize]    = (y1 + ((ru4*y2) % q) + ((ru1*y3) % q) + ((ru5*y4) % q) + ((ru2*y5) % q) + ((ru6*y6) % q)) % q;+                y[(tensorOffset+(rts<<2))*tupSize] = (y1 + ((ru5*y2) % q) + ((ru3*y3) % q) + ((ru1*y4) % q) + ((ru6*y5) % q) + ((ru4*y6) % q)) % q;+                y[(tensorOffset+rts*5)*tupSize]    = (y1 + ((ru6*y2) % q) + ((ru5*y3) % q) + ((ru4*y4) % q) + ((ru3*y5) % q) + ((ru2*y6) % q)) % q;+            }+        }+    }+    else+    {+        hInt_t* tempSpace = (hInt_t*)malloc((p-1)*sizeof(hInt_t));+        hDim_t temp1 = rts*(p-1);+        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                +                for(hDim_t row = 1; row < p; row++)+                {+                    hInt_t acc = 0;+                    for(hDim_t col = 0; col < p-1; col++)+                    {+                        acc += ((y[(tensorOffset+col*rts)*tupSize]*ru[((col*row) % p)*rustride*tupSize]) % q);+                    }+                    tempSpace[row-1] = acc % q;+                }+                +                for(hDim_t row = 0; row < p-1; row++)+                {+                    y[(tensorOffset+rts*row)*tupSize] = tempSpace[row];+                }+            }+        }+        free(tempSpace);+    }+}++//takes inverse rus+void crtpinvRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +                hDim_t p, hDim_t rustride, hInt_t* ruinv, hInt_t q)+{+    if(p ==2)+    {+        // need this case so that we can divide overall by mhat^(-1)+        return;+    }+    else+    {+        hDim_t tensorOffset,i;+        hInt_t* tempSpace = (hInt_t*)malloc((p-1)*sizeof(hInt_t));+        hDim_t temp1 = rts*(p-1);+        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                +                for(i = 0; i < p-1; i++)+                {+                    hInt_t sum = 0;+                    int j;+                    for(j = 0; j < p-1; j++)+                    {+                        int ruIdx = ((j+1)*i) % p;+                        sum += ((y[(tensorOffset+j*rts)*tupSize] * ruinv[ruIdx*rustride*tupSize]) % q);+                    }+                    tempSpace[i] = sum % q;+                }++                hInt_t shift = 0;+                for(i = 0; i < p-1; i++)+                {+                    // we were given the inverse rus, so we need to negate the indices+                    shift += ((y[(tensorOffset+i*rts)*tupSize] * ruinv[rustride*(p-(i+1))*tupSize]) % q);+                }++                for(i = 0; i < p-1; i++)+                {+                    y[(tensorOffset+i*rts)*tupSize] = (tempSpace[i] - shift) % q; +                }+            }+        }+    }+}++void ppDFTRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +              PrimeExponent pe, hDim_t rustride, hInt_t* ru, hInt_t q, hInt_t* temp)+{+    hDim_t p = pe.prime;+    hShort_t e = pe.exponent;+    +    if(e == 0)+    {+        return;+    }+    +    hDim_t primeRuStride = rustride*ipow(p,e-1);+    +    hShort_t i;+    +    hDim_t ltsScale = ipow(p,e-1);+    hDim_t rtsScale = 1;+    hDim_t twidRuStride = rustride;+    for(i = 0; i < e; i++)+    {+        hDim_t rtsDim = rts*rtsScale;+        dftpRq (y, tupSize, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp, q);+        dftptwidRq (y, tupSize, lts, rtsDim, pe, ltsScale*p, twidRuStride, ru, q);+        +        ltsScale /= p;+        rtsScale *= p;+        twidRuStride *= p;+        pe.exponent -= 1;+    }+}++void ppDFTInvRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +                 PrimeExponent pe, hDim_t rustride, hInt_t* ru, hInt_t q, hInt_t* temp)+{+    hDim_t p = pe.prime;+    hShort_t e = pe.exponent;+    +    if(e == 0)+    {+        return;+    }+    hDim_t primeRuStride = rustride*ipow(p,e-1);++    hShort_t i;+    +    hDim_t ltsScale = 1;+    hDim_t rtsScale = ipow(p,e-1);+    hDim_t twidRuStride = primeRuStride;+    pe.exponent = 1;+    for(i = 0; i < e; i++)+    {+        hDim_t rtsDim = rts*rtsScale;+        hDim_t ltsScaleP = ltsScale*p;+        dftptwidRq (y, tupSize, lts, rtsDim, pe, ltsScaleP, twidRuStride, ru, q);+        dftpRq (y, tupSize, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp, q);+        +        ltsScale = ltsScaleP;+        rtsScale /= p;+        twidRuStride /= p;+        pe.exponent += 1;+    }+}++void ppcrtRq (void* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +              PrimeExponent pe, void* ru, hInt_t* qs)+{+    hDim_t p = pe.prime;+    hDim_t e = pe.exponent;+#ifdef DEBUG_MODE+    ASSERT(e != 0);+#endif+    hDim_t mprime = ipow(p,e-1);+    +#ifdef DEBUG_MODE+    printf("lts is %" PRId32 "\trts is %" PRId32 "\n", lts, rts);+    printf("rus for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);+    hDim_t i;+    for(i = 0; i < ipow(p,e); i++) {+        printf("%" PRId64 ",", ((hInt_t*)ru)[i*tupSize+tupIdx]);+    }+    printf("]\n");+#endif++    hInt_t* temp = 0;+    if(p >= DFTP_GENERIC_SIZE)+    {+        temp = (hInt_t*)malloc(p*sizeof(hInt_t));+    }+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+        hInt_t* z = ((hInt_t*)y)+tupIdx;+        hInt_t q = qs[tupIdx];+        hInt_t* ruOffset = ((hInt_t*)ru)+tupIdx;+        crtpRq (z, tupSize, lts*mprime, rts, p, mprime, ruOffset, q);+        crtTwiddleRq (z, tupSize, lts, rts, pe, ruOffset, q);+        pe.exponent -= 1;+        ppDFTRq (z,  tupSize, lts, rts*(p-1), pe, p, ruOffset, q, temp);+        pe.exponent += 1;+    }++    if(p >= DFTP_GENERIC_SIZE)+    {+        free(temp);+    }+}++void ppcrtinvRq (void* y, hShort_t tupSize, hDim_t lts, hDim_t rts, +                 PrimeExponent pe, void* ru, hInt_t* qs)+{+    hDim_t p = pe.prime;+    hDim_t e = pe.exponent;+#ifdef DEBUG_MODE+    ASSERT(e != 0);+#endif+    hDim_t mprime = ipow(p,e-1);+#ifdef DEBUG_MODE+    printf("lts is %" PRId32 "\trts is %" PRId32 "\n", lts, rts);+    printf("rus for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);+    hDim_t i;+    for(i = 0; i < ipow(p,e); i++) {+        printf("%" PRId64 ",", ((hInt_t*)ru)[i*tupSize+tupIdx]);+    }+    printf("]\n");+#endif++    hInt_t* temp = 0;+    if(p >= DFTP_GENERIC_SIZE)+    {+        temp = (hInt_t*)malloc(p*sizeof(hInt_t));+    }+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+        hInt_t* z = ((hInt_t*)y)+tupIdx;+        hInt_t q = qs[tupIdx];+        hInt_t* ruOffset = ((hInt_t*)ru)+tupIdx;++        pe.exponent -= 1;+        ppDFTInvRq (z, tupSize, lts, rts*(p-1), pe, p, ruOffset, q, temp);+        pe.exponent += 1;+        crtTwiddleRq (z, tupSize, lts, rts, pe, ruOffset, q);+        crtpinvRq (z, tupSize, lts*mprime, rts, p, mprime, ruOffset, q);+    }++    if(p >= DFTP_GENERIC_SIZE)+    {+        free(temp);+    }+}++// EAC: Somebody who knows C/C++ should find a better way to handle pointers-to-pointers in a generic way+void tensorCRTRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** ru, hInt_t* qs)+{+    hDim_t i;+#ifdef STATS+    struct timespec s1,s2,s3,s4,t1,t2,t3,t4;++    crtRqCtr++;++    clock_gettime(CLOCK_REALTIME, &s1);+    clock_gettime(CLOCK_MONOTONIC, &s2);+    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &s3);+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &s4);+#endif+#ifdef DEBUG_MODE+    printf("\n\nEntered tensorCRTRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\ttupSize=%" PRId16 "\n[", totm, sizeOfPE,tupSize);+    for(i = 0; i < tupSize; i++) {+        printf("%" PRId64 ",", qs[i]);+    }+    printf("]\n[");+    for(i = 0; i < totm*tupSize; i++) {+        printf("%" PRId64 ",", y[i]);+    }+    printf("]\n[");+    for(i = 0; i < sizeOfPE; i++) {+        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);+    }+    printf("]\n");+#endif++    void** rus = (void**)malloc(sizeOfPE*sizeof(void*));+    for(i = 0; i < sizeOfPE; i++)+    {+        rus[i] = (void*) (ru[i]);+    }++  tensorFuserCRT (y, tupSize, ppcrtRq, totm, peArr, sizeOfPE, rus, qs);++    for(i = 0; i < tupSize; i++) {+        hInt_t q = qs[i];+      for(hDim_t j = 0; j < totm; j++)+      {+          if(y[j*tupSize+i]<0)+          {+              y[j*tupSize+i]+=q;+          }+#ifdef DEBUG_MODE+          if(y[j*tupSize+i]<0)+          {+              printf("TENSOR CRT^T INV\n");+          }+#endif+        }+  }++  free(rus);+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    clock_gettime(CLOCK_MONOTONIC, &t2);+    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t3);+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t4);++    crttime1 = tsAdd(crttime1, tsSubtract(t1,s1));+    crttime2 = tsAdd(crttime2, tsSubtract(t2,s2));+    crttime3 = tsAdd(crttime3, tsSubtract(t3,s3));+    crttime4 = tsAdd(crttime4, tsSubtract(t4,s4));+#endif+}++//takes inverse rus+void tensorCRTInvRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, +                    hInt_t** ruinv, hInt_t* mhatInv, hInt_t* qs)+{+  hDim_t i;+#ifdef STATS+    struct timespec s1,t1;+    crtInvRqCtr++;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+#ifdef DEBUG_MODE+    printf("\n\nEntered tensorCRTInvRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\ttupSize=%" PRId16 "\nqs[", totm, sizeOfPE, tupSize);+    for(i = 0; i < tupSize; i++) {+        printf("%" PRId64 ",", qs[i]);+    }+    printf("]\nmhatInv[");+    for(i = 0; i < tupSize; i++) {+        printf("%" PRId64 ",", mhatInv[i]);+    }+    printf("]\ny[");+    for(i = 0; i < totm*tupSize; i++) {+        printf("%" PRId64 ",", y[i]);+    }+    printf("]\npps[");+    for(i = 0; i < sizeOfPE; i++) {+        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);+    }+    printf("]\n");+#endif++  void** rus = (void**)malloc(sizeOfPE*sizeof(void*));+    for(i = 0; i < sizeOfPE; i++)+    {+        rus[i] = (void*) (ruinv[i]);+    }+  tensorFuserCRT (y, tupSize, ppcrtinvRq, totm, peArr, sizeOfPE, rus, qs);++    for (i = 0; i < tupSize; i++) {+        hInt_t q = qs[i];+      for (hDim_t j = 0; j < totm; j++)+      {+          y[j*tupSize+i] = (y[j*tupSize+i]*mhatInv[i])%q;+          if(y[j*tupSize+i] < 0)+          {+              y[j*tupSize+i] +=q;+          }+#ifdef DEBUG_MODE+          if(y[j*tupSize+i]<0)+          {+              printf("TENSOR CRT INV\n");+          }+#endif+        }+  }++  free(rus);+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    crtInvRqTime = tsAdd(crtInvRqTime, tsSubtract(t1,s1));+#endif+}+++++++++++++++++++++++++++++++++++++++++void crtTwiddleC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, complex_t* ru)+{+    hDim_t idx;+    hDim_t p = pe.prime;+    hShort_t e = pe.exponent;+    +#ifdef DEBUG_MODE+    ASSERT(e != 0);+#endif++    pe.exponent -= 1; // used for an argument to bitrev+    +    if(p == 2)+    {+        hDim_t mprime = 1<<(e-1);+        hDim_t blockDim = rts*mprime; // size of block in block diagonal tensor matrix++        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0+        {+            hDim_t temp2 = i0*rts;+            complex_t twid = ru[bitrev(pe,i0)*tupSize];++            for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)+            {+                hDim_t temp3 = blockIdx*blockDim + temp2;+                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                {+                    idx = temp3 + modOffset;+                    CMPLX_IMUL(y[idx*tupSize],twid);+                }+            }+        }+    }+    else+    {+        hDim_t mprime = ipow(p,e-1);+        hDim_t blockDim = rts*(p-1)*mprime; // size of block in block diagonal tensor matrix++        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0+        {+            hDim_t temp1 = i0*(p-1);+            for(hDim_t i1 = 0; i1 < (p-1); i1++) // loops over i%(p-1) for i = 0..(m'-1)+            {        +                hDim_t temp2 = (temp1+i1)*rts;+                complex_t twid = ru[bitrev(pe,i0)*(i1+1)*tupSize];++                for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)+                {+                    hDim_t temp3 = blockIdx*blockDim + temp2;+                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                    {+                        idx = temp3 + modOffset;+                        CMPLX_IMUL(y[idx*tupSize],twid);+                    }+                }+            }+        }+    }+}+    +// dim is power of p+void dftptwidC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t dim, hDim_t rustride, complex_t* ru)+{+    hDim_t idx;+    hDim_t p = pe.prime;+    pe.exponent -= 1; // used for an argument to bitrev+    +    if(p == 2)+    {+        hDim_t mprime = dim>>1; // divides evenly+        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset+        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0+        {+            hDim_t temp3 = rts*(i0*p+1);+            complex_t twid = ru[bitrev(pe,i0)*rustride*tupSize];++            for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+            {+                hDim_t temp2 = blockOffset*temp1 + temp3;+                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                {+                    idx = temp2 + modOffset;+                    CMPLX_IMUL(y[idx*tupSize],twid);+                }+            }+        }+    }+    else+    {+        hDim_t mprime = dim/p; // divides evenly+        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset+        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0+        {+            for(hDim_t i1 = 1; i1 < p; i1++) // loops over i%p for i = 0..(dim-1), but we skip i1=0+            {+                hDim_t temp3 = rts*(i0*p+i1);+                complex_t twid = ru[bitrev(pe,i0)*i1*rustride*tupSize];++                for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+                {+                    hDim_t temp2 = blockOffset*temp1 + temp3;+                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+                    {+                        idx = temp2 + modOffset;+                        CMPLX_IMUL(y[idx*tupSize],twid);+                    }+                }+            }+        }+    }+}++//implied length of ru is rustride*p+//implied length of tempSpace is p, if p is not a special case+void dftpC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ru, complex_t* tempSpace)+{+    hDim_t blockOffset, modOffset, tensorOffset;+    +    if(p == 2)+    {+        hDim_t temp1 = rts<<1;+        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                complex_t u = y[tensorOffset*tupSize];+                complex_t t = y[(tensorOffset+rts)*tupSize];+                y[tensorOffset*tupSize] = CMPLX_ADD(u,t);+                y[(tensorOffset+rts)*tupSize] = CMPLX_SUB(u,t);+            }+        }+    }+    else if(p == 3)+    {+        hDim_t temp1 = rts*3;+        complex_t ru1 = ru[rustride*tupSize];+        complex_t ru2 = ru[(rustride<<1)*tupSize];++        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                complex_t y1, y2, y3;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y[tensorOffset*tupSize]            = CMPLX_ADD3(y1,               y2,                y3);+                y[(tensorOffset+rts)*tupSize]      = CMPLX_ADD3(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3));+                y[(tensorOffset+(rts<<1))*tupSize] = CMPLX_ADD3(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru1,y3));+            }   +        }+    }+    else if(p == 5)+    {+        hDim_t temp1 = rts*5;+        complex_t ru1 = ru[rustride*tupSize];+        complex_t ru2 = ru[(rustride<<1)*tupSize];+        complex_t ru3 = ru[(rustride*3)*tupSize];+        complex_t ru4 = ru[(rustride<<2)*tupSize];++        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                complex_t y1, y2, y3, y4, y5;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];+                y5 = y[(tensorOffset+(rts<<2))*tupSize];+                y[tensorOffset*tupSize]          = CMPLX_ADD5(y1,               y2,                y3,                y4,                y5);+                y[(tensorOffset+rts)*tupSize]      = CMPLX_ADD5(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4), CMPLX_MUL(ru4,y5));+                y[(tensorOffset+(rts<<1))*tupSize] = CMPLX_ADD5(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru1,y4), CMPLX_MUL(ru3,y5));+                y[(tensorOffset+rts*3)*tupSize]    = CMPLX_ADD5(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru4,y4), CMPLX_MUL(ru2,y5));+                y[(tensorOffset+(rts<<2))*tupSize] = CMPLX_ADD5(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru2,y4), CMPLX_MUL(ru1,y5));+            }   +        }+    }+    else if(p == 7)+    {+        hDim_t temp1 = rts*7;+        complex_t ru1 = ru[rustride*tupSize];+        complex_t ru2 = ru[(rustride<<1)*tupSize];+        complex_t ru3 = ru[(rustride*3)*tupSize];+        complex_t ru4 = ru[(rustride<<2)*tupSize];+        complex_t ru5 = ru[(rustride*5)*tupSize];+        complex_t ru6 = ru[(rustride*6)*tupSize];++        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                complex_t y1, y2, y3, y4, y5, y6, y7;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];+                y5 = y[(tensorOffset+(rts<<2))*tupSize];+                y6 = y[(tensorOffset+rts*5)*tupSize];+                y7 = y[(tensorOffset+rts*6)*tupSize];+                y[tensorOffset*tupSize]          = CMPLX_ADD7(y1,               y2,                y3,                y4,                y5,                y6,                y7);+                y[(tensorOffset+rts)*tupSize]      = CMPLX_ADD7(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4), CMPLX_MUL(ru4,y5), CMPLX_MUL(ru5,y6), CMPLX_MUL(ru6,y7));+                y[(tensorOffset+(rts<<1))*tupSize] = CMPLX_ADD7(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru6,y4), CMPLX_MUL(ru1,y5), CMPLX_MUL(ru3,y6), CMPLX_MUL(ru5,y7));+                y[(tensorOffset+rts*3)*tupSize]    = CMPLX_ADD7(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru6,y3), CMPLX_MUL(ru2,y4), CMPLX_MUL(ru5,y5), CMPLX_MUL(ru1,y6), CMPLX_MUL(ru4,y7));+                y[(tensorOffset+(rts<<2))*tupSize] = CMPLX_ADD7(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru5,y4), CMPLX_MUL(ru2,y5), CMPLX_MUL(ru6,y6), CMPLX_MUL(ru3,y7));+                y[(tensorOffset+rts*5)*tupSize]    = CMPLX_ADD7(y1, CMPLX_MUL(ru5,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru1,y4), CMPLX_MUL(ru6,y5), CMPLX_MUL(ru4,y6), CMPLX_MUL(ru2,y7));+                y[(tensorOffset+rts*6)*tupSize]    = CMPLX_ADD7(y1, CMPLX_MUL(ru6,y2), CMPLX_MUL(ru5,y3), CMPLX_MUL(ru4,y4), CMPLX_MUL(ru3,y5), CMPLX_MUL(ru2,y6), CMPLX_MUL(ru1,y7));+            }   +        }+    }+    else+    {+        hDim_t temp1 = rts*p;+        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hDim_t row, col;+                +                for(row = 0; row < p; row++)+                {+                    complex_t acc = ((complex_t){0,0});+                    for(col = 0; col < p; col++)+                    {+                        CMPLX_IADD(acc, CMPLX_MUL(y[(tensorOffset+col*rts)*tupSize], ru[((col*row) % p)*rustride*tupSize]));+                    }+                    tempSpace[row] = acc;+                }+                +                for(row = 0; row < p; row++)+                {+                    y[(tensorOffset+rts*row)*tupSize] = tempSpace[row];   +                }+            }+        }+    }+}++void crtpC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ru)+{+    hDim_t blockOffset, modOffset, tensorOffset;+    +    if(p == 2)+    {+        return;+    }+    else if(p == 3)+    {+        hDim_t temp1 = rts*2;+        complex_t ru1 = ru[rustride*tupSize];+        complex_t ru2 = ru[(rustride<<1)*tupSize];++        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                complex_t y1, y2;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y[tensorOffset*tupSize]     = CMPLX_ADD(y1, CMPLX_MUL(ru1,y2));+                y[(tensorOffset+rts)*tupSize] = CMPLX_ADD(y1, CMPLX_MUL(ru2,y2));+            }   +        }+    }+    else if(p == 5)+    {+        hDim_t temp1 = rts*4;+        complex_t ru1 = ru[rustride*tupSize];+        complex_t ru2 = ru[(rustride<<1)*tupSize];+        complex_t ru3 = ru[(rustride*3)*tupSize];+        complex_t ru4 = ru[(rustride<<2)*tupSize];++        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                complex_t y1, y2, y3, y4;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];+                y[tensorOffset*tupSize]          = CMPLX_ADD4(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4));+                y[(tensorOffset+rts)*tupSize]      = CMPLX_ADD4(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru1,y4));+                y[(tensorOffset+(rts<<1))*tupSize] = CMPLX_ADD4(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru4,y4));+                y[(tensorOffset+rts*3)*tupSize]    = CMPLX_ADD4(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru2,y4));+            }   +        }+    }+    else if(p == 7)+    {+        hDim_t temp1 = rts*6;+        complex_t ru1 = ru[rustride*tupSize];+        complex_t ru2 = ru[(rustride<<1)*tupSize];+        complex_t ru3 = ru[(rustride*3)*tupSize];+        complex_t ru4 = ru[(rustride<<2)*tupSize];+        complex_t ru5 = ru[(rustride*5)*tupSize];+        complex_t ru6 = ru[(rustride*6)*tupSize];++        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                complex_t y1, y2, y3, y4, y5, y6;+                y1 = y[tensorOffset*tupSize];+                y2 = y[(tensorOffset+rts)*tupSize];+                y3 = y[(tensorOffset+(rts<<1))*tupSize];+                y4 = y[(tensorOffset+3*rts)*tupSize];+                y5 = y[(tensorOffset+(rts<<2))*tupSize];+                y6 = y[(tensorOffset+rts*5)*tupSize];+                y[tensorOffset*tupSize]          = CMPLX_ADD6(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4), CMPLX_MUL(ru4,y5), CMPLX_MUL(ru5,y6));+                y[(tensorOffset+rts)*tupSize]      = CMPLX_ADD6(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru6,y4), CMPLX_MUL(ru1,y5), CMPLX_MUL(ru3,y6));+                y[(tensorOffset+(rts<<1))*tupSize] = CMPLX_ADD6(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru6,y3), CMPLX_MUL(ru2,y4), CMPLX_MUL(ru5,y5), CMPLX_MUL(ru1,y6));+                y[(tensorOffset+rts*3)*tupSize]    = CMPLX_ADD6(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru5,y4), CMPLX_MUL(ru2,y5), CMPLX_MUL(ru6,y6));+                y[(tensorOffset+(rts<<2))*tupSize] = CMPLX_ADD6(y1, CMPLX_MUL(ru5,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru1,y4), CMPLX_MUL(ru6,y5), CMPLX_MUL(ru4,y6));+                y[(tensorOffset+rts*5)*tupSize]    = CMPLX_ADD6(y1, CMPLX_MUL(ru6,y2), CMPLX_MUL(ru5,y3), CMPLX_MUL(ru4,y4), CMPLX_MUL(ru3,y5), CMPLX_MUL(ru2,y6));+            }   +        }+    }+    else+    {+        complex_t* tempSpace = (complex_t*)malloc((p-1)*sizeof(complex_t));+        hDim_t temp1 = rts*(p-1);+        for(blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;+                hDim_t row, col;+                +                for(row = 1; row < p; row++)+                {+                    complex_t acc = ((complex_t){0,0});+                    for(col = 0; col < p-1; col++)+                    {+                        CMPLX_IADD(acc, CMPLX_MUL(y[(tensorOffset+col*rts)*tupSize], ru[((col*row) % p)*rustride*tupSize]));+                    }+                    tempSpace[row-1] = acc;+                }+                +                for(row = 0; row < p-1; row++)+                {+                    y[(tensorOffset+rts*row)*tupSize] = tempSpace[row];   +                }+            }+        }+        free(tempSpace);+    }+}++//takes inverse rus+void crtpinvC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ruinv)+{+    if(p ==2)+    {+        // need this case so that we can divide overall by mhat^(-1)+        return;+    }+    else+    {+        hDim_t tensorOffset,i;+        complex_t* tempSpace = (complex_t*)malloc(p*sizeof(complex_t));+        hDim_t temp1 = rts*(p-1);+        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)+        {+            hDim_t temp2 = blockOffset*temp1;+            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)+            {+                tensorOffset = temp2 + modOffset;++                for(i = 0; i < p-1; i++)+                {+                    complex_t sum = ((complex_t){0,0});+                    int j;+                    for(j = 0; j < p-1; j++)+                    {+                        int ruIdx = (((j+1)*i) % p)*rustride;+                        CMPLX_IADD(sum, CMPLX_MUL(y[(tensorOffset+j*rts)*tupSize],ruinv[ruIdx*tupSize]));+                    }+                    tempSpace[i] = sum;+                }++                complex_t shift = ((complex_t){0,0});+                for(i = 0; i < p-1; i++)+                {+                    // we were given the inverse rus, so we need to negate the indices+                    int ruIdx = p-(i+1);+                    CMPLX_IADD(shift, CMPLX_MUL(y[(tensorOffset+i*rts)*tupSize], ruinv[rustride*ruIdx*tupSize]));+                }++                for(i = 0; i < p-1; i++)+                {+                    y[(tensorOffset+i*rts)*tupSize] = CMPLX_SUB(tempSpace[i], shift); +                }+            }+        }+    }+}++void ppDFTC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t rustride, complex_t* ru, complex_t* temp)+{+    hDim_t p = pe.prime;+    hShort_t e = pe.exponent;+    +    if(e == 0)+    {+        return;+    }+    +    hDim_t primeRuStride = rustride*ipow(p,e-1);    ++    hShort_t i;+    +    hDim_t ltsScale = ipow(p,e-1);+    hDim_t rtsScale = 1;+    hDim_t twidRuStride = rustride;+    for(i = 0; i < e; i++)+    {+        hDim_t rtsDim = rts*rtsScale;+        dftpC (y, tupSize, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp);+        dftptwidC (y, tupSize, lts, rtsDim, pe, ltsScale*p, twidRuStride, ru);+        +        ltsScale /= p;+        rtsScale *= p;+        twidRuStride *= p;+        pe.exponent -= 1;+    }+}++void ppDFTInvC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t rustride, complex_t* ru, complex_t* temp)+{++    hDim_t p = pe.prime;+    hShort_t e = pe.exponent;+    +    if(e == 0)+    {+        return;+    }+    hDim_t primeRuStride = rustride*ipow(p,e-1);++    hShort_t i;+    +    hDim_t ltsScale = 1;+    hDim_t rtsScale = ipow(p,e-1);+    hDim_t twidRuStride = primeRuStride;+    pe.exponent = 1;+    for(i = 0; i < e; i++)+    {+        hDim_t rtsDim = rts*rtsScale;+        hDim_t ltsScaleP = ltsScale*p;+        dftptwidC (y, tupSize, lts, rtsDim, pe, ltsScaleP, twidRuStride, ru);+        dftpC (y, tupSize, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp);+        +        ltsScale = ltsScaleP;+        rtsScale /= p;+        twidRuStride /= p;+        pe.exponent += 1;+    }+}++void ppcrtC (void* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t* qs)+{+    hDim_t p = pe.prime;+    hDim_t e = pe.exponent;+#ifdef DEBUG_MODE+    ASSERT(e != 0);+#endif+    hDim_t mprime = ipow(p,e-1);++#ifdef DEBUG_MODE+    printf("rus for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);+    hDim_t i;+    for(i = 0; i < ipow(p,e); i++) {+        printf("(%f,%f),", ((complex_t*)ru)[i].real, ((complex_t*)ru)[i].imag);+    }+    printf("]\n");+#endif++    complex_t* temp = 0;+    if(p >= DFTP_GENERIC_SIZE)+    {+        temp = (complex_t*)malloc(p*sizeof(complex_t));+    }++    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+        complex_t* z = ((complex_t*)y)+tupIdx;+        complex_t* ruOffset = ((complex_t*)ru)+tupIdx;+        crtpC (z, tupSize, lts*mprime, rts, p, mprime, ruOffset);+        crtTwiddleC (z, tupSize, lts, rts, pe, ruOffset);+        pe.exponent -= 1;+        ppDFTC (z, tupSize, lts, rts*(p-1), pe, p, ruOffset, temp);+        pe.exponent += 1;+    }++    if(p >= DFTP_GENERIC_SIZE)+    {+        free(temp);+    }+}++void ppcrtinvC (void* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t* qs)+{+    hDim_t p = pe.prime;+    hDim_t e = pe.exponent;+#ifdef DEBUG_MODE+    ASSERT(e != 0);+#endif+    hDim_t mprime = ipow(p,e-1);+    +    complex_t* temp = 0;+    if(p >= DFTP_GENERIC_SIZE)+    {+        temp = (complex_t*)malloc(p*sizeof(complex_t));+    }++    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+        complex_t* z = ((complex_t*)y)+tupIdx;+        complex_t* ruOffset = ((complex_t*)ru)+tupIdx;+        pe.exponent -= 1;+        ppDFTInvC (z, tupSize, lts, rts*(p-1), pe, p, ruOffset, temp);+        pe.exponent += 1;+        crtTwiddleC (z, tupSize, lts, rts, pe, ruOffset);+        crtpinvC (z, tupSize, lts*mprime, rts, p, mprime, ruOffset);+    }++    if(p >= DFTP_GENERIC_SIZE)+    {+        free(temp);+    }+}++void tensorCRTC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru)+{+#ifdef STATS+    struct timespec s1,t1;+    crtCCtr++;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+#ifdef DEBUG_MODE+    printf("\n\nEntered tensorCRTC\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);+    hDim_t j;+    for(j = 0; j < totm; j++) {+        printf("(%f,%f),", y[j].real, y[j].imag);+    }+    printf("]\n[");+    for(j = 0; j < sizeOfPE; j++) {+        printf("(%" PRId32 ",%" PRId16 "),", peArr[j].prime, peArr[j].exponent);+    }+    printf("]\n");+#endif+    void** rus = (void**)malloc(sizeOfPE*sizeof(void*));+    hShort_t i;+    for(i = 0; i < sizeOfPE; i++)+    {+        rus[i] = (void*) (ru[i]);+    }+  tensorFuserCRT (y, tupSize, ppcrtC, totm, peArr, sizeOfPE, rus, (hInt_t*)0);+  free(rus);+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    crtCTime = tsAdd(crtCTime, tsSubtract(t1,s1));+#endif+}++//takes inverse rus+void tensorCRTInvC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, +                    hShort_t sizeOfPE, complex_t** ruinv, complex_t* mhatInv)+{+#ifdef STATS+    struct timespec s1,t1;+    crtInvCCtr++;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+  hDim_t i;+  +  void** rus = (void**)malloc(sizeOfPE*sizeof(void*));+    for(i = 0; i < sizeOfPE; i++)+    {+        rus[i] = (void*) (ruinv[i]);+    }+  +  tensorFuserCRT (y, tupSize, ppcrtinvC, totm, peArr, sizeOfPE, rus, (hInt_t*)0);++    for (i = 0; i < tupSize; i++) {+      for (hDim_t j = 0; j < totm; j++)+      {+          CMPLX_IMUL(y[j*tupSize+i], mhatInv[i]);+      }+    }+  +  free(rus);+#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    crtInvCTime = tsAdd(crtInvCTime, tsSubtract(t1,s1));+#endif+}
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/g.c view
@@ -0,0 +1,828 @@+#include "tensorTypes.h"
+
+
+void gPowR (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p)
+{
+  hDim_t tmp1 = rts*(p-1);
+  hDim_t tmp2 = tmp1 - rts;
+  hDim_t blockOffset, modOffset;
+  hDim_t i;
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp3 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp3 + modOffset;
+      hInt_t last = y[(tensorOffset + tmp2)*tupSize];
+      for (i = p-2; i != 0; --i)
+      {
+        hDim_t idx = tensorOffset + i * rts;
+        y[idx*tupSize] += last - y[(idx-rts)*tupSize];
+      }
+      y[tensorOffset*tupSize] += last;
+    }
+  }
+}
+
+void gPowRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
+{
+  hDim_t tmp1 = rts*(p-1);
+  hDim_t tmp2 = tmp1 - rts;
+  hDim_t blockOffset, modOffset;
+  hDim_t i;
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp3 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp3 + modOffset;
+      hInt_t last = y[(tensorOffset + tmp2)*tupSize];
+      for (i = p-2; i != 0; --i)
+      {
+        hDim_t idx = tensorOffset + i * rts;
+        y[idx*tupSize] = (y[idx*tupSize] + last - y[(idx-rts)*tupSize]) % q;
+      }
+      y[tensorOffset*tupSize] = (y[tensorOffset*tupSize] + last) % q;
+    }
+  }
+}
+
+void gPowC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p)
+{
+  hDim_t tmp1 = rts*(p-1);
+  hDim_t tmp2 = tmp1 - rts;
+  hDim_t blockOffset, modOffset;
+  hDim_t i;
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp3 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp3 + modOffset;
+      complex_t last = y[(tensorOffset + tmp2)*tupSize];
+      for (i = p-2; i != 0; --i)
+      {
+        hDim_t idx = tensorOffset + i * rts;
+        CMPLX_IADD(y[idx*tupSize],last);
+        CMPLX_ISUB(y[idx*tupSize],y[(idx-rts)*tupSize]);
+      }
+      CMPLX_IADD(y[tensorOffset*tupSize],last);
+    }
+  }
+}
+
+void ppGPowR (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+     
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gPowR (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+      }
+    }
+}
+
+void ppGPowRq (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gPowRq (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, qs[tupIdx]);
+      }
+    }
+}
+
+void ppGPowC (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gPowC (((complex_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+      }
+    }
+}
+
+void gDecR (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p)
+{
+  hDim_t tmp1 = rts*(p-1);
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  hDim_t i;
+
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp2 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hInt_t acc = y[tensorOffset*tupSize];
+      for (i = p-2; i != 0; --i)
+      {
+        hDim_t idx = tensorOffset + i * rts;
+        acc += y[idx*tupSize];
+        y[idx*tupSize] -= y[(idx-rts)*tupSize];
+      }
+      y[tensorOffset*tupSize] += acc;
+    }
+  }
+}
+
+void gDecRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
+{
+  hDim_t tmp1 = rts*(p-1);
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  hDim_t i;
+
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp2 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hInt_t acc = y[tensorOffset*tupSize];
+      for (i = p-2; i != 0; --i)
+      {
+        hDim_t idx = tensorOffset + i * rts;
+        // acc is at most p*q << 64 bits, so no need to mod
+        acc = acc + y[idx*tupSize];
+        y[idx*tupSize] = (y[idx*tupSize] - y[(idx-rts)*tupSize]) % q;
+      }
+      y[tensorOffset*tupSize] = (y[tensorOffset*tupSize] + acc) % q;
+    }
+  }
+}
+
+void ppGDecR (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gDecR (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+      }
+    }
+}
+
+void ppGDecRq (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gDecRq (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, qs[tupIdx]);
+      }
+    }
+}
+
+
+void gInvPowR (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p)
+{
+  hDim_t tmp1 = rts * (p-1);
+  hDim_t blockOffset, modOffset;
+  hDim_t i;
+
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp2 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hInt_t lelts = 0;
+      for (i = 0; i < p-1; ++i)
+      {
+        lelts += y[(tensorOffset + i*rts)*tupSize];
+      }
+      hInt_t relts = 0;
+      for (i = p-2; i >= 0; --i)
+      {
+        hDim_t idx = tensorOffset + i*rts;
+        hInt_t z = y[idx*tupSize];
+        y[idx*tupSize] = (p-1-i) * lelts - (i+1)*relts;
+        lelts -= z;
+        relts += z;
+      }
+    }
+  }
+}
+
+void gInvPowRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
+{
+  hDim_t tmp1 = rts * (p-1);
+  hDim_t blockOffset, modOffset;
+  hDim_t i;
+
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp2 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hInt_t lelts = 0;
+      //lelts is at most p*q, so we can mod once at the end
+      for (i = 0; i < p-1; ++i)
+      {
+        lelts = lelts + y[(tensorOffset + i*rts)*tupSize];
+      }
+      lelts = lelts % q;
+      //in the next loop, lelts <= p*q and relts <= p*q
+      //products are <= p*p*q, and diff is <= 2*p*p*q
+      //so we assume 2*p^2 << 31 bits
+      hInt_t relts = 0;
+      for (i = p-2; i >= 0; --i)
+      {
+        hDim_t idx = tensorOffset + i*rts;
+        hInt_t z = y[idx*tupSize];
+        y[idx*tupSize] = (((p-1-i) * lelts) - ((i+1)*relts)) % q;
+        lelts -= z;
+        relts += z;
+      }
+    }
+  }
+}
+
+void gInvPowC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p)
+{
+  hDim_t tmp1 = rts * (p-1);
+  hDim_t blockOffset, modOffset;
+  hDim_t i;
+
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp2 = blockOffset * tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      complex_t lelts = ((complex_t){0, 0});;
+      for (i = 0; i < p-1; ++i)
+      {
+        CMPLX_IADD(lelts,y[(tensorOffset + i*rts)*tupSize]);
+      }
+      complex_t relts = ((complex_t){0, 0});;
+      for (i = p-2; i >= 0; --i)
+      {
+        hDim_t idx = tensorOffset + i*rts;
+        complex_t z = y[idx*tupSize];
+
+        complex_t c1 = ((complex_t){p-1-i, 0});
+        complex_t c2 = ((complex_t){i+1, 0});
+        complex_t t1 = CMPLX_MUL(c1, lelts);
+        complex_t t2 = CMPLX_MUL(c2, relts);
+        y[idx*tupSize] = CMPLX_SUB(t1,t2);
+        CMPLX_ISUB(lelts,z);
+        CMPLX_IADD(relts,z);
+      }
+    }
+  }
+}
+
+void ppGInvPowR (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gInvPowR (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+      }
+    }
+}
+
+void ppGInvPowRq (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gInvPowRq (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, qs[tupIdx]);
+      }
+    }
+}
+
+void ppGInvPowC (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gInvPowC (((complex_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+      }
+    }
+}
+
+//do not call for p=2!
+void gCRTRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hInt_t* gcoeffs, hInt_t q)
+{
+    hDim_t gindex;
+    hDim_t blockOffset, modOffset, idx;
+    hDim_t temp1 = rts*(p-1);
+    
+    for(gindex = 0; gindex < p-1; gindex++)
+    {
+        hInt_t coeff = gcoeffs[gindex*tupSize];
+        hDim_t temp3 = gindex*rts;
+        for(blockOffset = 0; blockOffset < lts; blockOffset++)
+        {
+            hDim_t temp2 = blockOffset*temp1 + temp3;
+            for(modOffset = 0; modOffset < rts; modOffset++)
+            {
+                idx = temp2 + modOffset;
+                y[idx*tupSize] = (y[idx*tupSize]*coeff)%q;
+            }
+        }
+    }
+}
+
+//do not call for p=2!
+void gCRTC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, complex_t* gcoeffs)
+{
+    hDim_t gindex;
+    hDim_t blockOffset, modOffset, idx;
+    hDim_t temp1 = rts*(p-1);
+    
+    for(gindex = 0; gindex < p-1; gindex++)
+    {
+        complex_t coeff = gcoeffs[gindex*tupSize];
+        hDim_t temp3 = gindex*rts;
+        for(blockOffset = 0; blockOffset < lts; blockOffset++)
+        {
+            hDim_t temp2 = blockOffset*temp1 + temp3;
+            for(modOffset = 0; modOffset < rts; modOffset++)
+            {
+                idx = temp2 + modOffset;
+                CMPLX_IMUL(y[idx*tupSize],coeff);
+            }
+        }
+    }
+}
+
+void ppGCRTRq (void* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, void* gcoeffs, hInt_t* qs)
+{
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    
+#ifdef DEBUG_MODE
+    printf("gcoeffs for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);
+    int i;
+    for(i = 0; i < ((p-1)*ipow(p,e-1)); i++) {
+        printf("%" PRId64 ",", ((hInt_t*)gcoeffs)[i]);
+    }
+    printf("]\n");
+#endif
+    
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gCRTRq (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, ((hInt_t*)gcoeffs)+tupIdx, qs[tupIdx]);
+      }
+    }
+}
+
+void ppGCRTC (void* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, void* gcoeffs, hInt_t* qs)
+{
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    
+#ifdef DEBUG_MODE
+    printf("gcoeffs for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);
+    int i;
+    for(i = 0; i < ((p-1)*ipow(p,e-1)); i++) {
+        printf("(%f,%f),", ((complex_t*)gcoeffs)[i].real, ((complex_t*)gcoeffs)[i].imag);
+    }
+    printf("]\n");
+#endif
+    
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gCRTC (((complex_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, ((complex_t*)gcoeffs)+tupIdx);
+      }
+    }
+}
+
+void gInvDecR (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p)
+{
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  hDim_t i;
+  hDim_t tmp1 = rts*(p-1);
+
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hInt_t lastOut = 0;
+      for (i=1; i < p; ++i)
+      {
+        lastOut += i * y[(tensorOffset + (i-1)*rts)*tupSize];
+      }
+      hInt_t acc = lastOut / p;
+      ASSERT (acc * p == lastOut);  // this line asserts that lastOut % p == 0, without calling % operator
+      for (i = p-2; i > 0; --i)
+      {
+        hDim_t idx = tensorOffset + i*rts;
+        hInt_t tmp = acc;
+        acc -= y[idx*tupSize]; // we already divided acc by p, do not multiply y[idx] by p
+        y[idx*tupSize] = tmp;
+      }
+      y[tensorOffset*tupSize] = acc;
+    }
+  }
+}
+
+void gInvDecRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
+{
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  hDim_t i;
+  hDim_t tmp1 = rts*(p-1);
+  hInt_t reciprocalOfP = reciprocal (q,p);
+
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
+  {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset)
+    {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hInt_t lastOut = 0;
+      for (i=1; i < p; ++i)
+      {
+        lastOut += (i * y[(tensorOffset + (i-1)*rts)*tupSize]);
+      }
+      //in the previous loop, |lastOut| <= p*p*q
+      lastOut = lastOut % q;
+      hInt_t acc = (lastOut * reciprocalOfP) % q;
+      // |acc| <= p*q
+      for (i = p-2; i > 0; --i)
+      {
+        hDim_t idx = tensorOffset + i*rts;
+        hInt_t tmp = acc;
+        acc = acc - y[idx*tupSize];
+        y[idx*tupSize] = tmp % q;
+      }
+      y[tensorOffset*tupSize] = acc % q;
+    }
+  }
+}
+
+void ppGInvDecR (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gInvDecR (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+      }
+    }
+}
+
+void ppGInvDecRq (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs)
+{
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if (p != 2)
+    {
+      for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+        gInvDecRq (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, qs[tupIdx]);
+      }
+    }
+}
+
+#ifdef STATS
+int gprCtr = 0;
+int gprqCtr = 0;
+int gdrCtr = 0;
+int gdrqCtr = 0;
+int giprCtr = 0;
+int giprqCtr = 0;
+int gidrCtr = 0;
+int gidrqCtr = 0;
+int gcrqCtr = 0;
+int gccCtr = 0;
+int gicrqCtr = 0;
+int giccCtr = 0;
+
+struct timespec gprTime = {0,0};
+struct timespec gprqTime = {0,0};
+struct timespec gdrTime = {0,0};
+struct timespec gdrqTime = {0,0};
+struct timespec giprTime = {0,0};
+struct timespec giprqTime = {0,0};
+struct timespec gidrTime = {0,0};
+struct timespec gidrqTime = {0,0};
+struct timespec gcrqTime = {0,0};
+struct timespec gccTime = {0,0};
+#endif
+
+void tensorGPowR (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
+{
+#ifdef STATS
+    gprCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGPowR, totm, peArr, sizeOfPE, (hInt_t*)0);
+
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gprTime = tsAdd(gprTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGPowRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs)
+{
+#ifdef STATS
+    gprqCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGPowRq, totm, peArr, sizeOfPE, qs);
+
+  hDim_t j;
+  for(int tupIdx = 0; tupIdx<tupSize; tupIdx++) {
+    hInt_t q = qs[tupIdx];
+    for(j = 0; j < totm; j++)
+    {
+        if(y[j*tupSize+tupIdx]<0)
+        {
+            y[j*tupSize+tupIdx]+=q;
+        }
+    }
+  }
+
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gprqTime = tsAdd(gprqTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGPowC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
+{
+#ifdef STATS
+    gpcCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGPowC, totm, peArr, sizeOfPE, (hInt_t*)0);
+
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gpcTime = tsAdd(gpcTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGDecR (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
+{
+#ifdef STATS
+    gdrCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGDecR, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gdrTime = tsAdd(gdrTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGDecRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs)
+{
+#ifdef STATS
+    gdrqCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGDecRq, totm, peArr, sizeOfPE, qs);
+
+  hDim_t j;
+  for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+    hInt_t q = qs[tupIdx];
+    for(j = 0; j < totm; j++)
+    {
+        if(y[j*tupSize+tupIdx]<0)
+        {
+            y[j*tupSize+tupIdx]+=q;
+        }
+    }
+  }
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gdrqTime = tsAdd(gdrqTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGInvPowR (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
+{
+#ifdef STATS
+    giprCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGInvPowR, totm, peArr, sizeOfPE, (hInt_t*)0);
+
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    giprTime = tsAdd(giprTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGInvPowRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs)
+{
+#ifdef STATS
+    giprqCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGInvPowRq, totm, peArr, sizeOfPE, qs);
+
+  hDim_t j;
+  for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+    hInt_t q = qs[tupIdx];
+    for(j = 0; j < totm; j++)
+    {
+        if(y[j*tupSize+tupIdx]<0)
+        {
+            y[j*tupSize+tupIdx]+=q;
+        }
+    }
+  }
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    giprqTime = tsAdd(giprqTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGInvPowC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
+{
+#ifdef STATS
+    gipcCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGInvPowC, totm, peArr, sizeOfPE, (hInt_t*)0);
+
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gipcTime = tsAdd(gipcTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGInvDecR (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
+{
+#ifdef STATS
+    gidrCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppGInvDecR, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gidrTime = tsAdd(gidrTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGInvDecRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs)
+{
+#ifdef STATS
+    gidrqCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+    tensorFuser (y, tupSize, ppGInvDecRq, totm, peArr, sizeOfPE, qs);
+
+  hDim_t j;
+  for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+    hInt_t q = qs[tupIdx];
+    for(j = 0; j < totm; j++)
+    {
+        if(y[j*tupSize+tupIdx]<0)
+        {
+            y[j*tupSize+tupIdx]+=q;
+        }
+    }
+  }
+
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gidrqTime = tsAdd(gidrqTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorGCRTRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t* qs)
+{
+#ifdef STATS
+    gcrqCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+#ifdef DEBUG_MODE
+    printf("\n\nEntered tensorGCRTRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\tq=%" PRId64 "\n[", totm, sizeOfPE, q);
+    hDim_t j;
+    for(j = 0; j < totm; j++) {
+        printf("%" PRId64 ",", y[j]);
+    }
+    printf("]\n[");
+    for(j = 0; j < sizeOfPE; j++) {
+        printf("(%" PRId32 ",%" PRId16 "),", peArr[j].prime, peArr[j].exponent);
+    }
+    printf("]\n");
+#endif
+    void** vgcoeffs = (void**)malloc(sizeOfPE*sizeof(void*));
+    hDim_t i;
+    for(i = 0; i < sizeOfPE; i++)
+    {
+        vgcoeffs[i] = (void*) (gcoeffs[i]);
+    }
+
+    tensorFuserCRT (y, tupSize, ppGCRTRq, totm, peArr, sizeOfPE, vgcoeffs, qs);
+
+#ifdef DEBUG_MODE
+    for(j = 0; j < totm; j++)
+  {
+      if(y[j]<0)
+      {
+          printf("tensorGCRTRq\n");
+      }
+  }
+#endif
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gcrqTime = tsAdd(gcrqTime, tsSubtract(t1,s1));
+#endif
+}
+void tensorGCRTC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs)
+{
+#ifdef STATS
+    gccCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+#ifdef DEBUG_MODE
+    printf("\n\nEntered tensorGCRTC\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
+    hDim_t j;
+    for(j = 0; j < totm; j++) {
+        printf("(%f,%f),", (y[j]).real, (y[j]).imag);
+    }
+    printf("]\n[");
+    for(j = 0; j < sizeOfPE; j++) {
+        printf("(%" PRId32 ",%" PRId16 "),", peArr[j].prime, peArr[j].exponent);
+    }
+    printf("]\n");
+#endif
+    void** vgcoeffs = (void**)malloc(sizeOfPE*sizeof(void*));
+    hDim_t i;
+    for(i = 0; i < sizeOfPE; i++)
+    {
+        vgcoeffs[i] = (void*) (gcoeffs[i]);
+    }
+
+    tensorFuserCRT (y, tupSize, ppGCRTC, totm, peArr, sizeOfPE, vgcoeffs, (hInt_t*)0);
+
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    gccTime = tsAdd(gccTime, tsSubtract(t1,s1));
+#endif
+}
+void tensorGInvCRTRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t* qs)
+{
+#ifdef STATS
+    gicrqCtr++;
+#endif
+    tensorGCRTRq (tupSize, y, totm, peArr, sizeOfPE, gcoeffs, qs); //output is already shifted
+}
+void tensorGInvCRTC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs)
+{
+#ifdef STATS
+    giccCtr++;
+#endif
+    tensorGCRTC (tupSize, y, totm, peArr, sizeOfPE, gcoeffs);
+}
+
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/generalfuncs.c view
@@ -0,0 +1,305 @@+#include "tensorTypes.h"
+
+hDim_t ipow(hDim_t base, hShort_t exp)
+{
+#ifdef DEBUG_MODE
+    ASSERT(exp >= 0);
+#endif
+	hDim_t result = 1;
+    while (exp)
+    {
+        if (exp & 1)
+        {
+            result *= base;
+        }
+        exp >>= 1;
+        base *= base;
+    }
+    return result;
+}
+
+complex_t cmplxpow(complex_t base, hShort_t exp)
+{
+	complex_t result = (complex_t){1,0};
+    while (exp)
+    {
+        if (exp & 1)
+        {
+            CMPLX_IMUL(result,base);
+        }
+        exp >>= 1;
+        CMPLX_IMUL(base,base);
+    }
+    return result;
+}
+
+hInt_t qpow(hInt_t base, hShort_t exp, hInt_t q)
+{
+	hInt_t result = 1;
+    while (exp)
+    {
+        if (exp & 1)
+        {
+            result = (result*base)%q;
+        }
+        exp >>= 1;
+        base = (base*base)%q;
+    }
+    return result;
+}
+
+// a is the field size. we are looking for reciprocal of b
+hInt_t reciprocal (hInt_t a, hInt_t b)
+{
+	hInt_t fieldSize = a;
+
+	hInt_t y = 1;
+	hInt_t lasty = 0;
+	while (b != 0)
+	{
+		hInt_t quotient = a / b;
+		hInt_t tmp = a % b;
+		a = b;
+		b = tmp;
+		tmp = y;
+		y  = lasty - quotient*y;
+		lasty = tmp;
+	}
+	ASSERT (a==1);  // if this one fails, then b is not invertible mod a
+
+	// this actually returns EITHER the reciprocal OR reciprocal + fieldSize
+	hInt_t res = lasty + fieldSize;
+#ifdef DEBUG_MODE
+	ASSERT (0);
+	ASSERT ((res >= 0) && (res < fieldSize + fieldSize));
+	hInt_t test = res * b % fieldSize;
+	ASSERT (test == 1);
+#endif
+	return res;
+
+}
+
+//for square transforms
+void tensorFuser (void* y, hShort_t tupSize, funcPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs)
+{
+    hDim_t lts = totm;
+    hDim_t rts = 1;
+    hShort_t i;
+
+    for (i = 0; i < sizeOfPE; ++i)
+    {
+        PrimeExponent pe = peArr[i];
+        hDim_t ipow_pe = ipow(pe.prime, (pe.exponent-1));
+        hDim_t dim = (pe.prime-1) * ipow_pe;  // the totient of pe
+        lts /= dim;
+        (*f) (y, tupSize, pe, lts, rts, qs);
+        rts  *= dim;
+    }
+}
+
+void tensorFuserCRT (void* y, hShort_t tupSize, crtFuncPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, void** ru, hInt_t* q)
+{
+    hDim_t lts = totm;
+    hDim_t rts = 1;
+    hShort_t i;
+
+    for (i = 0; i < sizeOfPE; ++i)
+    {
+        PrimeExponent pe = peArr[i];
+        hDim_t ipow_pe = ipow(pe.prime, (pe.exponent-1));
+        hDim_t dim = (pe.prime-1) * ipow_pe;  // the totient of pe
+        lts /= dim;
+        (*f) (y, tupSize, lts, rts, pe, ru[i], q);
+        rts  *= dim;
+    }
+}
+
+struct  timespec  tsSubtract (struct  timespec  time1, struct  timespec  time2)
+{    /* Local variables. */
+    struct  timespec  result ;
+
+/* Subtract the second time from the first. */
+
+    if ((time1.tv_sec < time2.tv_sec) ||
+        ((time1.tv_sec == time2.tv_sec) &&
+         (time1.tv_nsec <= time2.tv_nsec))) {		/* TIME1 <= TIME2? */
+        result.tv_sec = result.tv_nsec = 0 ;
+    } else {						/* TIME1 > TIME2 */
+        result.tv_sec = time1.tv_sec - time2.tv_sec ;
+        if (time1.tv_nsec < time2.tv_nsec) {
+            result.tv_nsec = time1.tv_nsec + 1000000000L - time2.tv_nsec ;
+            result.tv_sec-- ;				/* Borrow a second. */
+        } else {
+            result.tv_nsec = time1.tv_nsec - time2.tv_nsec ;
+        }
+    }
+
+    return (result) ;
+}
+
+struct  timespec  tsAdd (struct  timespec  time1, struct  timespec  time2)
+{    /* Local variables. */
+    struct  timespec  result ;
+
+/* Add the two times together. */
+
+    result.tv_sec = time1.tv_sec + time2.tv_sec ;
+    result.tv_nsec = time1.tv_nsec + time2.tv_nsec ;
+    if (result.tv_nsec >= 1000000000L) {		/* Carry? */
+        result.tv_sec++ ;  result.tv_nsec = result.tv_nsec - 1000000000L ;
+    }
+
+    return (result) ;
+}
+
+const  char  *tsShow (struct  timespec  binaryTime, bool  inLocal, const  char  *format)
+{    /* Local variables. */
+    struct  tm  calendarTime ;
+#define  MAX_TIMES  4
+    static  char  asciiTime[MAX_TIMES][64] ;
+    static  int  current = 0 ;
+
+/* Convert the TIMESPEC to calendar time: year, month, day, etc. */
+
+#ifdef VXWORKS
+    if (inLocal)
+        localtime_r ((time_t *) &binaryTime.tv_sec, &calendarTime) ;
+    else
+        gmtime_r ((time_t *) &binaryTime.tv_sec, &calendarTime) ;
+#else
+    if (inLocal)
+        calendarTime = *(localtime ((time_t *) &binaryTime.tv_sec)) ;
+    else
+        calendarTime = *(gmtime ((time_t *) &binaryTime.tv_sec)) ;
+#endif
+
+/* Format the time in ASCII. */
+
+    current = (current + 1) % MAX_TIMES ;
+
+    if (format == NULL) {
+        strftime (asciiTime[current], 64, "%Y-%j-%H:%M:%S", &calendarTime) ;
+        sprintf (asciiTime[current] + strlen (asciiTime[current]),
+                 ".%06ld", (binaryTime.tv_nsec % 1000000000L) / 1000L) ;
+    } else {
+        strftime (asciiTime[current], 64, format, &calendarTime) ;
+        sprintf (asciiTime[current] + strlen (asciiTime[current]),
+                 ".%06ld", (binaryTime.tv_nsec % 1000000000L) / 1000L) ;
+    }
+
+    return (asciiTime[current]);
+}
+
+
+
+const char* timeformat = "%M:%S";
+
+void getStats() { 
+
+#ifdef STATS
+    struct timespec total;
+    printf("CRT Stats:\n");
+    printf("CRT_Rq times: Real:%s\tMono:%s\tProc:%s\tThread:%s\n", tsShow(crttime1, false, timeformat),tsShow(crttime2, false, timeformat),tsShow(crttime3, false, timeformat),tsShow(crttime4, false, timeformat));
+    printf("CTR_Rq: %d\t%s\t%d\t%s\n", crtRqCtr, tsShow(crttime1, false, timeformat), crtInvRqCtr, tsShow(crtInvRqTime, false, timeformat));
+    printf("CTR_C: %d\t%s\t%d\t%s\n", crtCCtr, tsShow(crtCTime, false, timeformat), crtInvCCtr, tsShow(crtInvCTime, false, timeformat));
+    
+    printf("\nG Stats:\n");
+    printf("GPow_R: %d\t%s\t%d\t%s\n", gprCtr, tsShow(gprTime, false, timeformat), giprCtr, tsShow(giprTime, false, timeformat));
+    printf("GPow_Rq: %d\t%s\t%d\t%s\n", gprqCtr, tsShow(gprqTime, false, timeformat), giprqCtr, tsShow(giprqTime, false, timeformat));
+    printf("GPow_C: %d\t%s\t%d\t%s\n", gpcCtr, tsShow(gpcTime, false, timeformat), gipcCtr, tsShow(gipcTime, false, timeformat));
+    printf("GDec_R: %d\t%s\t%d\t%s\n", gdrCtr, tsShow(gdrTime, false, timeformat), gidrCtr, tsShow(gidrTime, false, timeformat));
+    printf("GDec_Rq: %d\t%s\t%d\t%s\n", gdrqCtr, tsShow(gdrqTime, false, timeformat), gidrqCtr, tsShow(gidrqTime, false, timeformat));
+    printf("GCRT_Rq: %d\t%d\t%s\n", gcrqCtr, gicrqCtr, tsShow(gcrqTime, false, timeformat));
+    printf("GCRT_C: %d\t%d\t%s\n", gccCtr, giccCtr, tsShow(gccTime, false, timeformat));
+
+    printf("\nL Stats:\n");
+    printf("L_R: %d\t%s\t%d\t%s\n", lrCtr, tsShow(lrTime, false, timeformat), lirCtr, tsShow(lirTime, false, timeformat));
+    printf("L_Rq: %d\t%s\t%d\t%s\n", lrqCtr, tsShow(lrqTime, false, timeformat), lirqCtr, tsShow(lirqTime, false, timeformat));
+    printf("L_D: %d\t%s\t%d\t%s\n", ldCtr, tsShow(ldTime, false, timeformat), lidCtr, tsShow(lidTime, false, timeformat));
+    printf("L_C: %d\t%s\t%d\t%s\n", lcCtr, tsShow(lcTime, false, timeformat), licCtr, tsShow(licTime, false, timeformat));
+
+    printf("\nNorm Stats:\n");
+    printf("NormSq_R %d\t%s\n", normrCtr, tsShow(normrTime, false, timeformat));
+
+    printf("\nBasic Stats:\n");
+    printf("Mul: %d\t%s\n", mulCtr, tsShow(mulTime, false, timeformat));
+    printf("Add: %d\t%s\n", addCtr, tsShow(addTime, false, timeformat));
+
+    total = tsAdd(norrTime, tsAdd(crttime1, tsAdd(crtInvRqTime, tsAdd(crtCTime, tsAdd(crtInvCTime, tsAdd(gprTime, tsAdd(giprTime, tsAdd(gdrTime, tsAdd(gidrTime, tsAdd(gprqTime, tsAdd(giprqTime, tsAdd(gdrqTime, tsAdd(gidrqTime, tsAdd(gcrqTime, tsAdd(gccTime, tsAdd(lrTime, tsAdd(lirTime, tsAdd(lrqTime, tsAdd(lirqTime, tsAdd(ldTime, tsAdd(lidTime, tsAdd(lcTime, tsAdd(licTime, tsAdd(mulTime,addTime))))))))))))))))))))))));
+
+    printf("\nTotal C Time: %s\n\n", tsShow(total, false, timeformat));
+
+    crtRqCtr = 0;
+    crtInvRqCtr = 0;
+    crtCCtr = 0;
+    crtInvCCtr = 0;
+
+    gprCtr = 0;
+    gpcCtr = 0;
+    gprqCtr = 0;
+    gdrCtr = 0;
+    gdrqCtr = 0;
+    giprCtr = 0;
+    gipcCtr = 0;
+    giprqCtr = 0;
+    gidrCtr = 0;
+    gidrqCtr = 0;
+    gcrqCtr = 0;
+    gccCtr = 0;
+    gicrqCtr = 0;
+    giccCtr = 0;
+
+    lrqCtr = 0;
+    lrCtr = 0;
+    ldCtr = 0;
+    lcCtr = 0;
+    lirqCtr = 0;
+    lirCtr = 0;
+    lidCtr = 0;
+    licCtr = 0;
+
+    normrCtr = 0;
+
+    mulCtr = 0;
+    addCtr = 0;
+
+    mulTime = (struct timespec){0,0};
+    addTime = (struct timespec){0,0};
+
+    lrqTime = (struct timespec){0,0};
+    lrTime = (struct timespec){0,0};
+    ldTime = (struct timespec){0,0};
+    lcTime = (struct timespec){0,0};
+    lirqTime = (struct timespec){0,0};
+    lirTime = (struct timespec){0,0};
+    lidTime = (struct timespec){0,0};
+    licTime = (struct timespec){0,0};
+
+    normrTime = (struct timespec){0,0};
+
+    gprTime = (struct timespec){0,0};
+    gpcTime = (struct timespec){0,0};
+    gprqTime = (struct timespec){0,0};
+    gdrTime = (struct timespec){0,0};
+    gdrqTime = (struct timespec){0,0};
+    giprTime = (struct timespec){0,0};
+    gipcTime = (struct timespec){0,0};
+    giprqTime = (struct timespec){0,0};
+    gidrTime = (struct timespec){0,0};
+    gidrqTime = (struct timespec){0,0};
+    gcrqTime = (struct timespec){0,0};
+    gccTime = (struct timespec){0,0};
+
+    crttime1 = (struct timespec){0,0};
+    crttime2 = (struct timespec){0,0};
+    crttime3 = (struct timespec){0,0};
+    crttime4 = (struct timespec){0,0};
+
+    crtInvRqTime = (struct timespec){0,0};
+    crtCTime = (struct timespec){0,0};
+    crtInvCTime = (struct timespec){0,0};
+#endif
+    fflush(stdout);
+}
+
+
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/l.c view
@@ -0,0 +1,434 @@+#include "tensorTypes.h"
+
+void lpRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset) {
+      hDim_t idx = tmp2 + modOffset + rts;
+      for (i = 1; i < p-1; ++i) {
+        hInt_t temp = y[(idx-rts)*tupSize] + y[idx*tupSize];
+        if (temp >= q) y[idx*tupSize]=temp-q;
+        else y[idx*tupSize] = temp;
+        idx += rts;
+      }
+    }
+  }
+}
+
+void lpR (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset) {
+      hDim_t idx = tmp2 + modOffset + rts;
+      for (i = 1; i < p-1; ++i) {
+        y[idx*tupSize] += y[(idx-rts)*tupSize];
+        idx += rts;
+      }
+    }
+  }
+}
+
+void lpDouble (double* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset) {
+      hDim_t idx = tmp2 + modOffset + rts;
+      for (i = 1; i < p-1; ++i) {
+        y[idx*tupSize] += y[(idx-rts)*tupSize];
+        idx += rts;
+      }
+    }
+  }
+}
+
+void lpC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++modOffset) {
+      hDim_t idx = tmp2 + modOffset + rts;
+      for (i = 1; i < p-1; ++i) {
+        CMPLX_IADD (y[idx*tupSize], y[(idx-rts)*tupSize]);
+        idx += rts;
+      }
+    }
+  }
+}
+
+void lpInvRq (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++ modOffset) {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hDim_t idx = tensorOffset + (p-2) * rts;
+      for (i = p-2; i != 0; --i) {
+        hInt_t temp = y[idx*tupSize] - y[(idx-rts)*tupSize] + q;
+        if (temp >= q) y[idx*tupSize]=temp-q;
+        else y[idx*tupSize] = temp;
+        idx -= rts;
+      }
+    }
+  }
+}
+
+void lpInvR (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++ modOffset) {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hDim_t idx = tensorOffset + (p-2) * rts;
+      for (i = p-2; i != 0; --i) {
+        y[idx*tupSize] -= y[(idx-rts)*tupSize] ;
+        idx -= rts;
+      }
+    }
+  }
+}
+
+void lpInvDouble (double* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++ modOffset) {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hDim_t idx = tensorOffset + (p-2) * rts;
+      for (i = p-2; i != 0; --i) {
+        y[idx*tupSize] -= y[(idx-rts)*tupSize] ;
+        idx -= rts;
+      }
+    }
+  }
+}
+
+void lpInvC (complex_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p) {
+  hDim_t blockOffset;
+  hDim_t modOffset;
+  int i;
+
+  hDim_t tmp1 = rts*(p-1);
+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
+    hDim_t tmp2 = blockOffset*tmp1;
+    for (modOffset = 0; modOffset < rts; ++ modOffset) {
+      hDim_t tensorOffset = tmp2 + modOffset;
+      hDim_t idx = tensorOffset + (p-2) * rts;
+      for (i = p-2; i != 0; --i) {
+        CMPLX_ISUB (y[idx*tupSize], y[(idx-rts)*tupSize]);
+        idx -= rts;
+      }
+    }
+  }
+}
+
+void ppLRq (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpRq (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, qs[tupIdx]);
+    }
+}
+
+void ppLR (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpR (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+    }
+}
+
+void ppLDouble (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpDouble (((double*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+    }
+}
+
+void ppLC (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpC (((complex_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+    }
+}
+
+
+void ppLInvRq (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpInvRq (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p, qs[tupIdx]);
+    }
+}
+
+void ppLInvR (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpInvR (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+    }
+}
+
+void ppLInvDouble (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpInvDouble (((double*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+    }
+}
+
+void ppLInvC (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {
+#ifdef DEBUG_MODE
+  ASSERT (q==0);
+#endif
+    hDim_t p = pe.prime;
+    hShort_t e = pe.exponent;
+    if(p == 2) return;
+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {
+      lpInvC (((complex_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);
+    }
+}
+
+#ifdef STATS
+int lrqCtr = 0;
+int lrCtr = 0;
+int ldCtr = 0;
+int lcCtr = 0;
+int lirqCtr = 0;
+int lirCtr = 0;
+int lidCtr = 0;
+int licCtr = 0;
+
+struct timespec lrqTime = {0,0};
+struct timespec lrTime = {0,0};
+struct timespec ldTime = {0,0};
+struct timespec lcTime = {0,0};
+struct timespec lirqTime = {0,0};
+struct timespec lirTime = {0,0};
+struct timespec lidTime = {0,0};
+struct timespec licTime = {0,0};
+#endif
+
+
+void tensorLRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs) {
+#ifdef STATS
+    lrqCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+#ifdef DEBUG_MODE
+    hDim_t i;
+    printf("\n\nEntered tensorLRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\tq=%" PRId64 "\n[", totm, sizeOfPE, q);
+    /*for(i = 0; i < totm; i++) {
+        printf("%" PRId64 ",", y[i]);
+    }*/
+    printf("]\n[");
+    for(i = 0; i < sizeOfPE; i++) {
+        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
+    }
+    printf("]\n");
+#endif
+  tensorFuser (y, tupSize, ppLRq, totm, peArr, sizeOfPE, qs); // don't need to shift here
+#ifdef DEBUG_MODE
+  for(i = 0; i < totm*tupSize; i++) {
+      if(y[i]<0) {
+          printf("tensorLRq\n");
+      }
+  }
+#endif
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    lrqTime = tsAdd(lrqTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorLR (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
+#ifdef STATS
+    lrCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+#ifdef DEBUG_MODE
+    printf("\n\nEntered tensorLR\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
+    hDim_t i;
+    for(i = 0; i < totm; i++) {
+        printf("%" PRId64 ",", y[i]);
+    }
+    printf("]\n[");
+    for(i = 0; i < sizeOfPE; i++) {
+        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
+    }
+    printf("]\n");
+#endif
+  tensorFuser (y, tupSize, ppLR, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    lrTime = tsAdd(lrTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorLDouble (hShort_t tupSize, double* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
+#ifdef STATS
+    ldCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+#ifdef DEBUG_MODE
+    printf("\n\nEntered tensorLDouble\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
+    hDim_t i;
+    for(i = 0; i < totm; i++) {
+        printf("%f,", y[i]);
+    }
+    printf("]\n[");
+    for(i = 0; i < sizeOfPE; i++) {
+        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
+    }
+    printf("]\n");
+#endif
+  tensorFuser (y, tupSize, ppLDouble, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    ldTime = tsAdd(ldTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorLC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
+#ifdef STATS
+    lcCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+#ifdef DEBUG_MODE
+    printf("\n\nEntered tensorLC\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
+    hDim_t i;
+    for(i = 0; i < totm; i++) {
+        printf("(%f,%f),", y[i].real, y[i].imag);
+    }
+    printf("]\n[");
+    for(i = 0; i < sizeOfPE; i++) {
+        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
+    }
+    printf("]\n");
+#endif
+  tensorFuser (y, tupSize, ppLC, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    lcTime = tsAdd(lcTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorLInvRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs) {
+#ifdef STATS
+    lirqCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppLInvRq, totm, peArr, sizeOfPE, qs);
+#ifdef DEBUG_MODE
+  hDim_t i;
+  for(i = 0; i < totm*tupSize; i++)
+  {
+      if(y[i]<0)
+      {
+          printf("tensorLInvRq\n");
+      }
+  }
+#endif
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    lirqTime = tsAdd(lirqTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorLInvR (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
+#ifdef STATS
+    lirCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppLInvR, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    lirTime = tsAdd(lirTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorLInvDouble (hShort_t tupSize, double* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
+#ifdef STATS
+    lidCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppLInvDouble, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    lidTime = tsAdd(lidTime, tsSubtract(t1,s1));
+#endif
+}
+
+void tensorLInvC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
+#ifdef STATS
+    licCtr++;
+    struct timespec s1,t1;
+    clock_gettime(CLOCK_REALTIME, &s1);
+#endif
+  tensorFuser (y, tupSize, ppLInvC, totm, peArr, sizeOfPE, (hInt_t*)0);
+#ifdef STATS
+    clock_gettime(CLOCK_REALTIME, &t1);
+    licTime = tsAdd(licTime, tsSubtract(t1,s1));
+#endif
+}
+
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/norm.c view
@@ -0,0 +1,86 @@+#include "tensorTypes.h"++#ifdef STATS+int normrCtr = 0;+struct timespec normrTime = {0,0};+#endif++void pNormSqR (hInt_t* y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p) {+  hDim_t blockOffset;+  hDim_t modOffset;+  hDim_t i;++  if(p==2) {+    return;+  }++  hDim_t tmp1 = rts*(p-1);+  for (blockOffset = 0; blockOffset < lts; ++blockOffset) {+    hDim_t tmp2 = blockOffset*tmp1;+    for (modOffset = 0; modOffset < rts; ++modOffset) {+      hDim_t tensorOffset = tmp2 + modOffset;+      hInt_t sum = 0;+      for (i = 0; i < p-1; ++i) {+        sum += y[(tensorOffset + i*rts)*tupSize];+      }+      for (i = 0; i < p-1; ++i) {+        y[(tensorOffset + i*rts)*tupSize] += sum;+      }+    }+  }+}++void ppNormSqR (void* y, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs) {+#ifdef DEBUG_MODE+  ASSERT (q==0);+#endif+    hDim_t p = pe.prime;+    hShort_t e = pe.exponent;+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+      pNormSqR (((hInt_t*)y)+tupIdx, tupSize, lts*ipow(p,e-1), rts, p);+    }+}++void tensorNormSqR (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {+#ifdef STATS+    normrCtr++;+    struct timespec s1,t1;+    clock_gettime(CLOCK_REALTIME, &s1);+#endif+#ifdef DEBUG_MODE+    printf("\n\nEntered tensorNormSqR\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);+    hDim_t i;+    for(i = 0; i < totm; i++) {+        printf("%" PRId64 ",", y[i]);+    }+    printf("]\n[");+    for(i = 0; i < sizeOfPE; i++) {+        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);+    }+    printf("]\n");+#endif++  hInt_t* tempSpace = (hInt_t*)malloc(totm*tupSize*sizeof(hInt_t));+  for(hDim_t i = 0; i < totm*tupSize; i++) {+    tempSpace[i]=y[i];+  }++  tensorFuser(y, tupSize, ppNormSqR, totm, peArr, sizeOfPE, (hInt_t*)0);++  //do dot product and return in index 0+  for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+    hInt_t dotprod = 0;+    for(hDim_t i = 0; i < totm; i++) {+      dotprod += (tempSpace[i*tupSize+tupIdx]*y[i*tupSize+tupIdx]);+    }++    y[tupIdx] = dotprod;+  }++  free(tempSpace);++#ifdef STATS+    clock_gettime(CLOCK_REALTIME, &t1);+    lrTime = tsAdd(normrTime, tsSubtract(t1,s1));+#endif+}
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/random.c view
@@ -0,0 +1,74 @@++#include <math.h>+#include <stdlib.h>+#include "tensorTypes.h"++// this function takes *inverse* RUs, so no negation is needed on the indexing+// I had been negating the ru-idx, but this was causing a *negative* mod, resulting in a hard-to-find bug+void primeD (double *y, hShort_t tupSize, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ruinv)+{+	if(p == 2)+  {+      return;+  }+  hDim_t blockOffset, modOffset, tensorOffset;+	double *tempSpace = (double*)malloc((p-1)*sizeof(double));+  hDim_t temp1 = rts*(p-1);+  for(blockOffset = 0; blockOffset < lts; blockOffset++)+  {+    hDim_t temp2 = blockOffset*temp1;+    for(modOffset = 0; modOffset < rts; modOffset++)+    {+      tensorOffset = temp2 + modOffset;+      hDim_t row, col;+      +      for(row = 0; row < p-1; row++)+      {+        double acc = 0;+        for(col = 1; col <= (p>>1); col++)+        {+          acc += 2 * ruinv[((row*col) % p)*rustride*tupSize].real * y[(tensorOffset+rts*(col-1))*tupSize];+        }+        for(col = (p>>1)+1; col <= p-1; col++)+        {+          acc += 2 * ruinv[((row*col) % p)*rustride*tupSize].imag * y[(tensorOffset+rts*(col-1))*tupSize];+        }+        tempSpace[row] = acc/sqrt(2);+      }+      +      for(row = 0; row < p-1; row++)+      {+        y[(tensorOffset+rts*row)*tupSize] = tempSpace[row];+      }+    }+  }+  free(tempSpace);+}++void ppD (void *y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, void *ruinv, hInt_t* qs)+{+    hDim_t p = pe.prime;+    hDim_t e = pe.exponent;+#ifdef DEBUG_MODE+    ASSERT(e != 0);+#endif+    hDim_t mprime = ipow(p,e-1);+    for(int tupIdx = 0; tupIdx < tupSize; tupIdx++) {+      primeD (((double*)y)+tupIdx, tupSize, lts*mprime, rts, p, mprime, ((complex_t*)ruinv)+tupIdx);+    }+}++//the contents of y will be destroyed, but should be initialized in Haskell-land to independent Guassians over the reals+void tensorGaussianDec (hShort_t tupSize, double *y, hDim_t totm, PrimeExponent *peArr, hShort_t sizeOfPE, complex_t** ruinv)+{+  void** ruinvs = (void**)malloc(sizeOfPE*sizeof(void*));+  hShort_t i;+  for(i = 0; i < sizeOfPE; i++)+  {+      ruinvs[i] = (void*) (ruinv[i]);+  }+    +	tensorFuserCRT (y, tupSize, ppD, totm, peArr, sizeOfPE, ruinvs, (hInt_t*)0);+	+	free(ruinvs);+}
+ Crypto/Lol/Cyclotomic/Tensor/CTensor/tensorTypes.h view
@@ -0,0 +1,231 @@+
+#ifndef TENSORTYPES_H_
+#define TENSORTYPES_H_
+
+
+// remove next line for more efficient code
+//#define DEBUG_MODE
+
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+#define ASSERT(EXP) { \
+	if (!(EXP)) { \
+		fprintf (stderr, "Assertion in file '%s' line %d : " #EXP "  is false\n", __FILE__, __LINE__); \
+		exit(-1); \
+	} \
+}
+
+
+//timers and counters
+#ifdef STATS
+extern int crtRqCtr;
+extern int crtInvRqCtr;
+extern int crtCCtr;
+extern int crtInvCCtr;
+
+extern int gprCtr;
+extern int gpcCtr;
+extern int gprqCtr;
+extern int gdrCtr;
+extern int gdrqCtr;
+extern int giprCtr;
+extern int gipcCtr;
+extern int giprqCtr;
+extern int gidrCtr;
+extern int gidrqCtr;
+extern int gcrqCtr;
+extern int gccCtr;
+extern int gicrqCtr;
+extern int giccCtr;
+
+extern int lrqCtr;
+extern int lrCtr;
+extern int ldCtr;
+extern int lcCtr;
+extern int lirqCtr;
+extern int lirCtr;
+extern int lidCtr;
+extern int licCtr;
+
+extern int normrCtr;
+
+extern int mulCtr;
+extern struct timespec mulTime;
+extern int addCtr;
+extern struct timespec addTime;
+
+extern struct timespec lrqTime;
+extern struct timespec lrTime;
+extern struct timespec ldTime;
+extern struct timespec lcTime;
+extern struct timespec lirqTime;
+extern struct timespec lirTime;
+extern struct timespec lidTime;
+extern struct timespec licTime;
+
+extern struct timespec normrTime;
+
+extern struct timespec crttime1;
+extern struct timespec crttime2;
+extern struct timespec crttime3;
+extern struct timespec crttime4;
+extern struct timespec crtInvRqTime;
+extern struct timespec crtCTime;
+extern struct timespec crtInvCTime;
+
+extern struct timespec gprTime;
+extern struct timespec gpcTime;
+extern struct timespec gprqTime;
+extern struct timespec gdrTime;
+extern struct timespec gdrqTime;
+extern struct timespec giprTime;
+extern struct timespec gipcTime;
+extern struct timespec giprqTime;
+extern struct timespec gidrTime;
+extern struct timespec gidrqTime;
+extern struct timespec gcrqTime;
+extern struct timespec gccTime;
+#endif
+
+typedef int64_t hInt_t ;
+typedef int32_t hDim_t ;
+typedef int16_t hShort_t ;
+typedef int8_t hByte_t ;
+
+typedef struct
+{
+	hDim_t prime;
+	hShort_t exponent;
+}  PrimeExponent;
+
+
+typedef struct
+{
+	double real;
+	double imag;
+} complex_t;
+
+#define CMPLX_ADD(a,b)  ((complex_t){((a).real + (b).real), ((a).imag + (b).imag)})
+#define CMPLX_ADD3(a,b,c)  ((complex_t){((a).real + (b).real + (c).real), ((a).imag + (b).imag + (c).imag)})
+#define CMPLX_ADD4(a,b,c,d)  ((complex_t){((a).real + (b).real + (c).real + (d).real), ((a).imag + (b).imag + (c).imag + (d).imag)})
+#define CMPLX_ADD5(a,b,c,d,e)  ((complex_t){((a).real + (b).real + (c).real + (d).real + (e).real), ((a).imag + (b).imag + (c).imag + (d).imag + (e).imag)})
+#define CMPLX_ADD6(a,b,c,d,e,f)  ((complex_t){((a).real + (b).real + (c).real + (d).real + (e).real + (f).real), ((a).imag + (b).imag + (c).imag + (d).imag + (e).imag + (f).imag)})
+#define CMPLX_ADD7(a,b,c,d,e,f,g)  ((complex_t){((a).real + (b).real + (c).real + (d).real + (e).real + (f).real + (g).real), ((a).imag + (b).imag + (c).imag + (d).imag + (e).imag + (f).imag + (g).imag)})
+
+#define CMPLX_SUB(a,b)  ((complex_t){((a).real - (b).real), ((a).imag - (b).imag)})
+#define CMPLX_MUL(a,b)  ((complex_t){((a).real*(b).real - (a).imag*(b).imag), \
+	                                  (a).real*(b).imag + (a).imag*(b).real})
+#define CMPLX_DIV(a,b)  ((complex_t){((a).real*(b).real + (a).imag*(b).imag)/((b).real*(b).real+(b).imag*(b).imag), \
+                                     ((a).imag*(b).real - (a).real*(b).imag)/((b).real*(b).real+(b).imag*(b).imag)})
+
+// 'inside' operators
+#define CMPLX_IADD(a,b)  { (a).real += (b).real;  (a).imag += (b).imag; }
+#define CMPLX_ISUB(a,b)  { (a).real -= (b).real;  (a).imag -= (b).imag; }
+#define CMPLX_IMUL(a,b)  { double temp = ((a).real*(b).real - (a).imag*(b).imag); \
+	                       (a).imag = ((a).real*(b).imag + (a).imag*(b).real); \
+	                       (a).real = temp; }
+
+// calculates base ** exp
+hDim_t ipow(hDim_t base, hShort_t exp);
+complex_t cmplxpow(complex_t base, hShort_t exp);
+hInt_t qpow(hInt_t base, hShort_t exp, hInt_t q);
+
+hInt_t reciprocal (hInt_t a, hInt_t b);
+
+struct  timespec  tsSubtract (struct  timespec  time1, struct  timespec  time2);
+struct  timespec  tsAdd (struct  timespec  time1, struct  timespec  time2);
+const  char  *tsShow (struct  timespec  binaryTime, bool  inLocal, const  char  *format);
+
+void getStats();
+
+void mulRq (hShort_t tupSize, hInt_t* a, hInt_t* b, hDim_t totm, hInt_t* qs);
+//void mulMq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q);
+void mulC (hShort_t tupSize, complex_t* a, complex_t* b, hDim_t totm);
+
+void addR (hShort_t tupSize, hInt_t* a, hInt_t* b, hDim_t totm);
+void addRq (hShort_t tupSize, hInt_t* a, const hInt_t* b, const hDim_t totm, const hInt_t* qs);
+//void addMq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q);
+void addC (hShort_t tupSize, complex_t* a, complex_t* b, hDim_t totm);
+void addD (hShort_t tupSize, double* a, double* b, hDim_t totm);
+
+typedef void (*funcPtr) (void* outputVec, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* qs);
+void tensorFuser (void* y, hShort_t tupSize, funcPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs);
+
+typedef void (*normFuncPtr) (void* outputVec, hShort_t tupSize, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t* output, hInt_t* qs);
+void tensorFuserNorm (void* y, hShort_t tupSize, normFuncPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* output, hInt_t q);
+
+typedef void (*crtFuncPtr) (void* y, hShort_t tupSize, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t* q);
+void tensorFuserCRT (void* y, hShort_t tupSize, crtFuncPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, void** ru, hInt_t* q);
+
+void tensorGPowR (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorGPowRq (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs);
+
+void tensorGPowC (hShort_t tupSize, complex_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorGDecR (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorGDecRq (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs);
+
+void tensorGInvPowR (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorGInvPowRq (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs);
+
+void tensorGInvPowC (hShort_t tupSize, complex_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorGInvDecR (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorGInvDecRq (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs);
+
+void tensorGCRTRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t* qs);
+
+void tensorGInvCRTRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t* qs);
+
+void tensorGCRTC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs);
+
+void tensorGInvCRTC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs);
+
+
+
+void tensorLRq (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs);
+
+void tensorLR (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorLDouble (hShort_t tupSize, double* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorLC (hShort_t tupSize, complex_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorLInvRq (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t* qs);
+
+void tensorLInvR (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorLInvDouble (hShort_t tupSize, double* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+void tensorLInvC (hShort_t tupSize, complex_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+
+
+void tensorCRTRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** ru, hInt_t* qs);
+
+void tensorCRTC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru);
+
+void tensorCRTInvRq (hShort_t tupSize, hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** ru, hInt_t* minv, hInt_t* qs);
+
+void tensorCRTInvC (hShort_t tupSize, complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru, complex_t* minv);
+
+
+
+void tensorGaussianDec (hShort_t tupSize, double* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru);
+
+void tensorNormSqR (hShort_t tupSize, hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
+
+
+#endif /* TENSORTYPES_H_ */
+
+ Crypto/Lol/Cyclotomic/Tensor/RepaTensor.hs view
@@ -0,0 +1,258 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, GADTs, MultiParamTypeClasses,+             NoImplicitPrelude, PolyKinds, RebindableSyntax,+             RoleAnnotations, ScopedTypeVariables, StandaloneDeriving,+             TypeFamilies, TypeOperators, UndecidableInstances #-}++-- | A pure, repa-based implementation of the Tensor interface.++module Crypto.Lol.Cyclotomic.Tensor.RepaTensor+( RT ) where++import Crypto.Lol.Cyclotomic.Tensor                      as T+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.CRT+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Dec+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Extension+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.GL+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon  as RT+import Crypto.Lol.LatticePrelude                         as LP hiding+                                                                ((!!))+import Crypto.Lol.Reflects+import Crypto.Lol.Types.FiniteField                      as FF+import Crypto.Lol.Types.IZipVector++import Algebra.Additive     as Additive (C)+import Algebra.Module       as Module (C)+import Algebra.ZeroTestable as ZeroTestable (C)++import Control.Applicative  hiding ((*>))+import Control.Arrow        hiding (arr)+import Control.DeepSeq      (NFData (rnf))+import Control.Monad.Random+import Data.Coerce+import Data.Constraint      hiding ((***))+import Data.Foldable        as F+import Data.Maybe+import Data.Traversable     as T+import Data.Vector          as V hiding (force)+import Data.Vector.Unboxed  as U hiding (force)+import Test.QuickCheck++-- | An implementation of 'Tensor' backed by repa.+data RT (m :: Factored) r where+  RT :: Unbox r => !(Arr m r) -> RT m r+  ZV :: IZipVector m r -> RT m r++deriving instance Show r => Show (RT m r)++instance Eq r => Eq (RT m r) where+  (ZV a) == (ZV b) = a == b+  (RT a) == (RT b) = a == b+  a@(RT _) == b = a == toRT b+  a == b@(RT _) = toRT a == b+  {-# INLINABLE (==) #-}++zvToArr :: Unbox r => IZipVector m r -> Arr m r+zvToArr v = let vec = convert $ unIZipVector v+            in Arr $ fromUnboxed (Z :. U.length vec) vec++-- converts to RT constructor+toRT :: Unbox r => RT m r -> RT m r+toRT v@(RT _) = v+toRT (ZV v) = RT $ zvToArr v++toZV :: Fact m => RT m r -> RT m r+toZV (RT (Arr v)) = ZV $ fromMaybe (error "toZV: internal error") $+                    iZipVector $ convert $ toUnboxed v+toZV v@(ZV _) = v++{-# INLINABLE wrap #-}+wrap :: Unbox r => (Arr l r -> Arr m r) -> RT l r -> RT m r+wrap f (RT v) = RT $ f v+wrap f (ZV v) = RT $ f $ zvToArr v++{-# INLINABLE wrapM #-}+wrapM :: (Unbox r, Monad mon) => (Arr l r -> mon (Arr m r))+         -> RT l r -> mon (RT m r)+wrapM f (RT v) = RT <$> f v+wrapM f (ZV v) = RT <$> f (zvToArr v)++instance Tensor RT where++  type TElt RT r = (Unbox r, Elt r)++  entailIndexT  = tag $ Sub Dict+  entailEqT     = tag $ Sub Dict+  entailZTT     = tag $ Sub Dict+  --entailRingT   = tag $ Sub Dict+  entailNFDataT = tag $ Sub Dict+  entailRandomT = tag $ Sub Dict+  entailShowT   = tag $ Sub Dict+  entailModuleT = tag $ Sub Dict++  scalarPow = RT . scalarPow'++  l = wrap fL+  lInv = wrap fLInv++  mulGPow = wrap fGPow+  mulGDec = wrap fGDec++  divGPow = wrapM fGInvPow+  divGDec = wrapM fGInvDec++  crtFuncs = (,,,,) <$>+             ((RT .) <$> scalarCRT') <*>+             (wrap <$> mulGCRT') <*>+             (wrap <$> divGCRT') <*>+             (wrap <$> fCRT) <*>+             (wrap <$> fCRTInv)++  tGaussianDec = fmap RT . tGaussianDec'++  gSqNormDec (RT e) = gSqNormDec' e+  gSqNormDec e = gSqNormDec $ toRT e++  twacePowDec = wrap twacePowDec'++  embedPow = wrap embedPow'+  embedDec = wrap embedDec'++  crtExtFuncs = (,) <$> (wrap <$> twaceCRT') <*> (wrap <$> embedCRT')++  coeffs = wrapM coeffs'++  powBasisPow = (RT <$>) <$> powBasisPow'++  crtSetDec = (RT <$>) <$> crtSetDec'++  fmapT f (RT v) = RT $ (coerce $ force . RT.map f) v+  fmapT f v@(ZV _) = fmapT f $ toRT v++  -- Repa arrays don't have mapM, so apply to underlying Unboxed+  -- vector instead+  fmapTM f (RT (Arr arr)) = (RT . Arr . fromUnboxed (extent arr)) <$>+                            U.mapM f (toUnboxed arr)+  fmapTM f v = fmapTM f $ toRT v++  zipWithT f (RT (Arr a1)) (RT (Arr a2)) = RT $ Arr $ force $ RT.zipWith f a1 a2+  zipWithT f v1 v2 = zipWithT f (toRT v1) (toRT v2)++  unzipTElt (RT (Arr arr)) = (RT . Arr . fromUnboxed (extent arr)) ***+                             (RT . Arr . fromUnboxed (extent arr)) $+                             U.unzip $ toUnboxed arr+  unzipTElt v = unzipTElt $ toRT v++  unzipT v@(RT _) = unzipT $ toZV v+  unzipT (ZV v) = ZV *** ZV $ unzipIZV v++  {-# INLINABLE entailIndexT #-}+  {-# INLINABLE entailEqT #-}+  {-# INLINABLE entailZTT #-}+  {-# INLINABLE entailNFDataT #-}+  {-# INLINABLE entailRandomT #-}+  {-# INLINABLE entailShowT #-}+  {-# INLINABLE scalarPow #-}+  {-# INLINABLE l #-}+  {-# INLINABLE lInv #-}+  {-# INLINABLE mulGPow #-}+  {-# INLINABLE mulGDec #-}+  {-# INLINABLE divGPow #-}+  {-# INLINABLE divGDec #-}+  {-# INLINABLE crtFuncs #-}+  {-# INLINABLE twacePowDec #-}+  {-# INLINABLE embedPow #-}+  {-# INLINABLE embedDec #-}+  {-# INLINABLE tGaussianDec #-}+  {-# INLINABLE gSqNormDec #-}+  {-# INLINABLE crtExtFuncs #-}+  {-# INLINABLE coeffs #-}+  {-# INLINABLE powBasisPow #-}+  {-# INLINABLE crtSetDec #-}+  {-# INLINABLE fmapT #-}+  {-# INLINABLE fmapTM #-}+  {-# INLINABLE zipWithT #-}+  {-# INLINABLE unzipTElt #-}+  {-# INLINABLE unzipT #-}+++---------- Category-theoretic instances ----------++instance Fact m => Functor (RT m) where+  -- Functor instance is implied by Applicative+  fmap f x = pure f <*> x++instance Fact m => Applicative (RT m) where+  pure = ZV . pure++  -- RT can never hold an a -> b+  (ZV f) <*> (ZV a) = ZV (f <*> a)+  f@(ZV _) <*> v@(RT _) = f <*> toZV v++instance Fact m => Foldable (RT m) where+  -- Foldable instance is implied by Traversable+  foldMap = foldMapDefault++instance Fact m => Traversable (RT m) where+  traverse f r@(RT _) = T.traverse f $ toZV r+  traverse f (ZV v) = ZV <$> T.traverse f v+++---------- Numeric Prelude instances ----------++--CJP: Additive, Ring are not necessary when we use zipWithT+--EAC: But we need an Additive instance for the Module instance++instance (Unbox r, Additive (Arr m r)) => Additive.C (RT m r) where+  zero = RT zero++  (RT a) + (RT b) = RT $ a + b+  a + b = toRT a + toRT b++  (RT a) - (RT b) = RT $ a - b+  a - b = toRT a - toRT b++  negate (RT a) = RT $ negate a+  negate a = negate $ toRT a++  {-# INLINABLE (+) #-}+  {-# INLINABLE (-) #-}+  {-# INLINABLE zero #-}+  {-# INLINABLE negate #-}++{-+instance (Unbox r, Ring (Arr m r)) => Ring.C (RT m r) where+  (RT a) * (RT b) = RT $ a * b+  a * b = toRT a * toRT b++  fromInteger = RT . fromInteger+  {-# INLINABLE (*) #-}+  {-# INLINABLE fromInteger #-}+-}++instance (ZeroTestable (Arr m r), ZeroTestable (IZipVector m r))+    => ZeroTestable.C (RT m r) where+  isZero (RT a) = isZero a+  isZero (ZV v) = isZero v+  {-# INLINABLE isZero #-}++instance (GFCtx fp d, Fact m, Additive (RT m fp))+    => Module.C (GF fp d) (RT m fp) where++  r *> v = case v of+    RT (Arr arr) -> RT $ Arr $ RT.fromList (extent arr) $ unCoeffs $ r *> Coeffs $ RT.toList arr+    ZV zv -> ZV $ fromJust $ iZipVector $ V.fromList $ unCoeffs $ r *> Coeffs $ V.toList $ unIZipVector zv++---------- Miscellaneous instances ----------++instance (Unbox r, Random (Arr m r)) => Random (RT m r) where+  random = runRand $ RT <$> (liftRand random)++  randomR = error "randomR nonsensical for RT"++instance (Unbox r, Arbitrary (Arr m r)) => Arbitrary (RT m r) where+  arbitrary = RT <$> arbitrary++instance (NFData r) => NFData (RT m r) where+  rnf (RT v) = rnf v+  rnf (ZV v) = rnf v
+ Crypto/Lol/Cyclotomic/Tensor/RepaTensor/CRT.hs view
@@ -0,0 +1,215 @@+{-# LANGUAGE ConstraintKinds, FlexibleContexts, GADTs, NoImplicitPrelude,+             ScopedTypeVariables #-}++-- | Functions to support the chinese remainder transform on Repa arrays++module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.CRT+( scalarCRT'+, fCRT, fCRTInv+, mulGCRT', divGCRT'+, gCRT, gInvCRT+) where++import Crypto.Lol.CRTrans+import Crypto.Lol.Cyclotomic.Tensor+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.GL+import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon as RT+import Crypto.Lol.LatticePrelude                        as LP++import Control.Applicative+import Data.Coerce+import Data.Singletons.Prelude++-- | Embeds a scalar into the CRT basis (when it exists).+scalarCRT' :: forall m r . (Fact m, CRTrans r, Unbox r)+              => Maybe (r -> Arr m r)+{-# INLINABLE scalarCRT' #-}+scalarCRT'+  = let pps = proxy ppsFact (Proxy::Proxy m)+        sz = Z :. totientPPs pps+    in pure $ Arr . force . fromFunction sz . const++-- | Multiply by @g_m@ in the CRT basis (when it exists).+mulGCRT' :: forall m r . (Fact m, CRTrans r, Unbox r, Elt r)+            => Maybe (Arr m r -> Arr  m r)+{-# INLINABLE mulGCRT' #-}+mulGCRT' = (coerce (\x -> force . RT.zipWith (*) x) `asTypeOf` asTypeOf) <$> gCRT++-- | Divide by @g@ in the CRT basis (when it exists).+divGCRT' :: (Fact m, CRTrans r, IntegralDomain r, ZeroTestable r,+             Unbox r, Elt r) => Maybe (Arr m r -> Arr m r)+{-# INLINABLE divGCRT' #-}+divGCRT' =  (coerce (\x -> force . RT.zipWith (*) x) `asTypeOf` asTypeOf) <$> gInvCRT++-- | The representation of @g@ in the CRT basis (when it exists).+gCRT :: (Fact m, CRTrans r, Unbox r, Elt r) => Maybe (Arr m r)+{-# INLINABLE gCRT #-}+gCRT = fCRT <*> pure (fGPow $ scalarPow' LP.one)++-- | The representation of @g^{ -1 }@ in the CRT basis (when it exists).+gInvCRT:: (Fact m, CRTrans r, IntegralDomain r,+           ZeroTestable r, Unbox r, Elt r)+          => Maybe (Arr m r)+{-# INLINABLE gInvCRT #-}+gInvCRT = fCRT <*> fGInvPow (scalarPow' LP.one)++fCRT, fCRTInv ::+  forall m r . (Fact m, CRTrans r, Unbox r, Elt r)+  => Maybe (Arr m r -> Arr m r)++{-# INLINABLE fCRT #-}+{-# INLINABLE fCRTInv #-}++-- | The chinese remainder transform.+-- Exists if and only if crt exists for all prime powers.+fCRT = evalM $ fTensor ppCRT++-- divide by mhat after doing crtInv'+-- | The inverse chinese remainder transform.+-- Exists if and only if crt exists for all prime powers.+fCRTInv = do -- in Maybe+  (_, mhatInv) :: (CRTInfo r) <- proxyT crtInfoFact (Proxy :: Proxy m)+  let totm = proxy totientFact (Proxy :: Proxy m)+      divMhat = trans totm $ RT.map (*mhatInv)+  evalM $ (divMhat .*) <$> fTensor ppCRTInv'++ppDFT, ppDFTInv', ppCRT, ppCRTInv' ::+  forall pp r . (PPow pp, CRTrans r, Unbox r, Elt r)+  => TaggedT pp Maybe (Trans r)++{-# INLINABLE ppDFT #-}+{-# INLINABLE ppDFTInv' #-}+{-# INLINABLE ppCRT #-}+{-# INLINABLE ppCRTInv' #-}++ppDFT = case (sing :: SPrimePower pp) of+  (SPP (STuple2 sp SO)) -> tagT $ withWitnessT pDFT sp+  spp@(SPP (STuple2 sp (SS se'))) ->+    tagT $ do+      let spp' = SPP (STuple2 sp se')+      pp'dft <- withWitnessT ppDFT spp'+      pptwid <- withWitnessT (ppTwid False) spp+      pdft <- withWitnessT pDFT sp+      return $ (pp'dft @* Id (dim pdft)) .* pptwid .* (Id (dim pp'dft) @* pdft)++ppDFTInv' = case (sing :: SPrimePower pp) of+  (SPP (STuple2 sp SO)) -> tagT $ withWitnessT pDFTInv' sp+  spp@(SPP (STuple2 sp (SS se'))) ->+    tagT $ do+      let spp' = SPP (STuple2 sp se')+      pp'dftInv' <- withWitnessT ppDFTInv' spp'+      pptwidInv <- withWitnessT (ppTwid True) spp+      pdftInv' <- withWitnessT pDFTInv' sp+      return $ (Id (dim pp'dftInv') @* pdftInv') .* pptwidInv .*+                 (pp'dftInv' @* Id (dim pdftInv'))++ppCRT = case (sing :: SPrimePower pp) of+  (SPP (STuple2 sp SO)) -> tagT $ withWitnessT pCRT sp+  spp@(SPP (STuple2 sp (SS se'))) ->+    tagT $ do+      let spp' = SPP (STuple2 sp se')+      pp'dft <- withWitnessT ppDFT spp'+      pptwid <- withWitnessT (ppTwidHat False) spp+      pcrt <- withWitnessT pCRT sp+      return $+        (pp'dft @* Id (dim pcrt)) .* pptwid .*+        -- save some work when p=2+        (if dim pcrt > 1 then Id (dim pp'dft) @* pcrt else Id (dim pp'dft))++ppCRTInv' = case (sing :: SPrimePower pp) of+  (SPP (STuple2 sp SO)) -> tagT $ withWitnessT pCRTInv' sp+  spp@(SPP (STuple2 sp (SS se'))) ->+    tagT $ do+      let spp' = SPP (STuple2 sp se')+      pp'dftInv' <- withWitnessT ppDFTInv' spp'+      pptwidInv <- withWitnessT (ppTwidHat True) spp+      pcrtInv' <- withWitnessT pCRTInv' sp+      return $+        (Id (dim pp'dftInv') @* pcrtInv') .* pptwidInv .*+        (pp'dftInv' @* Id (dim pcrtInv'))++butterfly :: (Additive r, Unbox r, Elt r) => Trans r+butterfly = trans 2 $ \arr ->+            fromFunction (extent arr) $+                             \(sh:.j) -> case j of+                                           0 -> arr ! (sh:.0) ++                                                arr ! (sh:.1)+                                           1 -> arr ! (sh:.0) -+                                                arr ! (sh:.1)++-- DFT_p, CRT_p, scaled DFT_p^{ -1 } and CRT_p^{ -1 }+pDFT, pDFTInv', pCRT, pCRTInv' ::+  forall p r . (Prim p, CRTrans r, Unbox r, Elt r)+  => TaggedT p Maybe (Trans r)++{-# INLINABLE pDFT #-}+{-# INLINABLE pDFTInv' #-}+{-# INLINABLE pCRT #-}+{-# INLINABLE pCRTInv' #-}++pDFT = let pval = proxy valuePrime (Proxy::Proxy p)+       in if pval == 2+          then return butterfly+          else do (omegaPPow, _) <- crtInfoPrime+                  return $ trans pval $ mulMat $ force $+                         fromFunction (Z :. pval :. pval)+                                          (\(Z:.i:.j) -> omegaPPow (i*j))++pDFTInv' = let pval = proxy valuePrime (Proxy::Proxy p)+           in if pval == 2+              then return butterfly+              else do (omegaPPow, _) <- crtInfoPrime+                      return $ trans pval $ mulMat $ force $+                             fromFunction (Z :. pval :. pval)+                                              (\(Z:.i:.j) -> omegaPPow (-i*j))++pCRT = let pval = proxy valuePrime (Proxy::Proxy p)+       in if pval == 2+          then return $ Id 1+          else do (omegaPPow, _) <- crtInfoPrime+                  return $ trans (pval-1) $ mulMat $ force $+                         fromFunction (Z :. pval-1 :. pval-1)+                                          (\(Z:.i:.j) -> omegaPPow ((i+1)*j))++-- crt_p * this = \hat{p}*I, for all prime p.+pCRTInv' =+  let pval = proxy valuePrime (Proxy::Proxy p)+  in if pval == 2 then return $ Id 1+     else do+       (omegaPPow, _) <- crtInfoPrime+       return $ trans (pval-1) $  mulMat $ force $+              fromFunction (Z :. pval-1 :. pval-1)+                               (\(Z:.i:.j) -> omegaPPow (negate i*(j+1)) -+                                              omegaPPow (j+1))++-- twiddle factors for DFT_pp and CRT_pp decompositions+ppTwid, ppTwidHat ::+  forall pp r . (PPow pp, CRTrans r, Unbox r, Elt r)+  => Bool -> TaggedT pp Maybe (Trans r)++{-# INLINABLE ppTwid #-}+{-# INLINABLE ppTwidHat #-}++ppTwid inv =+  let pp@(p,e) = proxy ppPPow (Proxy :: Proxy pp)+      ppval = valuePP pp+  in do+    (omegaPPPow, _) <- crtInfoPPow+    return $ trans ppval $ mulDiag $ force $+                           fromFunction (Z :. ppval)+                           (\(Z:.i) -> let (iq,ir) = i `divMod` p+                                           pow = (if inv then negate else id)+                                                 ir * digitRev (p,e-1) iq+                                       in omegaPPPow pow)++ppTwidHat inv =+  let pp@(p,e) = proxy ppPPow (Proxy :: Proxy pp)+      pptot = totientPP pp+  in do+    (omegaPPPow, _) <- crtInfoPPow+    return $ trans pptot $ mulDiag $ force $+                           fromFunction (Z :. pptot)+                           (\(Z:.i) -> let (iq,ir) = i `divMod` (p-1)+                                           pow = (if inv then negate else id)+                                                 (ir+1) * digitRev (p,e-1) iq+                                       in omegaPPPow pow)
+ Crypto/Lol/Cyclotomic/Tensor/RepaTensor/Dec.hs view
@@ -0,0 +1,74 @@+{-# 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')++
+ Crypto/Lol/Cyclotomic/Tensor/RepaTensor/Extension.hs view
@@ -0,0 +1,193 @@+{-# LANGUAGE BangPatterns, ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, MultiParamTypeClasses, NoImplicitPrelude,+             PolyKinds, ScopedTypeVariables, TemplateHaskell, TypeFamilies,+             TypeOperators #-}++-- | RT-specific functions for embedding/twacing in various bases++module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Extension+( twacePowDec', twaceCRT', embedPow', embedDec', embedCRT'+, coeffs', powBasisPow', crtSetDec'+) where++import           Crypto.Lol.LatticePrelude              as LP hiding (lift, (!!))+import           Crypto.Lol.CRTrans+import           Crypto.Lol.Reflects+import qualified Crypto.Lol.Cyclotomic.Tensor                      as T+import           Crypto.Lol.Cyclotomic.Tensor.RepaTensor.CRT+import           Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon as RT+import           Crypto.Lol.Types.FiniteField+import           Crypto.Lol.Types.ZmStar++import Control.Applicative+import Control.Arrow       (first, (***))++import           Data.Coerce+import           Data.Default+import           Data.Maybe+import           Data.Reflection (reify)+import qualified Data.Vector                  as V+import qualified Data.Vector.Unboxed          as U+import           Data.Vector.Unboxed.Deriving++-- Default instances+instance Default Z where def = Z+instance (Default a, Default b) => Default (a:.b) where def = def:.def++-- derived Unbox instances+derivingUnbox "DIM1"+  [t| (Z:.Int) -> Int |]+  [| \(Z:.i) -> i |]+  [| (Z :.) |]++-- | 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 . (m `Divides` m', Unbox r)+                 => Arr m' r -> Arr m r+twacePowDec'+  = let indices = proxy extIndicesPowDec (Proxy::Proxy '(m, m'))+    in coerce $ \ !arr -> force $ backpermute (extent indices) (indices !) arr++-- | The "tweaked trace" function in the CRT+-- basis of the m'th cyclotomic ring to the mth cyclotomic ring when +-- @m | m'@.+twaceCRT' :: forall m m' r .+             (m `Divides` m', CRTrans r, IntegralDomain r,+              ZeroTestable r, Unbox r, Elt r)+             => Maybe (Arr m' r -> Arr m r)+twaceCRT' = do           -- Maybe monad+  g' :: Arr m' r <- gCRT+  gInv <- gInvCRT+  embed :: Arr m r -> Arr m' r <- embedCRT'+  (_, m'hatinv) <- proxyT crtInfoFact (Proxy::Proxy m')+  let hatRatioInv = m'hatinv * fromIntegral (proxy valueHatFact (Proxy::Proxy m))+      -- tweak = mhat * g' / (m'hat * g)+      tweak = (coerce $ \x -> force . RT.map (* hatRatioInv) . RT.zipWith (*) x) (embed gInv) g' :: Arr m' r+      indices = proxy extIndicesCRT (Proxy::Proxy '(m, m'))+  return $ +    -- take true trace after mul-by-tweak+    coerce (\ !arr -> sumS . backpermute (extent indices) (indices !) . RT.zipWith (*) arr) tweak++embedPow', embedDec' :: forall m m' r .+             (m `Divides` m', Unbox r, Additive r)+             => Arr m r -> Arr m' r+-- | Embeds an array in the powerful basis of the the mth cyclotomic ring+-- to an array in the powerful basis of the m'th cyclotomic ring when @m | m'@+embedPow'+  = let indices = proxy baseIndicesPow (Proxy::Proxy '(m, m'))+    in coerce $ \ !arr -> force $ fromFunction (extent indices)+                       (\idx -> let (j0,j1) = (indices ! idx)+                                in if j0 == 0 then arr ! j1 else zero)+-- | Embeds an array in the decoding basis of the the mth cyclotomic ring+-- to an array in the decoding basis of the m'th cyclotomic ring when @m | m'@+embedDec'+  = let indices = proxy baseIndicesDec (Proxy::Proxy '(m, m'))+    in coerce $ \ !arr -> force $+                       fromFunction (extent indices)+                         (\idx -> maybe zero+                                  (\(sh,b) -> if b then negate (arr ! sh)+                                              else arr ! sh)+                                  (indices ! idx))++-- | Embeds an array in the CRT basis of the the mth cyclotomic ring+-- to an array in the CRT basis of the m'th cyclotomic ring when @m | m'@+embedCRT' :: forall m m' r . (m `Divides` m', CRTrans r, Unbox r)+             => Maybe (Arr m r -> Arr m' r)+embedCRT' = do -- in Maybe+  -- first check existence of CRT transform of index m'+  proxyT crtInfoFact (Proxy::Proxy m') :: Maybe (CRTInfo r)+  let idxs = proxy baseIndicesCRT (Proxy::Proxy '(m,m'))+  return $ coerce $ \ !arr -> (force $ backpermute (extent idxs) (idxs !) arr)++-- | maps an array in the powerful/decoding basis, representing an+-- O_m' element, to an array of arrays representing O_m elements in+-- the same type of basis+coeffs' :: forall m m' r . (m `Divides` m', Unbox r)+             => Arr m' r -> [Arr m r]+coeffs' =+  let indices = proxy extIndicesCoeffs (Proxy::Proxy '(m, m'))+  in coerce $ \ !arr -> V.toList $+  V.map (\idxs -> force $ backpermute (extent idxs) (idxs !) arr) indices++-- | The powerful extension basis, wrt the powerful basis.+-- Outputs a list of arrays in O_m' that are an O_m basis for O_m'+powBasisPow' :: forall m m' r . (m `Divides` m', Ring r, Unbox r)+                => Tagged m [Arr m' r]+powBasisPow' = return $  +  let (_, phi, phi', _) = proxy T.indexInfo (Proxy::Proxy '(m,m'))+      idxs = proxy T.baseIndicesPow (Proxy::Proxy '(m,m'))+  in LP.map (\k -> Arr $ force $ fromFunction (Z :. phi')+                         (\(Z:.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 arrays 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',+               Unbox fp)+              => Tagged m [Arr m' fp]+crtSetDec' = return $ +  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) ->+       let twCRTs' :: T.Matrix (GF fp d)+             = fromMaybe (error "internal error: crtSetDec': twCRTs") $ proxyT T.twCRTs m'p+           zmsToIdx = proxy T.zmsToIndexFact m'p+           elt j i = T.indexM twCRTs' j (zmsToIdx i)+           trace' = trace :: GF fp d -> fp+           cosets = proxy (partitionCosets p) (Proxy::Proxy '(m,m'))+       in LP.map (\is -> Arr $ force $ fromFunction (Z :. phi) +                          (\(Z:.j) -> hinv * trace'+                                      (sum $ LP.map (elt j) is))) cosets+++-- convert memoized reindexing Vectors to Arrays, for convenience and speed++extIndicesPowDec :: forall m m' . (m `Divides` m')+                    => Tagged '(m, m') (Array U DIM1 DIM1)+extIndicesPowDec = do+  idxs <- T.extIndicesPowDec+  return $ fromUnboxed (Z :. U.length idxs) $ U.map (Z:.) idxs++extIndicesCRT :: forall m m' . (m `Divides` m')+                 => Tagged '(m, m') (Array U DIM2 DIM1)+extIndicesCRT =+  let phi = proxy totientFact (Proxy::Proxy m)+      phi' = proxy totientFact (Proxy::Proxy m')+  in do+    idxs <- T.extIndicesCRT+    return $ fromUnboxed (Z :. phi :. phi' `div` phi) $ U.map (Z:.) idxs++baseIndicesPow :: forall m m' . (m `Divides` m')+                  => Tagged '(m, m') (Array U DIM1 (Int,DIM1))++baseIndicesDec :: forall m m' . (m `Divides` m')+                  => Tagged '(m, m') (Array U DIM1 (Maybe (DIM1, Bool)))++baseIndicesCRT :: forall m m' . (m `Divides` m')+                  => Tagged '(m, m') (Array U DIM1 DIM1)++baseIndicesPow = do+  idxs <- T.baseIndicesPow+  return $ fromUnboxed (Z :. U.length idxs) $ U.map (id *** (Z:.)) idxs++baseIndicesDec = do+  idxs <- T.baseIndicesDec+  return $ fromUnboxed (Z :. U.length idxs) $ U.map (liftA (first (Z:.))) idxs++baseIndicesCRT = do+  idxs <- T.baseIndicesCRT+  return $ fromUnboxed (Z :. U.length idxs) $ U.map (Z:.) idxs++extIndicesCoeffs :: forall m m' . (m `Divides` m')+                    => Tagged '(m, m') (V.Vector (Array U DIM1 DIM1))+extIndicesCoeffs = +  V.map (\arr -> fromUnboxed (Z :. U.length arr) $ +                 U.map (Z:.) arr) <$> T.extIndicesCoeffs
+ Crypto/Lol/Cyclotomic/Tensor/RepaTensor/GL.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE BangPatterns, ConstraintKinds, FlexibleContexts, GADTs,+             MultiParamTypeClasses, NoImplicitPrelude, RankNTypes,+             RebindableSyntax, ScopedTypeVariables #-}++-- | The @G@ and @L@ transforms for Repa arrays.++module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.GL+( fL, fLInv, fGPow, fGDec, fGInvPow, fGInvDec+) where++import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon as RT+import Crypto.Lol.LatticePrelude                        as LP+import Data.Coerce++fL, fLInv, fGPow, fGDec :: (Fact m, Additive r, Unbox r, Elt r)+  => Arr m r -> Arr m r+{-# INLINABLE fL #-}+{-# INLINABLE fLInv #-}+{-# INLINABLE fGPow #-}+{-# INLINABLE fGDec #-}++fGInvPow, fGInvDec ::+ (Fact m, IntegralDomain r, ZeroTestable r, Unbox r, Elt r)+  => Arr m r -> Maybe (Arr m r)+{-# INLINABLE fGInvPow #-}+{-# INLINABLE fGInvDec #-}++-- | Arbitrary-index @L@ transform, which converts from decoding-basis+-- to powerful-basis representation.+fL = eval $ fTensor $ ppTensor pL+-- | Arbitrary-index @L^{ -1 }@ transform, which converts from+-- powerful-basis to decoding-basis representation.+fLInv = eval $ fTensor $ ppTensor pLInv+-- | Arbitrary-index multiplication by @g_m@ in the powerful basis.+fGPow = eval $ fTensor $ ppTensor pGPow+-- | Arbitrary-index multiplication by @g_m@ in the decoding basis.+fGDec = eval $ fTensor $ ppTensor pGDec+-- | Arbitrary-index division by @g_m@ in the powerful+-- basis. Outputs 'Nothing' if the input is not evenly divisible by+-- @g_m@.  Warning: not constant time!+fGInvPow = wrapGInv' pGInvPow'+-- | Arbitrary-index division by @g_m@ in the decoding+-- basis. Outputs 'Nothing' if the input is no evenly divisible by+-- @g_m@.  Warning: not constant time!+fGInvDec = wrapGInv' pGInvDec'++wrapGInv' :: forall m r .+  (Fact m, IntegralDomain r, ZeroTestable r, Unbox r, Elt r)+  => (forall p . Prim p => Tagged p (Trans r))+  -> Arr m r -> Maybe (Arr m r)+wrapGInv' ginv =+  let fGInv = eval $ fTensor $ ppTensor ginv+      oddrad = fromIntegral $ proxy oddRadicalFact (Proxy::Proxy m)+  in (`divCheck` oddrad) . fGInv+{-# INLINABLE wrapGInv' #-}++-- | This is not a constant-time algorithm!  Depending on its usage,+-- it might provide a timing side-channel.+divCheck :: (IntegralDomain r, ZeroTestable r, Unbox r)+            => Arr m r -> r -> Maybe (Arr m r)+divCheck = coerce $  \ !arr den ->+  let qrs = force $ RT.map (`divMod` den) arr+      pass = foldAllS (&&) True $ RT.map (isZero . snd) qrs+      out = force $ RT.map fst qrs+  in if pass then Just out else Nothing+{-# INLINABLE divCheck #-}++pWrap :: forall p r . Prim p+         => (forall rep . Source rep r => Int -> Array rep DIM2 r -> Array D DIM2 r)+         -> Tagged p (Trans r)+pWrap f = let pval = proxy valuePrime (Proxy::Proxy p)+              -- special case: return identity function for p=2+          in return $ if pval > 2+                      then trans  (pval-1) $ f pval+                      else Id 1+{-# INLINABLE pWrap #-}+++pL, pLInv, pGPow, pGDec :: (Prim p, Additive r, Unbox r, Elt r)+  => Tagged p (Trans r)++pGInvPow', pGInvDec' :: (Prim p, Ring r, Unbox r, Elt r)+  => Tagged p (Trans r)+{-# INLINABLE pL #-}+{-# INLINABLE pLInv #-}+{-# INLINABLE pGPow #-}+{-# INLINABLE pGDec #-}+{-# INLINABLE pGInvPow' #-}+{-# INLINABLE pGInvDec' #-}++pL = pWrap (\_ !arr ->+             fromFunction (extent arr) $+             \ (i':.i) -> sumAllS $ extract (Z:.0) (Z:.(i+1)) $ slice arr (i':.All))++pLInv = pWrap (\_ !arr ->+                let f (i' :. 0) = arr! (i' :. 0)+                    f (i' :. i) = arr! (i' :. i) - arr! (i' :. i-1)+                in fromFunction (extent arr) f)+++-- multiplicaton by g_p=1-zeta_p in power basis.+-- this is "wrong" for p=2 but we never use that case thanks to pWrap.+pGPow = pWrap (\p !arr ->+                let f (i':.0) = arr! (i':.p-2) + arr! (i':.0)+                    f (i':.i) = arr! (i':.p-2) + arr! (i':.i) - arr! (i':.i-1)+                in fromFunction (extent arr) f)++-- multiplication by g_p=1-zeta_p in decoding basis+pGDec = pWrap (\_ !arr ->+                let f (i':.0) = arr! (i':.0) + sumAllS (slice arr (i':.All))+                    f (i':.i) = arr! (i':.i) - arr! (i':.i-1)+                in fromFunction (extent arr) f)++-- CJP: profiling suggests that this does two read passes through the+-- array; see if we can rewrite to make it one++-- doesn't do division by (odd) p+pGInvPow' =+  pWrap (\p !arr ->+          let f (i':.i) =+                let col = slice arr (i':.All)+                in fromIntegral (p-i-1) * sumAllS (extract (Z:.0) (Z:.i+1) col) ++                   fromIntegral (-i-1) * sumAllS (extract (Z:.i+1) (Z:.p-i-2) col)+          in fromFunction (extent arr) f)++-- doesn't do division by (odd) p+pGInvDec' =+  pWrap (\p !arr ->+          let f (i':.i) =+                let col = slice arr (i':.All)+                    nats = fromFunction (Z:.p-1) (\(Z:.j) -> fromIntegral j+1)+                in (sumAllS $ RT.zipWith (*) col nats) -+                   fromIntegral p * sumAllS (extract (Z:.i+1) (Z:.p-i-2) col)+          in fromFunction (extent arr) f)
+ Crypto/Lol/Cyclotomic/Tensor/RepaTensor/RTCommon.hs view
@@ -0,0 +1,277 @@+{-# LANGUAGE BangPatterns, ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, GADTs, GeneralizedNewtypeDeriving,+             KindSignatures, MultiParamTypeClasses, NoImplicitPrelude,+             RankNTypes, RebindableSyntax, RoleAnnotations,+             ScopedTypeVariables, TypeOperators #-}++-- | A simple DSL for tensoring Repa arrays and other common functionality+-- on Repa arrays++module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon+( module R+, module Data.Array.Repa.Eval+, module Data.Array.Repa.Repr.Unboxed+, Arr(..), repl, replM, eval, evalM, fTensor, ppTensor+, Trans(Id), trans, dim, (.*), (@*), force+, mulMat, mulDiag+, scalarPow'+, sumS, sumAllS+) where++import Crypto.Lol.LatticePrelude as LP hiding ((!!))++import Algebra.Additive as Additive (C)+import Algebra.Ring as Ring (C)+import Algebra.ZeroTestable as ZeroTestable (C)++import Control.DeepSeq              (NFData (..))+import Control.Monad.Identity+import Control.Monad.Random+import Data.Array.Repa              as R hiding (sumAllP, sumAllS, sumP,+                                          sumS, (*^), (+^), (-^), (/^))+import Data.Array.Repa.Eval         hiding (one, zero)+import Data.Array.Repa.Repr.Unboxed+import Data.Coerce+import Data.Singletons+import Data.Singletons.Prelude      hiding ((:.))+import qualified Data.Vector.Unboxed as U+import Test.QuickCheck++-- just for specialization+import Crypto.Lol.Types.ZqBasic++-- always unboxed (manifest); intermediate calculations can use+-- delayed arrays++-- | Indexed newtype for 1-dimensional Unbox repa arrays+newtype Arr (m :: Factored) r = Arr (Array U DIM1 r)+                              deriving (Eq, Show, NFData)++-- the first argument, though phantom, affects representation+-- CJP: why must the second arg be nominal?+-- EAC: From https://ghc.haskell.org/trac/ghc/wiki/Roles#Thesolution:+--   "The exception to the above algorithm is for classes: all parameters for a class default to a nominal role."+-- Arr is a synonym for Array, which is an associated data type to the class Source. The parameter `r` above+-- corresponds to the parameter `e` in the definition of class Source, so it's role must be nominal.+type role Arr nominal nominal++-- | An 'Arr' filled with the argument.+repl :: forall m r . (Fact m, Unbox r) => r -> Arr m r+repl = let n = proxy totientFact (Proxy::Proxy m)+       in Arr . fromUnboxed (Z:.n) . U.replicate n+{-# INLINABLE repl #-}++-- | Monadic version of 'repl'.+replM :: forall m r mon . (Fact m, Unbox r, Monad mon)+         => mon r -> mon (Arr m r)+replM = let n = proxy totientFact (Proxy::Proxy m)+        in liftM (Arr . fromUnboxed (Z:.n)) . U.replicateM n+{-# INLINABLE replM #-}++instance (Fact m, Additive r, Unbox r, Elt r) => Additive.C (Arr m r) where+  zero = repl zero+  (Arr a) + (Arr b) = Arr $ force $ R.zipWith (+) a b+  negate (Arr a) = Arr $ force $ R.map negate a+  {-# INLINABLE zero #-}+  {-# INLINABLE (+) #-}+  {-# INLINABLE negate #-}++instance (Fact m, Ring r, Unbox r, Elt r) => Ring.C (Arr m r) where+  one = repl one+  (Arr a) * (Arr b) = Arr $ force $ R.zipWith (*) a b+  fromInteger = repl . fromInteger+  {-# INLINABLE one #-}+  {-# INLINABLE (*) #-}+  {-# INLINABLE fromInteger #-}++instance (Fact m, ZeroTestable r, Unbox r, Elt r) => ZeroTestable.C (Arr m r) where+  -- not using 'zero' to avoid Additive r constraint+  isZero (Arr a) +      = isZero $ foldAllS (\ x y -> if isZero x then y else x) (a R.! (Z:.0)) a+  {-# INLINABLE isZero #-}+++instance (Unbox r) => NFData (Array U DIM1 r) where+  -- EAC: Repa doesn't define any NFData instances,+  -- I'm hoping deepSeqArray is a reasonable approx+  rnf x = deepSeqArray x ()++instance (Unbox r, Random r, Fact m) => Random (Arr m r) where+  random = runRand $ replM (liftRand random)++  randomR = error "randomR nonsensical for Arr"++instance (Arbitrary r, Unbox r, Fact m) => Arbitrary (Arr m r) where+    arbitrary = replM arbitrary+    shrink = shrinkNothing++-- | For a factored index, tensors up any function defined for (and+-- tagged by) any prime power+fTensor :: forall m r mon . (Fact m, Monad mon, Unbox r)+  => (forall pp . (PPow pp) => TaggedT pp mon (Trans r))+  -> TaggedT m mon (Trans r)++fTensor func = tagT $ go $ sUnF (sing :: SFactored m)+  where+    go :: Sing (pplist :: [PrimePower]) -> mon (Trans r)+    go spps = case spps of+          SNil -> return $ Id 1+          (SCons spp rest) -> do+            rest' <- go rest+            func' <- withWitnessT func spp+            return $ rest' @* func'+{-# INLINABLE fTensor #-}++-- | For a prime power p^e, tensors up any function f defined for+-- (and tagged by) a prime to @I_(p^{e-1}) \otimes f@+ppTensor :: forall pp r mon . (PPow pp, Monad mon)+            => (forall p . (Prim p) => TaggedT p mon (Trans r))+            -> TaggedT pp mon (Trans r)++ppTensor func = tagT $ case (sing :: SPrimePower pp) of+  pp@(SPP (STuple2 sp _)) -> do+    func' <- withWitnessT func sp+    let lts = withWitness valuePPow pp `div` withWitness valuePrime sp+    return $ Id lts @* func'+{-# INLINABLE ppTensor #-}+++-- deeply embedded DSL for transformations and their various+-- compositions++-- (dim(f), f) where f operates on innermost dimension of array+data Tensorable r = Tensorable+  !Int !(forall rep . Source rep r => Array rep DIM2 r -> Array D DIM2 r)++-- transform component: a Tensorable with particular I_l, I_r+type TransC r = (Tensorable r, Int, Int)++-- full transform: sequence of zero or more components+-- | a DSL for tensor transforms on Repa arrays+data Trans r = Id !Int                      -- ^| identity sentinel+             | TSnoc !(Trans r) !(TransC r) -- ^| (function) composition of transforms++dimC :: TransC r -> Int+dimC (Tensorable d _, l, r) = l*d*r+{-# INLINABLE dimC #-}++-- | Returns the (linear) dimension of a transform+dim :: Trans r -> Int+dim (Id n) = n+dim (TSnoc _ f) = dimC f        -- just use dimension of head+{-# INLINABLE dim #-}++-- | smart constructor from a Tensorable+trans :: Int -> (forall rep . Source rep r => Array rep DIM2 r -> Array D DIM2 r) -> Trans r+trans d f = TSnoc (Id d) (Tensorable d f, 1, 1)+{-# INLINABLE trans #-}++-- | compose transforms+(.*) :: Trans r -> Trans r -> Trans r+f .* g | dim f == dim g = f ..* g+       | otherwise = error $ "(.*): transform dimensions don't match "+                     LP.++ show (dim f) LP.++ ", " LP.++ show (dim g)+  where+    f' ..* (Id _) = f'          -- drop sentinel+    f' ..* (TSnoc rest g') = TSnoc (f' ..* rest) g'+{-# INLINABLE (.*) #-}++-- | tensor/Kronecker product (otimes)+(@*) :: Trans r -> Trans r -> Trans r+-- merge identity transforms+(Id n) @* (Id m) = Id (n*m)+-- Id on left or right+i@(Id n) @* (TSnoc g' (g, l, r)) = TSnoc (i @* g') (g, n*l, r)+(TSnoc f' (f, l, r)) @* i@(Id n) = TSnoc (f' @* i) (f, l, r*n)+-- no Ids: compose+f @* g = (f @* Id (dim g)) .* (Id (dim f) @* g)+{-# INLINABLE (@*) #-}++evalC :: (Unbox r) => TransC r -> Array U DIM1 r -> Array U DIM1 r+evalC (Tensorable d f, _, r) = force . unexpose r . f . expose d r+{-# INLINABLE evalC #-}++-- | Creates an evaluatable Haskell function from a tensored transform+eval :: (Unbox r) => Tagged m (Trans r) -> Arr m r -> Arr m r+eval x = coerce $ eval' $ untag x+  where eval' (Id _) = id+        eval' (TSnoc rest f) = eval' rest . evalC f+{-# INLINABLE eval #-}++-- | Monadic version of 'eval'+evalM :: (Unbox r, Monad mon) => TaggedT m mon (Trans r) -> mon (Arr m r -> Arr m r)+evalM = liftM (eval . return) . untagT+{-# INLINE evalM #-}++-- | maps the innermost dimension to a 2-dim array with innermost dim d,+-- for performing a I_l \otimes f_d \otimes I_r transformation+expose :: (Source r1 r, Unbox r)+          => Int -> Int -> Array r1 DIM1 r -> Array D DIM2 r+expose !d !r !arr =+  let (Z :. sz) = extent arr+      f (Z :. i :. j) = let imodr = i `mod` r+                        in (Z :. (i-imodr)*d + j*r + imodr)+  in backpermute (Z :. sz `div` d :. d) f arr+{-# INLINABLE expose #-}++-- | inverse of expose+unexpose :: (Source r1 r, Unbox r) => Int -> Array r1 DIM2 r -> Array D DIM1 r+unexpose !r !arr =+  let (Z :. sz :. d) = extent arr+      f (Z :. i) = let (idivr,imodr) = i `divMod` r+                       (idivrd,j) = idivr `divMod` d+                   in (Z :. r*idivrd + imodr :. j)+  in backpermute (Z :. sz*d) f arr+{-# INLINABLE unexpose #-}++-- | general matrix multiplication along innermost dim of v+mulMat :: (Source r1 r, Source r2 r, Ring r, Unbox r, Elt r)+          => Array r1 DIM2 r -> Array r2 DIM2 r -> Array D DIM2 r+mulMat !m !v+  = let (Z :. mrows :. mcols) = extent m+        (sh :. vrows) = extent v+        f (sh' :. i) = sumAllS $ R.zipWith (*) (slice m (Z:.i:.All)) $ slice v (sh':.All)+    in if mcols == vrows then fromFunction (sh :. mrows) f+       else error "mulMatVec: mcols != vdim"+{-# INLINABLE mulMat #-}+            +-- | multiplication by a diagonal matrix along innermost dim+mulDiag :: (Source r1 r, Source r2 r, Ring r, Unbox r, Elt r)+           => Array r1 DIM1 r -> Array r2 DIM2 r -> Array D DIM2 r+mulDiag !diag !arr = fromFunction (extent arr) f+  where f idx@(_ :. i) = (arr ! idx) * (diag ! (Z:.i))+{-# INLINABLE mulDiag #-}++-- misc Tensor functions++-- | Embeds a scalar into a powerful-basis representation of a Repa array,+-- tagged by the cyclotomic index+scalarPow' :: forall m r . (Fact m, Additive r, Unbox r) => r -> Arr m r+scalarPow' = coerce . (go $ proxy totientFact (Proxy::Proxy m))+  where go n !r = let fct (Z:.0) = r+                      fct _ = LP.zero+                  in force $ fromFunction (Z:.n) fct+{-# INLINABLE scalarPow' #-}++-- | Forces a delayed array to a manifest array.+force :: (Shape sh, Unbox r) => Array D sh r -> Array U sh r+force = computeS+--force = runIdentity . computeP+{-# INLINABLE force #-}++-- copied implementations of functions we need that normally require+-- Num++-- | Sum the inner-most dimension of an array sequentially+sumS :: (Source r a, Elt a, Unbox a, Additive a, Shape sh)+  => Array r (sh :. Int) a+  -> Array U sh a+sumS = foldS (+) LP.zero+{-# INLINABLE sumS #-}++-- | Sum all array indices to a scalar sequentially+sumAllS :: (Shape sh, Source r a, Elt a, Unbox a, Additive a)+  => Array r sh a+  -> a+sumAllS = foldAllS (+) LP.zero+{-# INLINABLE sumAllS #-}
+ Crypto/Lol/Cyclotomic/UCyc.hs view
@@ -0,0 +1,591 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, GADTs, InstanceSigs, MultiParamTypeClasses,+             NoImplicitPrelude, PolyKinds, RankNTypes, RebindableSyntax,+             ScopedTypeVariables, TypeFamilies, TypeOperators,+             UndecidableInstances #-}++-- | A low-level implementation of cyclotomic rings that allows (and+-- requires) the programmer to control the underlying representation+-- of ring elements, i.e., powerful, decoding, or CRT basis.+--+-- __WARNING:__ as with all fixed-point arithmetic, the functions+-- associated with 'UCyc' may result in overflow (and thereby+-- incorrect answers and potential security flaws) if the input+-- arguments are too close to the bounds imposed by the base type.+-- The acceptable range of inputs for each function is determined by+-- the internal linear transforms and other operations it performs.++module Crypto.Lol.Cyclotomic.UCyc+(+-- * Data types and constraints+  UCyc, P, D, C, UCElt, NFElt+-- * Changing representation+, toPow, toDec, toCRT, fmapPow, fmapDec, unzipCyc, unzipUCElt+-- * Scalars+, scalarPow, scalarCRT          -- scalarDec suppressed+-- * Basic operations+, mulG, divG, gSqNorm+-- * Error sampling+, tGaussian, errorRounded, errorCoset+-- * Inter-ring operations and values+, embedPow, embedDec, embedCRT+, twacePow, twaceDec, twaceCRT+, coeffsPow, coeffsDec, powBasis, crtSet+) where++import Crypto.Lol.Cyclotomic.Tensor hiding (embedCRT, embedDec, embedPow,+                                     scalarCRT, scalarPow, -- scalarDec+                                     twaceCRT)++import           Crypto.Lol.CRTrans+import qualified Crypto.Lol.Cyclotomic.Tensor as T+import           Crypto.Lol.LatticePrelude    as LP+import           Crypto.Lol.Types.FiniteField+import           Crypto.Lol.Types.ZPP++import qualified Algebra.Additive     as Additive (C)+import qualified Algebra.Module       as Module (C)+import qualified Algebra.Ring         as Ring (C)+import qualified Algebra.ZeroTestable as ZeroTestable (C)++import Control.Applicative    as A+import Control.Arrow+import Control.DeepSeq+import Control.Monad+import Control.Monad.Random+import Data.Foldable          as F+import Data.Maybe+import Data.Traversable+import Test.QuickCheck++--import qualified Debug.Trace as DT++-- | Nullary index type representing the powerful basis.+data P+-- | Nullary index type representing the decoding basis.+data D+-- | Nullary index type representing a CRT basis.+data C++-- | Represents a cyclotomic ring such as @Z[zeta]@,+-- @Zq[zeta]@, and @Q(zeta)@ in an explicit representation: @t@ is the+-- 'Tensor' type for storing coefficient tensors; @m@ is the+-- cyclotomic index; @rep@ is the representation ('P', 'D', or 'C');+-- @r@ is the base ring of the coefficients (e.g., @Z@, @Zq@).+--+-- The 'Functor', 'Applicative', 'Foldable' and 'Traversable'+-- instances all work coefficient-wise (in the specified basis).+data UCyc t m rep r where+  Pow  :: !(t m r) -> UCyc t m P r+  Dec  :: !(t m r) -> UCyc t m D r+  -- Invariant: for a given (t,m,r), exactly one of these two is ever+  -- used: CRTr if crtFuncs exists, otherwise CRTe+  CRTr :: !(t m r) -> UCyc t m C r+  CRTe :: !(t m (CRTExt r)) -> UCyc t m C r++-- | Constraints needed for many operations involving the 'UCyc' CRT ('C')+-- representation.+type UCElt t r = (Tensor t, CRTEmbed r, CRTElt t r, CRTElt t (CRTExt r))++-- | Convenient synonym for 'deepseq'-able element type.+type NFElt r = (NFData r, NFData (CRTExt r))++-- | Embed a scalar from the base ring.+scalarPow :: (Tensor t, Fact m, Ring r, TElt t r) => r -> UCyc t m P r+scalarPow = Pow . T.scalarPow+{-# INLINABLE scalarPow #-}++{- CJP: suppressed++-- | Embed a scalar from the base ring.+scalarDec :: (Tensor t, Fact m, Ring r, TElt t r) => r -> UCyc t m D r+scalarDec = Dec . T.scalarDec+{-# INLINABLE scalarDec #-}++-}++-- | Embed a scalar from the base ring.+scalarCRT :: (Fact m, UCElt t r) => r -> UCyc t m C r+scalarCRT = fromMaybe+               (CRTe . fromJust' "UCyc: no CRT over CRTExt" T.scalarCRT . toExt)+               ((CRTr .) <$> T.scalarCRT)+{-# INLINABLE scalarCRT #-}++-- Eq instances++instance (Eq r, Tensor t, Fact m, TElt t r) => Eq (UCyc t m P r) where+  (Pow v1) == (Pow v2) = v1 == v2 \\ witness entailEqT v1+  {-# INLINABLE (==) #-}++instance (Eq r, Tensor t, Fact m, TElt t r) => Eq (UCyc t m D r) where+  (Dec v1) == (Dec v2) = v1 == v2 \\ witness entailEqT v1+  {-# INLINABLE (==) #-}++instance (Eq r, Fact m, UCElt t r) => Eq (UCyc t m C r) where+  (CRTr v1) == (CRTr v2) = v1 == v2 \\ witness entailEqT v1+  -- compare in pow due to precision+  u1 == u2 = toPow u1 == toPow u2+  {-# INLINABLE (==) #-}+++---------- Numeric Prelude instances ----------++-- ZeroTestable instances++instance (ZeroTestable r, Tensor t, Fact m, TElt t r)+    => ZeroTestable.C (UCyc t m P r) where+  isZero (Pow v) = isZero v \\ witness entailZTT v+  {-# INLINABLE isZero #-}++instance (ZeroTestable r, Tensor t, Fact m, TElt t r)+    => ZeroTestable.C (UCyc t m D r) where+  isZero (Dec v) = isZero v \\ witness entailZTT v+  {-# INLINABLE isZero #-}++instance (ZeroTestable r, Fact m, UCElt t r)+    => ZeroTestable.C (UCyc t m C r) where+  isZero (CRTr v) = isZero v \\ witness entailZTT v+  -- use powerful basis due to precision+  isZero u = isZero $ toPow u+  {-# INLINABLE isZero #-}++-- Additive instances++instance (Additive r, Tensor t, Fact m, TElt t r) => Additive.C (UCyc t m P r) where+  zero = Pow $ T.scalarPow zero+  (Pow v1) + (Pow v2) = Pow $ zipWithT (+) v1 v2+  (Pow v1) - (Pow v2) = Pow $ zipWithT (-) v1 v2+  negate (Pow v) = Pow $ fmapT negate v+  {-# INLINABLE zero #-}+  {-# INLINABLE (+) #-}+  {-# INLINABLE (-) #-}+  {-# INLINABLE negate #-}++instance (Additive r, Tensor t, Fact m, TElt t r) => Additive.C (UCyc t m D r) where+  zero = Dec $ T.scalarPow zero -- scalarPow works because it's zero+  (Dec v1) + (Dec v2) = Dec $ zipWithT (+) v1 v2+  (Dec v1) - (Dec v2) = Dec $ zipWithT (-) v1 v2+  negate (Dec v) = Dec $ fmapT negate v+  {-# INLINABLE zero #-}+  {-# INLINABLE (+) #-}+  {-# INLINABLE (-) #-}+  {-# INLINABLE negate #-}++instance (Fact m, UCElt t r) => Additive.C (UCyc t m C r) where+  zero = scalarCRT zero++  -- CJP: precision OK?  Alternatively, switch to pow and back after+  -- adding/subtracting.  Expensive, but necessary given output type.+  (CRTr v1) + (CRTr v2) = CRTr $ zipWithT (+) v1 v2+  (CRTe v1) + (CRTe v2) = CRTe $ zipWithT (+) v1 v2+  _ + _ = error "UCyc (+) internal error: mixed CRTr/CRTe"++  (CRTr v1) - (CRTr v2) = CRTr $ zipWithT (-) v1 v2+  (CRTe v1) - (CRTe v2) = CRTe $ zipWithT (-) v1 v2+  _ - _ = error "UCyc (-) internal error: mixed CRTr/CRTe"++  negate (CRTr v) = CRTr $ fmapT negate v+  negate (CRTe v) = CRTe $ fmapT negate v++  {-# INLINABLE zero #-}+  {-# INLINABLE (+) #-}+  {-# INLINABLE (-) #-}+  {-# INLINABLE negate #-}++-- Ring instance: only for CRT++instance (Fact m, UCElt t r) => Ring.C (UCyc t m C r) where+  one = scalarCRT one+  fromInteger c = scalarCRT $ fromInteger c++  -- CJP: precision OK?  Alternatively, switch to pow (and back) after+  -- multiplying.  Expensive, but necessary given output type.+  (CRTr v1) * (CRTr v2) = CRTr $ zipWithT (*) v1 v2+  (CRTe v1) * (CRTe v2) = CRTe $ zipWithT (*) v1 v2+  _ * _ = error "UCyc internal error: mixed CRTr/CRTe"++  {-# INLINABLE one #-}+  {-# INLINABLE fromInteger #-}+  {-# INLINABLE (*) #-}+++instance (Ring r, Tensor t, Fact m, TElt t r) => Module.C r (UCyc t m P r) where+  r *> (Pow v) = Pow $ fmapT (r *) v+  {-# INLINABLE (*>) #-}++instance (Ring r, Tensor t, Fact m, TElt t r) => Module.C r (UCyc t m D r) where+  r *> (Dec v) = Dec $ fmapT (r *) v+  {-# INLINABLE (*>) #-}++instance (Ring r, Fact m, UCElt t r) => Module.C r (UCyc t m C r) where+  r *> (CRTr v) = CRTr $ fmapT (r *) v+  r *> (CRTe v) = CRTe $ fmapT (toExt r *) v+  {-# INLINABLE (*>) #-}++instance (GFCtx fp d, Fact m, UCElt t fp) => Module.C (GF fp d) (UCyc t m P fp) where+  -- can use any r-basis to define module mult, but must be+  -- consistent.+  r *> (Pow v) = Pow $ r LP.*> v \\ witness entailModuleT (r,v)+++instance (Reduce a b, Tensor t, Fact m, TElt t a, TElt t b)+    => Reduce (UCyc t m P a) (UCyc t m P b) where+  reduce (Pow v) = Pow $ fmapT reduce v+  {-# INLINABLE reduce #-}++instance (Reduce a b, Tensor t, Fact m, TElt t a, TElt t b)+    => Reduce (UCyc t m D a) (UCyc t m D b) where+  reduce (Dec v) = Dec $ fmapT reduce v+  {-# INLINABLE reduce #-}++-- CJP: no Reduce for C rep because we can't efficiently handle CRTe case++type instance LiftOf (UCyc t m P r) = UCyc t m P (LiftOf r)+type instance LiftOf (UCyc t m D r) = UCyc t m D (LiftOf r)++instance (Lift' r, Tensor t, Fact m, TElt t r, TElt t (LiftOf r))+         => Lift' (UCyc t m P r) where+  lift (Pow v) = Pow $ fmapT lift v+  {-# INLINABLE lift #-}++instance (Lift' r, Tensor t, Fact m, TElt t r, TElt t (LiftOf r))+         => Lift' (UCyc t m D r) where+  lift (Dec v) = Dec $ fmapT lift v+  {-# INLINABLE lift #-}+++instance (Rescale a b, Tensor t, Fact m, TElt t a, TElt t b)+         => Rescale (UCyc t m P a) (UCyc t m P b) where+  rescale (Pow v) = Pow $ fmapT rescale v+  {-# INLINABLE rescale #-}++instance (Rescale a b, Tensor t, Fact m, TElt t a, TElt t b)+         => Rescale (UCyc t m D a) (UCyc t m D b) where+  rescale (Dec v) = Dec $ fmapT rescale v+  {-# INLINABLE rescale #-}+++-- CJP: we don't instantiate RescaleCyc because it requires changing bases++-- CJP: we don't instantiate Gadget etc., because (1) their methods+-- wouldn't be efficient, and (2) their superclasses are not even+-- well-defined (e.g., Ring for P rep).+++-- | Type-restricted (and potentially more efficient) map for+-- powerful-basis representation.+fmapPow :: (Tensor t, Fact m, TElt t a, TElt t b)+           => (a -> b) -> UCyc t m P a -> UCyc t m P b+fmapPow f (Pow v) = Pow $ fmapT f v+{-# INLINABLE fmapPow #-}++-- | Type-restricted (and potentially more efficient) map for+-- decoding-basis representation.+fmapDec :: (Tensor t, Fact m, TElt t a, TElt t b)+           => (a -> b) -> UCyc t m D a -> UCyc t m D b+fmapDec f (Dec v) = Dec $ fmapT f v+{-# INLINABLE fmapDec #-}++-- | Unzip for unrestricted types.+unzipCyc :: (Tensor t, Fact m)+            => UCyc t m rep (a,b) -> (UCyc t m rep a, UCyc t m rep b)+{-# INLINABLE unzipCyc #-}+unzipCyc (Pow v) = Pow *** Pow $ unzipT v+unzipCyc (Dec v) = Dec *** Dec $ unzipT v+unzipCyc (CRTr v) = CRTr *** CRTr $ unzipT v+unzipCyc (CRTe v) = CRTe *** CRTe $ unzipT v++-- | Type-restricted (and potentially more efficient) unzip.+unzipUCElt :: (Tensor t, Fact m, UCElt t (a,b), UCElt t a, UCElt t b)+              => UCyc t m rep (a,b) -> (UCyc t m rep a, UCyc t m rep b)+{-# INLINABLE unzipUCElt #-}+unzipUCElt (Pow v) = Pow *** Pow $ unzipTElt v+unzipUCElt (Dec v) = Dec *** Dec $ unzipTElt v+unzipUCElt (CRTr v) = CRTr *** CRTr $ unzipTElt v+unzipUCElt (CRTe v) = CRTe *** CRTe $ unzipTElt v++-- | Multiply by the special element @g@.+mulG :: (Tensor t, Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m rep r+{-# INLINABLE mulG #-}+mulG (Pow v) = Pow $ mulGPow v+mulG (Dec v) = Dec $ mulGDec v+-- fromJust is safe here because we're already in CRTr+mulG (CRTr v) = CRTr $ fromJust' "UCyc.mulG CRTr" mulGCRT v+mulG (CRTe v) = CRTe $ fromJust' "UCyc.mulG CRTe" mulGCRT v++-- | Divide by the special element @g@.+divG :: (Tensor t, Fact m, UCElt t r) => UCyc t m rep r -> Maybe (UCyc t m rep r)+{-# INLINABLE divG #-}+divG (Pow v) = Pow <$> divGPow v+divG (Dec v) = Dec <$> divGDec v+-- fromJust is OK here because we're already in CRTr+divG (CRTr v) = Just $ CRTr $ fromJust' "UCyc.divG CRTr" divGCRT v+divG (CRTe v) = Just $ CRTe $ fromJust' "UCyc.divG CRTe" divGCRT v++-- | 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@ .+gSqNorm :: (Ring r, Tensor t, Fact m, TElt t r) => UCyc t m D r -> r+gSqNorm (Dec v) = gSqNormDec v+{-# INLINABLE gSqNorm #-}++-- | Sample from the "tweaked" Gaussian error distribution @t*D@ in+-- the decoding basis, where @D@ has scaled variance @v@.  (Note: This+-- implementation uses Double precision to generate the Gaussian+-- sample, which may not be sufficient for rigorous proof-based+-- security.)+tGaussian :: (Tensor t, Fact m, OrdFloat q, Random q, TElt t q,+              ToRational v, MonadRandom rnd)+             => v -> rnd (UCyc t m D q)+tGaussian = fmap Dec . tGaussianDec+{-# INLINABLE tGaussian #-}++-- | Generate an LWE error term from the "tweaked" Gaussian with given+-- scaled variance, deterministically rounded using the decoding+-- basis.+errorRounded :: forall v rnd t m z .+                (ToInteger z, Tensor t, Fact m, TElt t z,+                 ToRational v, MonadRandom rnd)+                => v -> rnd (UCyc t m D z)+{-# INLINABLE errorRounded #-}+errorRounded svar =+  Dec . fmapT (roundMult one) <$> (tGaussianDec svar :: rnd (t m Double))++-- | Generate an LWE error term from the "tweaked" Gaussian with+-- scaled variance @v * p^2@, deterministically rounded to the given+-- coset of @R_p@ using the decoding basis.+errorCoset :: forall t m zp z v rnd .+  (Mod zp, z ~ ModRep zp, Lift zp z, Tensor t, Fact m,+   TElt t zp, TElt t z, ToRational v, MonadRandom rnd)+  => v -> UCyc t m D zp -> rnd (UCyc t m D z)+{-# INLINABLE errorCoset #-}+errorCoset =+  let pval = fromIntegral $ proxy modulus (Proxy::Proxy zp)+  in \ svar c -> do err <- tGaussian (svar*pval*pval) :: rnd (UCyc t m D Double)+                    return $! roundCoset <$> c <*> err+++----- inter-ring operations++-- | Embed into an extension ring, for the powerful basis.+embedPow :: (Additive r, Tensor t, m `Divides` m', TElt t r)+            => UCyc t m P r -> UCyc t m' P r+embedPow (Pow v) = Pow $ T.embedPow v+{-# INLINABLE embedPow #-}++-- | Embed into an extension ring, for the decoding basis.+embedDec :: (Additive r, Tensor t, m `Divides` m', TElt t r)+            => UCyc t m D r -> UCyc t m' D r+embedDec (Dec v) = Dec $ T.embedDec v+{-# INLINABLE embedDec #-}++-- | Embed into an extension ring, for a CRT basis.  (The output is+-- an 'Either' because in some cases it is most efficient to preserve+-- the 'UCyc' internal invariant by producing output with respect to+-- the powerful basis.)+embedCRT :: forall t m m' r . (m `Divides` m', UCElt t r)+            => UCyc t m C r -> Either (UCyc t m' P r) (UCyc t m' C r)+{-# INLINABLE embedCRT #-}+embedCRT x@(CRTr v) = fromMaybe (Left $ embedPow $ toPow x)+                      (Right . CRTr <$> (T.embedCRT <*> pure v))+embedCRT x@(CRTe v) =+    -- preserve invariant: CRTe iff CRTr is invalid for m'+    fromMaybe (Right $ CRTe $ fromJust' "UCyc.embedCRT CRTe" T.embedCRT v)+              (proxyT hasCRTFuncs (Proxy::Proxy (t m r)) A.*>+               pure (Left $ embedPow $ toPow x))++-- | Twace into a subring, for the powerful basis.+twacePow :: (Ring r, Tensor t, m `Divides` m', TElt t r)+            => UCyc t m' P r -> UCyc t m P r+twacePow (Pow v) = Pow $ twacePowDec v+{-# INLINABLE twacePow #-}++-- | Twace into a subring, for the decoding basis.+twaceDec :: (Ring r, Tensor t, m `Divides` m', TElt t r)+            => UCyc t m' D r -> UCyc t m D r+twaceDec (Dec v) = Dec $ twacePowDec v+{-# INLINABLE twaceDec #-}++-- | Twace into a subring, for a CRT basis.  (The output is an+-- 'Either' because in some cases it is most efficient to preserve the+-- 'UCyc' internal invariant by producing output with respect to the+-- powerful basis.)+twaceCRT :: forall t m m' r . (m `Divides` m', UCElt t r)+            => UCyc t m' C r -> Either (UCyc t m P r) (UCyc t m C r)+{-# INLINABLE twaceCRT #-}+twaceCRT x@(CRTr v) =+  -- stay in CRTr only iff it's valid for target, else go to Pow+  fromMaybe (Left $ twacePow $ toPow x) (Right . CRTr <$> (T.twaceCRT <*> pure v))+twaceCRT x@(CRTe v) =+  -- stay in CRTe iff CRTr is invalid for target, else go to Pow+  fromMaybe (Right $ CRTe $ fromJust' "UCyc.twace CRTe" T.twaceCRT v)+            (proxyT hasCRTFuncs (Proxy::Proxy (t m r)) A.*>+             Just (Left $ twacePow $ toPow x))++-- | Yield the @O_m@-coefficients of an @O_m'@-element, with respect to+-- the relative powerful @O_m@-basis.+coeffsPow :: (Ring r, Tensor t, m `Divides` m', TElt t r)+             => UCyc t m' P r -> [UCyc t m P r]+{-# INLINABLE coeffsPow #-}+coeffsPow (Pow v) = LP.map Pow $ coeffs v++-- | Yield the @O_m@-coefficients of an @O_m'@ element, with respect to+-- the relative decoding @O_m@-basis.+coeffsDec :: (Ring r, Tensor t, m `Divides` m', TElt t r)+             => UCyc t m' D r -> [UCyc t m D r]+{-# INLINABLE coeffsDec #-}+coeffsDec (Dec v) = LP.map Dec $ coeffs v++-- | The relative powerful basis of @O_m' / O_m@.+powBasis :: (Ring r, Tensor t, m `Divides` m', TElt t r)+            => Tagged m [UCyc t m' P r]+{-# INLINABLE powBasis #-}+powBasis = (Pow <$>) <$> powBasisPow++-- | The relative mod-@r@ CRT set of @O_m' / O_m@, represented with+-- respect to the powerful basis (which seems to be the best choice+-- for typical use cases).+crtSet :: forall t m m' r p mbar m'bar .+           (m `Divides` m', ZPP r, p ~ CharOf (ZpOf r),+            mbar ~ PFree p m, m'bar ~ PFree p m',+            UCElt t r, TElt t (ZpOf r))+           => Tagged m [UCyc t m' P r]+{-# INLINABLE crtSet #-}+crtSet =+  -- CJP: consider using traceEvent or traceMarker+  --DT.trace ("UCyc.crtSet: m = " +++  --          show (proxy valueFact (Proxy::Proxy m)) ++ ", m'= " +++  --          show (proxy valueFact (Proxy::Proxy m'))) $+  let (p,e) = proxy modulusZPP (Proxy::Proxy r)+      pp = Proxy::Proxy p+      pm = Proxy::Proxy m+      pm' = Proxy::Proxy m'+  in retag (fmap (embedPow .+                  (if e > 1 then toPow . (^(p^(e-1))) . toCRT else toPow) .+                  Dec . fmapT liftZp) <$>+            (crtSetDec :: Tagged mbar [t m'bar (ZpOf r)]))+     \\ pFreeDivides pp pm pm' \\ pSplitTheorems pp pm \\ pSplitTheorems pp pm'+++--------- Conversion methods ------------------+++-- | Convert to powerful-basis representation.+toPow :: (Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m P r+{-# INLINABLE toPow #-}+toPow x@(Pow _) = x+toPow (Dec v) = Pow $ l v+toPow (CRTr v) = Pow $ fromJust' "UCyc.toPow CRTr" crtInv v+toPow (CRTe v) =+    Pow $ fmapT fromExt $ fromJust' "UCyc.toPow CRTe" crtInv v++-- | Convert to decoding-basis representation.+toDec :: (Fact m, UCElt t r) => UCyc t m rep r -> UCyc t m D r+{-# INLINABLE toDec #-}+toDec (Pow v) = Dec $ lInv v+toDec x@(Dec _) = x+toDec x@(CRTr _) = toDec $ toPow x+toDec x@(CRTe _) = toDec $ toPow x++-- | Convert to a CRT-basis representation.+toCRT :: forall t m rep r . (Fact m, UCElt t r)+         => UCyc t m rep r -> UCyc t m C r+{-# INLINABLE toCRT #-}+toCRT = let crte = CRTe . fromJust' "UCyc.toCRT: no crt for Ext" crt+            crtr = fmap (CRTr .) crt+            fromPow :: t m r -> UCyc t m C r+            fromPow v = fromMaybe (crte $ fmapT toExt v) (crtr <*> Just v)+        in \x -> case x of+                   (CRTr _) -> x+                   (CRTe _) -> x+                   (Pow v) -> fromPow v+                   (Dec v) -> fromPow $ l v+++---------- Category-theoretic instances ----------++-- CJP: no Applicative, Foldable, Traversable for C because types+-- (and math) don't work out for the CRTe case.++instance (Tensor t, Fact m) => Functor (UCyc t m P) where+  -- Functor instance is implied by Applicative laws+  {-# INLINABLE fmap #-}+  fmap f x = pure f <*> x++instance (Tensor t, Fact m) => Functor (UCyc t m D) where+  -- Functor instance is implied by Applicative laws+  {-# INLINABLE fmap #-}+  fmap f x = pure f <*> x++instance (Tensor t, Fact m) => Applicative (UCyc t m P) where+  pure = Pow . pure \\ proxy entailIndexT (Proxy::Proxy (t m r))+  (Pow f) <*> (Pow v) = Pow $ f <*> v \\ witness entailIndexT v++  {-# INLINABLE pure #-}+  {-# INLINABLE (<*>) #-}++instance (Tensor t, Fact m) => Applicative (UCyc t m D) where+  pure = Dec . pure \\ proxy entailIndexT (Proxy::Proxy (t m r))+  (Dec f) <*> (Dec v) = Dec $ f <*> v \\ witness entailIndexT v++  {-# INLINABLE pure #-}+  {-# INLINABLE (<*>) #-}+++instance (Tensor t, Fact m) => Foldable (UCyc t m P) where+  {-# INLINABLE foldr #-}+  foldr f b (Pow v) = F.foldr f b v \\ witness entailIndexT v++instance (Tensor t, Fact m) => Foldable (UCyc t m D) where+  {-# INLINABLE foldr #-}+  foldr f b (Dec v) = F.foldr f b v \\ witness entailIndexT v+++instance (Tensor t, Fact m) => Traversable (UCyc t m P) where+  {-# INLINABLE traverse #-}+  traverse f (Pow v) = Pow <$> traverse f v \\ witness entailIndexT v++instance (Tensor t, Fact m) => Traversable (UCyc t m D) where+  {-# INLINABLE traverse #-}+  traverse f (Dec v) = Dec <$> traverse f v \\ witness entailIndexT v+++---------- Utility instances ----------++instance (Random r, Tensor t, Fact m, CRTElt t r)+         => Random (Either (UCyc t m P r) (UCyc t m C r)) where++  -- create in CRTr basis if possible, otherwise in powerful+  random = let cons = fromMaybe (Left . Pow)+                      (proxyT hasCRTFuncs (Proxy::Proxy (t m r))+                       >> Just (Right . CRTr))+           in \g -> let (v,g') = random g \\ witness entailRandomT v+                    in (cons v, g')++  randomR _ = error "randomR non-sensical for UCyc"++instance (Show r, Show (CRTExt r), Tensor t, Fact m, TElt t r, TElt t (CRTExt r))+    => Show (UCyc t m rep r) where+  show (Pow  v) = "UCyc Pow: "  ++ show v \\ witness entailShowT v+  show (Dec  v) = "UCyc Dec: "  ++ show v \\ witness entailShowT v+  show (CRTr v) = "UCyc CRTr: " ++ show v \\ witness entailShowT v+  show (CRTe v) = "UCyc CRTe: " ++ show v \\ witness entailShowT v++instance (Arbitrary (t m r)) => Arbitrary (UCyc t m P r) where+  arbitrary = Pow <$> arbitrary+  shrink = shrinkNothing++instance (Arbitrary (t m r)) => Arbitrary (UCyc t m D r) where+  arbitrary = Dec <$> arbitrary+  shrink = shrinkNothing++instance (Arbitrary (t m r)) => Arbitrary (UCyc t m C r) where+  arbitrary = CRTr <$> arbitrary+  shrink = shrinkNothing++instance (Tensor t, Fact m, NFElt r, TElt t r, TElt t (CRTExt r))+         => NFData (UCyc t m rep r) where+  rnf (Pow x)    = rnf x \\ witness entailNFDataT x+  rnf (Dec x)    = rnf x \\ witness entailNFDataT x+  rnf (CRTr x)   = rnf x \\ witness entailNFDataT x+  rnf (CRTe x)   = rnf x \\ witness entailNFDataT x
+ Crypto/Lol/Factored.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE DataKinds, TemplateHaskell, TupleSections #-}++-- | This module defines types and operations for type-level+-- representation and manipulation of natural numbers, as represented+-- by their prime-power factorizations.  It relies on Template+-- Haskell, so parts of the documentation may be difficult to read.+-- See source-level comments for further details.++module Crypto.Lol.Factored+( module Crypto.Lol.FactoredDefs+-- * Convenient synonyms for 'Factored', 'PrimePower', and 'Prime' types+, module Crypto.Lol.Factored+) where++import Crypto.Lol.FactoredDefs++$(mapM fDec [1..512])+$(mapM fDec [1024,2048])++$(mapM ppDec $ (2,) <$> [1,2,3,4,5,6,7])+$(mapM ppDec $ (3,) <$> [1,2,3,4])+$(mapM ppDec $ (,1) <$> [5,7,11])++$(mapM pDec $ take 120 primes)++-- CJP: this fails to compile, as it should, because 4 is not prime+-- (sequence [ppDec (4,2)])
+ Crypto/Lol/FactoredDefs.hs view
@@ -0,0 +1,429 @@+{-# LANGUAGE ConstraintKinds, DataKinds, ExplicitNamespaces, GADTs,+             InstanceSigs, KindSignatures, PolyKinds, ScopedTypeVariables,+             TemplateHaskell, TypeFamilies, TypeOperators,+             UndecidableInstances #-}++-- | This sub-module exists only because we can't define and use+-- template Haskell splices in the same module.++module Crypto.Lol.FactoredDefs+(+-- * Factored natural numbers+  Factored, SFactored, Fact, fType, fDec+-- * Prime powers+, PrimePower, SPrimePower, Sing(SPP), PPow, ppType, ppDec+-- * Primes+, Prime, SPrime, Prim, pType, pDec+-- * Constructors+, pToPP, sPToPP, PToPP, ppToF, sPpToF, PpToF, pToF, sPToF, PToF+-- * Unwrappers+, unF, sUnF, UnF, unPP, sUnPP, UnPP, primePP, PrimePP, exponentPP, ExponentPP+-- * Arithmetic operations+, fPPMul, FPPMul, fMul, FMul, type (*)+, fDivides, FDivides, Divides, fDiv, FDiv, type (/)+, fGCD, FGCD, fLCM, FLCM, Coprime+, fOddRadical, FOddRadical+, pFree, PFree+-- * Convenient reflections+, ppsFact, valueFact, totientFact, valueHatFact, radicalFact, oddRadicalFact+, ppPPow, primePPow, exponentPPow, valuePPow, totientPPow+, valuePrime+-- * Number-theoretic laws+, transDivides, gcdDivides, lcmDivides, lcm2Divides+, pSplitTheorems, pFreeDivides+, (\\) -- re-export from Data.Constraint for convenience+-- * Utility operations on prime powers+, valueHat+, PP, ppToPP, valuePP, totientPP, radicalPP, oddRadicalPP+, valuePPs, totientPPs, radicalPPs, oddRadicalPPs+-- * Re-export+, module Crypto.Lol.PosBin+) where++import Crypto.Lol.PosBin++import Control.Arrow+import Data.Constraint           hiding ((***), (&&&))+import Data.Functor.Trans.Tagged+import Data.List                 hiding ((\\))+import Data.Singletons.Prelude   hiding ((:-))+import Data.Singletons.TH+import Language.Haskell.TH++import Unsafe.Coerce++singletons [d|++            -- CJP: record syntax doesn't work here with singletons;+            -- something about "escaped type variables"++            -- restrict to primes+            newtype Prime = P Bin deriving (Eq,Ord,Show)++            -- (prime, exponent) +            newtype PrimePower = PP (Prime,Pos) deriving (Eq,Show)++            -- Invariant: primes appear in strictly increasing+            -- order (no duplicates).+            newtype Factored = F [PrimePower] deriving (Eq,Show)++            -- Unwrap 'Prime'+            unP :: Prime -> Bin+            unP (P p) = p++            -- Unwrap 'PrimePower'.+            unPP :: PrimePower -> (Prime,Pos)+            unPP (PP pp) = pp++            -- Unwrap 'Factored'+            unF :: Factored -> [PrimePower]+            unF (F pps) = pps++            -- Prime component of a 'PrimePower'.+            primePP :: PrimePower -> Prime+            primePP = fst . unPP++            -- Exponent component of a 'PrimePower'.+            exponentPP :: PrimePower -> Pos+            exponentPP = snd . unPP++            |]++type F1 = 'F '[]++singletons [d|++            fPPMul :: PrimePower -> Factored -> Factored+            fMul :: Factored -> Factored -> Factored++            -- Multiply a 'PrimePower' into a 'Factored' number.+            fPPMul pp (F pps) = F (ppMul pp pps)++            -- Multiply two 'Factored' numbers.+            fMul (F pps1) (F pps2) = F (ppsMul pps1 pps2)++            -- helper functions (not for export)++            -- keeps primes in sorted order; merges duplicates+            ppMul :: PrimePower -> [PrimePower] -> [PrimePower]+            ppMul x [] = [x]+            ppMul pp'@(PP (p',e')) pps@(pp@(PP (p,e)):pps') =+              case compare p' p of+                EQ -> PP (p, addPos e e') : pps'+                LT -> pp' : pps+                GT -> pp : ppMul pp' pps'++            ppsMul :: [PrimePower] -> [PrimePower] -> [PrimePower]+            ppsMul [] ys = ys+            ppsMul (pp:pps) ys = ppsMul pps (ppMul pp ys)++            |]++-- ARITHMETIC OPERATIONS+singletons [d|+            pToPP :: Prime -> PrimePower+            pToPP p = PP (p, O)++            ppToF :: PrimePower -> Factored+            ppToF pp = F [pp]++            pToF :: Prime -> Factored+            pToF = ppToF . pToPP++            fGCD, fLCM :: Factored -> Factored -> Factored+            fDivides :: Factored -> Factored -> Bool+            fDiv :: Factored -> Factored -> Factored+            fOddRadical :: Factored -> Factored++            fGCD (F pps1) (F pps2) = F (ppsGCD pps1 pps2)+            fLCM (F pps1) (F pps2) = F (ppsLCM pps1 pps2)++            fDivides (F pps1) (F pps2) = ppsDivides pps1 pps2+            fDiv (F pps1) (F pps2) = F (ppsDiv pps1 pps2)+            fOddRadical (F pps) = F (ppsOddRad pps)++            -- Helper functions (not for export) on PrimePowers and+            -- lists.  Can assume that input lists obey the invariant+            -- of Factored lists, and need to ensure that output lists+            -- also obey the invariant.+            ppsGCD :: [PrimePower] -> [PrimePower] -> [PrimePower]+            ppsGCD [] _ = []+            ppsGCD (_:_) [] = []+            ppsGCD xs@(PP (p,e) : xs') ys@(PP (p',e') : ys') =+              case compare p p' of+                EQ -> PP (p, min e e') : ppsGCD xs' ys'+                LT -> ppsGCD xs' ys+                GT -> ppsGCD xs  ys'++            ppsLCM :: [PrimePower] -> [PrimePower] -> [PrimePower]+            ppsLCM [] ys = ys+            ppsLCM xs@(_:_) [] = xs+            ppsLCM xs@(pp@(PP (p,e)) : xs') ys@(pp'@(PP (p',e')) : ys') =+              case compare p p' of+                EQ -> PP (p, max e e') : ppsLCM xs' ys'+                LT -> pp  : ppsLCM xs' ys+                GT -> pp' : ppsLCM xs  ys'++            ppsDivides :: [PrimePower] -> [PrimePower] -> Bool+            ppsDivides [] _ = True+            ppsDivides (_:_) [] = False+            ppsDivides xs@(PP (p,e) : xs') (PP (p',e') : ys') =+              if p == p' then (e <= e') && ppsDivides xs' ys'+              else (p > p') && ppsDivides xs ys'++            ppsDiv :: [PrimePower] -> [PrimePower] -> [PrimePower]+            ppsDiv xs [] = xs+            ppsDiv (pp@(PP (p,e)) : xs') ys@(PP (p',e') : ys') =+              if p == p' && e' == e then ppsDiv xs' ys'+              else if p == p' && e' <= e then PP (p, subPos e e') : ppsDiv xs' ys'+              else if p <= p' then pp : ppsDiv xs' ys+              else error "invalid call to ppsDiv"++            ppsOddRad :: [PrimePower] -> [PrimePower]+            ppsOddRad [] = []+            ppsOddRad (PP (p, _) : xs') =+                if p == P (D0 B1) then ppsOddRad xs' -- D0 B1 == 2+                else PP (p,O) : ppsOddRad xs'++            |]++singletons [d|+            -- Remove all @p@-factors from a 'Factored'.+            pFree :: Prime -> Factored -> Factored+            pFree p (F pps) = F (go pps)+              where go [] = []+                    go (pp@(PP (p',_)) : ps) =+                      if p == p' then ps+                      else pp : (go ps)+            |]++-- | Type (family) synonym for division of 'Factored' types+type a / b = FDiv a b++-- | Type (family) synonym for multiplication of 'Factored' types+type a * b = FMul a b++-- convenience aliases: enforce kind, hide SingI++-- | Kind-restricted synonym for 'SingI'.+type Prim (p :: Prime) = SingI p++-- | Kind-restricted synonym for 'SingI'.+type PPow (pp :: PrimePower) = SingI pp++-- | Kind-restricted synonym for 'SingI'.+type Fact (m :: Factored) = SingI m++-- | Constraint synonym for divisibility of 'Factored' types.+type Divides m m' = (Fact m, Fact m', FDivides m m' ~ 'True)++-- | Constraint synonym for coprimality of 'Factored' types.+type Coprime m m' = (FGCD m m' ~ F1)++-- coercions: using proxy arguments here due to compiler bugs in usage++-- coerce any divisibility relationship we want+coerceFDivs :: p m -> p' m' -> (() :- (FDivides m m' ~ 'True))+coerceFDivs _ _ = Sub $ unsafeCoerce (Dict :: Dict ())++-- coerce any GCD we want+coerceGCD :: p a -> p' a' -> p'' a'' -> (() :- (FGCD a a' ~ a''))+coerceGCD _ _ _ = Sub $ unsafeCoerce (Dict :: Dict ())++-- | Entails constraint for transitivity of division, i.e.+-- if @k|l@ and @l|m@, then @k|m@.+transDivides :: forall k l m . Proxy k -> Proxy l -> Proxy m ->+                ((k `Divides` l, l `Divides` m) :- (k `Divides` m))+transDivides k _ m = Sub Dict \\ coerceFDivs k m++-- | Entailment for divisibility by GCD:+-- if @g=GCD(m1,m2)@ then @g|m1@ and @g|m2@.+gcdDivides :: forall m1 m2 g . Proxy m1 -> Proxy m2 ->+              ((Fact m1, Fact m2, g ~ FGCD m1 m2) :-+               (g `Divides` m1, g `Divides` m2))+gcdDivides m1 m2 =+  Sub $ withSingI (sFGCD (sing :: SFactored m1) (sing :: SFactored m2))+  Dict \\ coerceFDivs (Proxy::Proxy g) m1+       \\ coerceFDivs (Proxy::Proxy g) m2++-- | Entailment for LCM divisibility:+-- if @l=LCM(m1,m2)@ then @m1|l@ and @m2|l@.+lcmDivides :: forall m1 m2 l . Proxy m1 -> Proxy m2 ->+              ((Fact m1, Fact m2, l ~ FLCM m1 m2) :-+               (m1 `Divides` l, m2 `Divides` l))+lcmDivides m1 m2 =+  Sub $ withSingI (sFLCM (sing :: SFactored m1) (sing :: SFactored m2))+  Dict \\ coerceFDivs m1 (Proxy::Proxy l)+       \\ coerceFDivs m2 (Proxy::Proxy l)++-- | Entailment for LCM divisibility:+-- the LCM of two divisors of @m@ also divides @m@.+lcm2Divides :: forall m1 m2 l m . Proxy m1 -> Proxy m2 -> Proxy m ->+               ((m1 `Divides` m, m2 `Divides` m, l ~ FLCM m1 m2) :-+                (m1 `Divides` l, m2 `Divides` l, (FLCM m1 m2) `Divides` m))+lcm2Divides m1 m2 m =+  Sub $ withSingI (sFLCM (sing :: SFactored m1) (sing :: SFactored m2))+  Dict \\ coerceFDivs (Proxy::Proxy (FLCM m1 m2)) m \\ lcmDivides m1 m2++-- | Entailment for @p@-free division:+-- if @f@ is @m@ after removing all @p@-factors, then @f|m@ and+-- @gcd(f,p)=1@.+pSplitTheorems :: forall p m f . Proxy p -> Proxy m ->+                  ((Prim p, Fact m, f ~ PFree p m) :-+                   (f `Divides` m, Coprime (PToF p) f))+pSplitTheorems _ m =+  Sub $ withSingI (sPFree (sing :: SPrime p) (sing :: SFactored m))+  Dict \\ coerceFDivs (Proxy::Proxy f) m+  \\ coerceGCD (Proxy::Proxy (PToF p)) (Proxy::Proxy f) (Proxy::Proxy F1)++-- | Entailment for @p@-free division:+-- if @m|m'@, then @p-free(m) | p-free(m')@.+pFreeDivides :: forall p m m' . Proxy p -> Proxy m -> Proxy m' ->+                ((Prim p, m `Divides` m') :-+                 ((PFree p m) `Divides` (PFree p m')))+pFreeDivides _ _ _ =+  Sub $ withSingI (sPFree (sing :: SPrime p) (sing :: SFactored m)) $+        withSingI (sPFree (sing :: SPrime p) (sing :: SFactored m')) $+        Dict \\ coerceFDivs (Proxy::Proxy (PFree p m)) (Proxy::Proxy (PFree p m'))++-- | Type synonym for @(prime, exponent)@ pair.+type PP = (Int, Int)++-- | Value-level prime-power factorization tagged by a 'Factored' type.+ppsFact :: forall m . Fact m => Tagged m [PP]+ppsFact = tag $ map ppToPP $ unF $ fromSing (sing :: SFactored m)++valueFact, totientFact, valueHatFact, radicalFact, oddRadicalFact ::+  Fact m => Tagged m Int++-- | The value of a 'Factored' type.+valueFact = valuePPs <$> ppsFact++-- | The totient of a 'Factored' type's value.+totientFact = totientPPs <$> ppsFact++-- | The "hat" of a 'Factored' type's value:+-- @\hat{m}@ is @m@ if @m@ is odd, and @m/2@ otherwise.+valueHatFact = valueHat <$> valueFact++-- | The radical (product of prime divisors) of a 'Factored' type.+radicalFact = radicalPPs <$> ppsFact++-- | The odd radical (product of odd prime divisors) of a 'Factored'+-- type.+oddRadicalFact = oddRadicalPPs <$> ppsFact++-- | Reflect a 'PrimePower' type to a 'PP' value.+ppPPow :: forall pp . PPow pp => Tagged pp PP+ppPPow = tag $ ppToPP $ fromSing (sing :: SPrimePower pp)++primePPow, exponentPPow, valuePPow, totientPPow :: PPow pp => Tagged pp Int+-- | Reflect the prime component of a 'PrimePower' type.+primePPow = fst <$> ppPPow+-- | Reflect the exponent component of a 'PrimePower' type.+exponentPPow = snd <$> ppPPow+-- | The value of a 'PrimePower' type.+valuePPow = valuePP <$> ppPPow+-- | The totient of a 'PrimePower' type's value.+totientPPow = totientPP <$> ppPPow++-- | The value of a 'Prime' type.+valuePrime :: forall p . Prim p => Tagged p Int+valuePrime = tag $ binToInt $ unP $ fromSing (sing :: SPrime p)++-- | Return @m@ if @m@ is odd, and @m/2@ otherwise.+valueHat :: Integral i => i -> i+valueHat m = if m `mod` 2 == 0 then m `div` 2 else m++-- | Conversion.+ppToPP :: PrimePower -> PP+ppToPP = (binToInt . unP *** posToInt) . unPP++valuePP, totientPP, radicalPP, oddRadicalPP :: PP -> Int+-- | The value of a prime power.+valuePP (p,e) = p^e++-- | Totient of a prime power.+totientPP (_,0) = 1+totientPP (p,e) = (p-1)*(p^(e-1))++-- | The radical of a prime power.+radicalPP (_,0) = 1+radicalPP (p,_) = p++-- | The odd radical of a prime power.+oddRadicalPP (2,_) = 1+oddRadicalPP (p,_) = p++valuePPs, totientPPs, radicalPPs, oddRadicalPPs :: [PP] -> Int+-- | Product of values of individual 'PP's+valuePPs = product . map valuePP+-- | Product of totients of individual 'PP's+totientPPs = product . map totientPP+-- | Product of radicals of individual 'PP's+radicalPPs = product . map radicalPP+-- | Product of odd radicals of individual 'PP's+oddRadicalPPs = product . map oddRadicalPP+++-- | Template Haskell splice for the 'Prime' type corresponding to a+-- given positive prime integer.  (Uses 'prime' to enforce primality+-- of the base, so should only be used on small-to-moderate-sized+-- arguments.)  This is the preferred (and only) way of constructing a+-- concrete 'Prime' type (and is used to define the @Primep@ type+-- synonyms).+pType :: Int -> TypeQ+pType p+    | prime p = conT 'P `appT` binType p+    | otherwise = fail $ "pType : non-prime p " ++ show p++-- | Template Haskell splice for the 'PrimePower' type corresponding to+-- a given 'PP'.  (Calls 'pType' on the first component of its+-- argument, so should only be used on small-to-moderate-sized+-- numbers.)  This is the preferred (and only) way of constructing a+-- concrete 'PrimePower' type.+ppType :: PP -> TypeQ+ppType (p,e) = conT 'PP `appT`+               (promotedTupleT 2 `appT` pType p `appT` posType e)++-- | Template Haskell splice for the 'Factored' type corresponding to a+-- given positive integer.  Factors its argument using a naive+-- trial-division algorithm with 'primes', so should only be used on+-- small-to-moderate-sized arguments (any reasonable cyclotomic index+-- should be OK).+fType :: Int -> TypeQ+fType n = conT 'F `appT` (foldr (\pp -> appT (promotedConsT `appT` ppType pp)) +                                promotedNilT $ factorize n)++-- | Template Haskell splice that defines the 'Prime' type synonym+-- @Primep@ for a positive prime integer @p@.+pDec :: Int -> DecQ+pDec p = tySynD (mkName $ "Prime" ++ show p) [] $ pType p++-- | Template Haskell splice that defines the 'PrimePower' type synonym+-- @PPn@, where @n=p^e@.+ppDec :: PP -> DecQ+ppDec pp@(p,e) = tySynD (mkName $ "PP" ++ show (p^e)) [] $ ppType pp++-- | Template Haskell splice that defines the 'Factored' type synonym+-- @Fn@ for a positive integer @n@.+fDec :: Int -> DecQ+fDec n = tySynD (mkName $ 'F' : show n) [] $ fType n++-- | Factorize a positive integer into an ordered list of its prime+-- divisors, with multiplicities.  First argument is infinite list of+-- primes left to consider.+factorize' :: [Int] -> Int -> [Int]+factorize' _ 1 = []+factorize' ds@(d:ds') n +  | n > 1 = if d * d > n then [n]+            else let (q,r) = n `divMod` d+                 in if r == 0 then d : factorize' ds q+                    else factorize' ds' n+  | otherwise = error "can only factorize positive integers"++-- | Factorize a positive integer into a list of (prime,exponent)+-- pairs, in strictly increasing order by prime.+factorize :: Int -> [(Int,Int)]+factorize = map (head &&& length) . group . factorize' primes+
+ Crypto/Lol/Gadget.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, MultiParamTypeClasses, NoImplicitPrelude,+             PolyKinds, ScopedTypeVariables, TupleSections, TypeFamilies,+             UndecidableInstances #-}++-- | Interfaces for "gadgets," decomposition, and error correction.++module Crypto.Lol.Gadget+( Gadget(..), Decompose(..), Correct(..)+, TrivGad, BaseBGad+) where++import Crypto.Lol.LatticePrelude++import Control.Applicative+import Control.Arrow++-- | Dummy type representing the gadget @[1]@.+data TrivGad+-- | Dummy type representing the gadget @[1,b,b^2,...]@.+data BaseBGad b++-- | "Gadget" vectors, parameterized by an index type.++class Ring u => Gadget gad u where+  -- | The gadget vector over @u@.+  gadget :: Tagged gad [u]++  -- | Yield an error-tolerant encoding of an element with respect to+  -- the gadget.  (Mathematically, this should just be the product of+  -- the input with the gadget, but it is a class method to allow for+  -- optimized implementations.)+  encode :: u -> Tagged gad [u]+  encode s = ((* s) <$>) <$> gadget++-- | Decomposition relative to a gadget.++class (Gadget gad u, Reduce (DecompOf u) u) => Decompose gad u where+  -- | The ring that @u@ decomposes over.+  type DecompOf u++  -- | Yield a short vector @x@ such that @\<g, x\> = u@.+  decompose :: u -> Tagged gad [DecompOf u]++-- | Error correction relative to a gadget.++class Gadget gad u => Correct gad u where++  -- | Error-correct a "noisy" encoding of an element (see 'encode'),+  -- returning the encoded element and the error vector.+  correct :: Tagged gad [u] -> (u, [LiftOf u])+++-- instances for products++instance (Gadget gad a, Gadget gad b) => Gadget gad (a,b) where++  gadget = (++) <$> (map (,zero) <$> gadget) <*> (map (zero,) <$> gadget)++instance (Decompose gad a, Decompose gad b, DecompOf a ~ DecompOf b)+         => Decompose gad (a,b) where++  type DecompOf (a,b) = DecompOf a+  decompose (a,b) = (++) <$> decompose a <*> decompose b++instance (Correct gad a, Correct gad b,+          Mod a, Mod b, Field a, Field b, Lift' a, Lift' b,+          ToInteger (LiftOf a), ToInteger (LiftOf b))+    => Correct gad (a,b) where++  correct =+    let gada = gadget :: Tagged gad [a]+        gadb = gadget :: Tagged gad [b]+        ka = length gada+        qaval = toInteger $ proxy modulus (Proxy::Proxy a)+        qbval = toInteger $ proxy modulus (Proxy::Proxy b)+        qamod = fromIntegral qaval+        qbmod = fromIntegral qbval+        qainv = recip qamod+        qbinv = recip qbmod+    in \tv ->+        let v = untag tv+            (wa,wb) = splitAt ka v+            (va,xb) = unzip $+                      (\(a,b) -> let x = toInteger $ lift b+                                 in (qbinv * (a - fromIntegral x), x)) <$> wa+            (vb,xa) = unzip $+                      (\(a,b) -> let x = toInteger $ lift a+                                 in (qainv * (b - fromIntegral x), x)) <$> wb+            (sa,ea) = (qbmod *) ***+                      zipWith (\x e -> x + qbval * toInteger e) xb $+                      correct (tag va `asTypeOf` gada)+            (sb,eb) = (qamod *) ***+                      zipWith (\x e -> x + qaval * toInteger e) xa $+                      correct (tag vb `asTypeOf` gadb)+        in ((sa,sb), ea ++ eb)+++{- CJP: strawman class for the more general view of LWE secrets as+"module characters," i.e., module homomorphisms into a particular+range.  This is probably wrong, though.++class Character u where       -- Module superclass(es)?+  type CharRange u+  data Char u                   -- need data for injectivity++  evalChar :: Char u -> u -> CharRange u++class (Gadget gad u, Character u) => Correct gad u where++  -- | Correct a "noisy" encoding of an LWE secret (i.e., a+  -- 'ModuleHomom' on 'u').+  correct :: Tagged gad [CharRange u] -> Char u++encode :: (Correct gad u) => Char u -> Tagged gad [CharRange u]+encode s = pasteT $ evalMH s <$> peelT gadget++-}+
+ Crypto/Lol/GaussRandom.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables #-}++-- | Functions for sampling from a continuous Gaussian distribution++module Crypto.Lol.GaussRandom+( realGaussian, realGaussians ) where++import Crypto.Lol.LatticePrelude++import qualified Data.Vector.Generic as V++import Control.Monad+import Control.Monad.Random++-- | Using polar form of Box-Muller transform, returns a pair of+-- centered, Gaussian-distributed real numbers with scaled variance+-- @svar = true variance * (2*pi)@. See+-- <http://www.alpheratz.net/murison/Maple/GaussianDistribution/GaussianDistribution.pdf+-- this link> for details.++realGaussian :: forall v q m .+                (ToRational v, OrdFloat q, Random q, MonadRandom m)+                => v -> m (q,q)+realGaussian svar =+    let var = realToField svar / pi :: q -- twice true variance+    in do (u,v) <- iterateWhile uvGuard getUV+          let t = u*u+v*v+              com = sqrt (-var * log t / t)+          -- we can either sample u,v from [-1,1]+          -- or generate sign bits for the outputs+          s1 <- getRandom+          s2 <- getRandom+          let u' = if s1 then u else -u+              v' = if s2 then v else -v+          return (u'*com,v'*com)+    where getUV = do u <- getRandomR (zero,one)+                     v <- getRandomR (zero,one)+                     return (u,v)+          uvGuard (u,v) = (u*u+v*v >= one) || (u*u+v*v == zero)++-- | Generate @n@ real, independent gaussians of scaled variance @svar+-- = true variance * (2*pi)@.+realGaussians ::+    (ToRational svar, OrdFloat i, Random i, V.Vector v i, MonadRandom m)+    => svar -> Int -> m (v i)+realGaussians var n+    | odd n = liftM V.tail (realGaussians var (n+1)) -- O(1) tail+    | otherwise = liftM (V.fromList . uncurry (++) . unzip) $+                  replicateM (n `div` 2) (realGaussian var)+++++++-- Taken from monad-loops-0.4.3++-- | Execute an action repeatedly until its result fails to satisfy a predicate,+-- and return that result (discarding all others).+iterateWhile :: (Monad m) => (a -> Bool) -> m a -> m a+iterateWhile p x = x >>= iterateUntilM (not . p) (const x)++-- | Analogue of @('Prelude.until')@+-- Yields the result of applying f until p holds.+iterateUntilM :: (Monad m) => (a -> Bool) -> (a -> m a) -> a -> m a+iterateUntilM p f v +    | p v       = return v+    | otherwise = f v >>= iterateUntilM p f++{-+-- | Returns a Gaussian-distributed sample over 'pZ' with given+-- (scaled) variance parameter @v=var/(2*pi)@ and center, using+-- rejection sampling++gaussRound :: (RealTranscendental v, Random v,+               RealRing c, ToRational c,+               Ring i, ToInteger i, Random i, MonadRandom m)+               => v -> c -> m i+gaussRound svar c =+    let dev = ceiling $ 6 * sqrt svar -- 6 gives stat dist < 2^-163+        lower = floor c - dev+        upper = ceiling c + dev+        sampler = do+           z <- getRandomR (lower, upper)+           u <- getRandomR (zero, one)+           let dist = fromIntegral z - realToField c+           let prob = exp (-pi * (dist*dist / svar))+           if u <= prob then return z else sampler+    in sampler+-}
+ Crypto/Lol/LatticePrelude.hs view
@@ -0,0 +1,276 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, FunctionalDependencies,+             GeneralizedNewtypeDeriving, MultiParamTypeClasses,+             NoImplicitPrelude, PolyKinds, RankNTypes, RebindableSyntax,+             ScopedTypeVariables, StandaloneDeriving, TemplateHaskell,+             TypeFamilies, TypeOperators, UndecidableInstances #-}++-- | A substitute for the Prelude that is more suitable for Lol.  This+-- module exports most of the Numeric Prelude and other frequently+-- used modules, plus some low-level classes, missing instances, and+-- assorted utility functions.++module Crypto.Lol.LatticePrelude+(+-- * Classes and families+  Enumerable(..)+, Mod(..)+, Reduce(..), LiftOf, Lift, Lift'(..), Rescale(..), Encode(..), msdToLSD+, CharOf+-- * Numeric+, module Crypto.Lol.Types.Numeric+-- * Complex+, module Crypto.Lol.Types.Complex+-- * Factored+, module Crypto.Lol.Factored+-- * Miscellaneous+, rescaleMod, roundCoset+, fromJust', pureT, peelT, pasteT, withWitness, withWitnessT+, module Data.Functor.Trans.Tagged+, module Data.Proxy+) where++import Crypto.Lol.Factored+import Crypto.Lol.Types.Complex+import Crypto.Lol.Types.Numeric++import Algebra.Field          as Field (C)+import Algebra.IntegralDomain as IntegralDomain (C)+import Algebra.Ring           as Ring (C)++import Control.Applicative+import Control.Arrow+import Control.DeepSeq+import Control.Monad.Identity+import Control.Monad.Random+import Data.Coerce+import Data.Default+import Data.Functor.Trans.Tagged+import Data.Maybe+import Data.Proxy+import Data.Singletons++-- for Unbox instance of Maybe a+import qualified Data.Vector.Unboxed          as U+import           Data.Vector.Unboxed.Deriving++instance NFData (Proxy (a :: k)) where rnf Proxy = ()++deriving instance NFData (m a) => NFData (TaggedT s m a)+deriving instance (MonadRandom m) => MonadRandom (TaggedT (tag :: k) m)++derivingUnbox "Maybe"+  [t| forall a . (Default a, U.Unbox a) => Maybe a -> (Bool, a) |]+  [| maybe (False, def) (\ x -> (True, x)) |]+  [| \ (b, x) -> if b then Just x else Nothing |]++instance Default Bool where def = False++-- | The characteristic of a ring, represented as a type.+type family CharOf fp :: k++-- | Poor man's 'Enum'.+class Enumerable a where+  values :: [a]++-- | Represents a quotient group modulo some integer.+class (ToInteger (ModRep a), Additive a) => Mod a where+  type ModRep a+  modulus :: Tagged a (ModRep a)++-- | Represents that @b@ is a quotient group of @a@.+class (Additive a, Additive b) => Reduce a b where+  reduce :: a -> b++-- | Represents that @b@ can be lifted to a "short" @a@ congruent to @b@.+type Lift b a = (Lift' b, LiftOf b ~ a)++-- | The type of representatives of @b@.+type family LiftOf b++-- | Fun-dep version of Lift.+class (Reduce (LiftOf b) b) => Lift' b where+  lift :: b -> LiftOf b++-- | Represents that @a@ can be rescaled to @b@, as an "approximate"+-- additive homomorphism.+class (Additive a, Additive b) => Rescale a b where+  rescale :: a -> b++-- | Represents that the target ring can "noisily encode" values from+-- the source ring, in either "most significant digit" (MSD) or "least+-- significant digit" (LSD) encodings, and provides conversion factors+-- between the two types of encodings.++class (Field src, Field tgt) => Encode src tgt where+    -- | The factor that converts an element from LSD to MSD encoding+    -- in the target field, with associated scale factor to apply to+    -- correct the resulting encoded value.+    lsdToMSD :: (src, tgt)++-- | Inverted entries of 'lsdToMSD'.+msdToLSD :: (Encode src tgt) => (src, tgt)+msdToLSD = (recip *** recip) lsdToMSD+{-# INLINABLE msdToLSD #-}++-- | A default implementation of rescaling for 'Mod' types.+rescaleMod :: forall a b .+              (Mod a, Mod b, (ModRep a) ~ (ModRep b),+               Lift a (ModRep b), Ring b)+              => a -> b+{-# INLINABLE rescaleMod #-}+rescaleMod =+    let qval = proxy modulus (Proxy :: Proxy a)+        q'val = proxy modulus (Proxy :: Proxy b)+    in \x -> let (quot',_) = divModCent (q'val * lift x) qval+             in fromIntegral quot'++-- | Deterministically round to a nearby value in the desired coset+roundCoset :: forall zp z r .+              (Mod zp, z ~ ModRep zp, Lift zp z, RealField r) => zp -> r -> z+{-# INLINABLE roundCoset #-}+roundCoset = let pval = proxy modulus (Proxy::Proxy zp)+             in \ zp x -> let rep = lift zp+                          in rep + roundMult pval (x - fromIntegral rep)++---------- Instances for product groups/rings ----------++type instance LiftOf (a,b) = Integer++instance (Mod a, Mod b, Lift' a, Lift' b, Reduce Integer (a,b),+          ToInteger (LiftOf a), ToInteger (LiftOf b))+         => Lift' (a,b) where++  {-# INLINABLE lift #-}+  lift (a,b) =+    let moda = toInteger $ proxy modulus (Proxy::Proxy a)+        modb = toInteger $ proxy modulus (Proxy::Proxy b)+        q = moda * modb+        ainv = fromMaybe (error "Lift' (a,b): moduli not coprime") $ moda `modinv` modb+        lifta = toInteger $ lift a+        liftb = toInteger $ lift b+        -- put in [-q/2, q/2)+        (_,r) = (moda * (liftb - lifta) * ainv + lifta) `divModCent` q+    in r+++-- NP should define Ring and Field instances for pairs, but doesn't.+-- So we do it here.+instance (Ring r1, Ring r2) => Ring.C (r1, r2) where+  (x1, x2) * (y1, y2) = (x1*y1, x2*y2)+  one = (one,one)+  fromInteger x = (fromInteger x, fromInteger x)++  {-# INLINABLE (*) #-}+  {-# INLINABLE one #-}+  {-# INLINABLE fromInteger #-}++instance (Field f1, Field f2) => Field.C (f1, f2) where+  (x1, x2) / (y1, y2) = (x1 / y1, x2 / y2)+  recip = recip *** recip+  {-# INLINABLE (/) #-}+  {-# INLINABLE recip #-}++instance (IntegralDomain a, IntegralDomain b) => IntegralDomain.C (a,b) where+  (a1,b1) `divMod` (a2,b2) =+    let (da,ra) = (a1 `divMod` a2)+        (db,rb) = (b1 `divMod` b2)+    in ((da,db), (ra,rb))+  {-# INLINABLE divMod #-}++instance (Mod a, Mod b) => Mod (a,b) where+  type ModRep (a,b) = Integer++  modulus = tag $ fromIntegral (proxy modulus (Proxy::Proxy a)) *+            fromIntegral (proxy modulus (Proxy::Proxy b))+  {-# INLINABLE modulus #-}++instance (Reduce a b1, Reduce a b2) => Reduce a (b1, b2) where+  reduce x = (reduce x, reduce x)+  {-# INLINABLE reduce #-}++-- instances of Rescale for a product+instance (Mod a, Field b, Lift a (ModRep a), Reduce (LiftOf a) b)+         => Rescale (a,b) b where+  rescale = let q1val = proxy modulus (Proxy::Proxy a)+                q1inv = recip $ reduce q1val+            in \(x1,x2) -> q1inv * (x2 - reduce (lift x1))+  {-# INLINABLE rescale #-}++instance (Mod b, Field a, Lift b (ModRep b), Reduce (LiftOf b) a)+         => Rescale (a,b) a where+  rescale = let q2val = proxy modulus (Proxy::Proxy b)+                q2inv = recip $ reduce q2val+            in \(x1,x2) -> q2inv * (x1 - reduce (lift x2))+  {-# INLINABLE rescale #-}++-- some multi-step scaledowns; could do this forever+instance (Rescale (a,(b,c)) (b,c), Rescale (b,c) c)+         => Rescale (a,(b,c)) c where+  rescale = (rescale :: (b,c) -> c) . rescale+  {-# INLINABLE rescale #-}++instance (Rescale ((a,b),c) (a,b), Rescale (a,b) a)+         => Rescale ((a,b),c) a where+  rescale = (rescale :: (a,b) -> a) . rescale+  {-# INLINABLE rescale #-}++-- scaling up to a product+instance (Ring a, Mod b, Reduce (ModRep b) a) => Rescale a (a,b) where+  -- multiply by q2+  rescale = let q2val = reduce $ proxy modulus (Proxy::Proxy b)+            in \x -> (q2val * x, zero)+  {-# INLINABLE rescale #-}++instance (Ring b, Mod a, Reduce (ModRep a) b) => Rescale b (a,b) where+  -- multiply by q1+  rescale = let q1val = reduce $ proxy modulus (Proxy::Proxy a)+            in \x -> (zero, q1val * x)+  {-# INLINABLE rescale #-}++-- Instance of 'Encode' for product ring.+instance (Encode s t1, Encode s t2, Field (t1, t2)) => Encode s (t1, t2) where+  {-# INLINABLE lsdToMSD #-}+  lsdToMSD = let (s1, t1conv) = lsdToMSD+                 (s2, t2conv) = lsdToMSD+             in (negate s1 * s2, (t1conv,t2conv))++-- Random could have defined this instance, but didn't, so we do it+-- here.+instance (Random a, Random b) => Random (a,b) where+  {-# INLINABLE random #-}+  random g = let (a,g') = random g+                 (b, g'') = random g'+             in ((a,b), g'')++  {-# INLINABLE randomR #-}+  randomR ((loa,lob), (hia,hib)) g = let (a,g') = randomR (loa,hia) g+                                         (b,g'') = randomR (lob,hib) g'+                                     in ((a,b),g'')++-- | Version of 'fromJust' with an error message.+fromJust' :: String -> Maybe a -> a+fromJust' str = fromMaybe (error str)++-- | Apply any applicative to a Tagged value.+pureT :: Applicative f => TaggedT t Identity a -> TaggedT t f a+pureT = mapTaggedT (pure . runIdentity)++-- | Expose the monad of a tagged value.+peelT :: Tagged t (f a) -> TaggedT t f a+peelT = coerce++-- | Hide the monad of a tagged value.+pasteT :: TaggedT t f a -> Tagged t (f a)+pasteT = coerce++-- | Use a singleton as a witness to extract a value from a tagged value.+withWitness :: forall n r . (SingI n => Tagged n r) -> Sing n -> r+withWitness t wit = withSingI wit $ proxy t (Proxy::Proxy n)+{-# INLINABLE withWitness #-}++-- | Transformer version of 'withWitness'.+withWitnessT :: forall n mon r .+                (SingI n => TaggedT n mon r) -> Sing n -> mon r+withWitnessT t wit = withSingI wit $ proxyT t (Proxy::Proxy n)+{-# INLINABLE withWitnessT #-}
+ Crypto/Lol/PosBin.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE DataKinds, TemplateHaskell #-}++-- | Positive naturals in Peano and binary representations,+-- singletonized and promoted to the type level.  This module relies+-- on Template Haskell, so parts of the documentation may be difficult+-- to read.  See source-level comments for further details.++module Crypto.Lol.PosBin+( module Crypto.Lol.PosBinDefs+-- * Convenient synonyms for 'Pos' and 'Bin' types+, module Crypto.Lol.PosBin+) where++import Crypto.Lol.PosBinDefs++$(mapM posDec [1..16])++$(mapM binDec [1..128])
+ Crypto/Lol/PosBinDefs.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE ConstraintKinds, DataKinds, GADTs, InstanceSigs,+             KindSignatures, NoImplicitPrelude, PolyKinds,+             RebindableSyntax, ScopedTypeVariables, TemplateHaskell,+             TypeFamilies, UndecidableInstances #-}++-- | This sub-module exists only because we can't define and use+-- template Haskell splices in the same module.++module Crypto.Lol.PosBinDefs+( -- * Positive naturals in Peano representation+  Pos(..), Sing(SO, SS), SPos, PosC+, posToInt, addPos, sAddPos, AddPos, subPos, sSubPos, SubPos+, posType, posDec+, OSym0, SSym0, SSym1, AddPosSym0, AddPosSym1, SubPosSym0, SubPosSym1+  -- * Positive naturals in binary representation+, Bin(..), Sing(SB1, SD0, SD1), SBin, BinC+, binToInt, binType, binDec+, B1Sym0, D0Sym0, D0Sym1, D1Sym0, D1Sym1+  -- * Miscellaneous+, intDec, primes, prime+)+where++import Data.Singletons.Prelude+import Data.Singletons.TH+import Language.Haskell.TH++import Algebra.ToInteger as ToInteger+import NumericPrelude++singletons [d|+            -- Positive naturals (1, 2, ...) in Peano representation.+            data Pos = O     -- one+                     | S Pos -- successor+                       deriving (Show, Eq)++            instance Ord Pos where+              compare O O          = EQ+              compare O (S _)      = LT+              compare (S _) O      = GT+              compare (S a) (S b)  = compare a b++            addPos :: Pos -> Pos -> Pos+            addPos O b      = S b+            addPos (S a) b  = S $ addPos a b++            subPos :: Pos -> Pos -> Pos+            subPos (S a) O      = a+            subPos (S a) (S b)  = subPos a b+            subPos O _          = error "Invalid call to subPos: a <= b"++           |]++-- not promotable due to numeric output++-- | Convert a 'Pos' to an integral type.+posToInt :: ToInteger.C z => Pos -> z+posToInt O = one+posToInt (S a) = one + posToInt a++singletons [d|+            -- Positive naturals in binary representation.+            data Bin = B1       -- 1+                     | D0 Bin   -- 2*b (double)+                     | D1 Bin   -- 1 + 2*b (double and increment)+                       deriving (Show, Eq)++            instance Ord Bin where+              compare B1 B1          = EQ+              compare B1 (D0 _)      = LT+              compare B1 (D1 _)      = LT+              compare (D0 _) B1      = GT+              compare (D1 _) B1      = GT+              compare (D0 a) (D0 b)  = compare a b+              compare (D1 a) (D1 b)  = compare a b+              compare (D0 a) (D1 b)  = case compare a b of+                                       EQ -> LT+                                       LT -> LT+                                       GT -> GT+              compare (D1 a) (D0 b)  = case compare a b of+                                       EQ -> GT+                                       LT -> LT+                                       GT -> GT++           |]++-- | Convert a 'Bin' to an integral type.+binToInt :: ToInteger.C z => Bin -> z+binToInt B1 = one+binToInt (D0 a) = 2 * binToInt a+binToInt (D1 a) = 1 + 2 * binToInt a++-- | Kind-restricted synonym for 'SingI'.+type PosC (p :: Pos) = SingI p++-- | Kind-restricted synonym for 'SingI'.+type BinC (b :: Bin) = SingI b++-- | Template Haskell splice for the 'Pos' type+-- representing a given 'Int', e.g., @$(posType 8)@.+posType :: Int -> TypeQ+posType n+    | n <= 0 = fail $ "posType: non-positive argument n = " ++ show n+    | n == 1 = conT 'O+    | otherwise = conT 'S `appT` posType (n-1)++-- | Template Haskell splice for the 'Bin' type+-- representing a given 'Int', e.g., @$(binType 89)@.+binType :: Int -> TypeQ+binType n+    | n <= 0 = fail $ "binType: non-positive argument n = " ++ show n+    | otherwise = case n `quotRem` 2 of+                    (0,1) -> conT 'B1+                    (q,0) -> conT 'D0 `appT` binType q+                    (q,1) -> conT 'D1 `appT` binType q+                    _ -> fail "internal error in PosBinTH.bin"++posDec, binDec :: Int -> DecQ+-- | Template Haskell splice that defines the 'Pos' type synonym @Pn@.+posDec = intDec "P" posType+-- | Template Haskell splice that defines the 'Bin' type synonym @Bn@.+binDec = intDec "B" binType++-- | Template Haskell splice that declares a type synonym+-- @<pfx>n@ as the type @f n@.+intDec :: String               -- ^ @pfx@+       -> (Int -> TypeQ)       -- ^ @f@+       -> Int                  -- ^ @n@+       -> DecQ+intDec pfx f n = tySynD (mkName $ pfx ++ show n) [] (f n)++-- | Infinite list of primes, built using Sieve of Erastothenes.+primes :: [Int]+primes = 2 : 3 : 5 : primes'+  where+    isPrime (p:ps) n = p*p > n || n `rem` p /= 0 && isPrime ps n+    primes' = 7 : filter (isPrime primes') (scanl (+) 11 $ cycle [2,4,2,4,6,2,6,4])++-- | Search for the argument in 'primes'.  This is not particularly+-- fast, but works well enough for moderate-sized numbers that would+-- appear as (divisors of) cyclotomic indices of interest.+prime :: Int -> Bool+prime = go primes+    where go (p:ps) n = case compare p n of+                          LT -> go ps n+                          EQ -> True+                          GT -> False
+ Crypto/Lol/Reflects.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances,+             KindSignatures, MultiParamTypeClasses, NoImplicitPrelude,+             PolyKinds, ScopedTypeVariables, UndecidableInstances #-}++-- | Generic interface for reflecting types to values.++module Crypto.Lol.Reflects+( Reflects(..)+) where++import Algebra.ToInteger as ToInteger+import NumericPrelude++import Crypto.Lol.Factored++import Control.Applicative+import Data.Functor.Trans.Tagged+import Data.Proxy+import Data.Reflection+import GHC.TypeLits              as TL++-- | Reflection without fundep, and with tagged value. Intended only+-- for low-level code; build specialized wrappers around it for+-- specific functionality.++class Reflects a i where+  -- | Reflect the value assiated with the type @a@.+  value :: Tagged a i++instance (KnownNat a, ToInteger.C i) => Reflects (a :: TL.Nat) i where+  value = tag $ fromIntegral $ natVal (Proxy::Proxy a)++{-++instance (PosC a, ToInteger.C i) => Reflects a i where+  value = tag $ posToInt $ fromSing (sing :: Sing a)++instance (BinC a, ToInteger.C i) => Reflects a i where+  value = tag $ binToInt $ fromSing (sing :: Sing a)++-}++-- CJP: need reflections for Prime and PrimePower types because we use+-- them with ZqBasic++instance (Prim p, ToInteger.C i) => Reflects p i where+  value = fromIntegral <$> valuePrime++instance (PPow pp, ToInteger.C i) => Reflects pp i where+  value = fromIntegral <$> valuePPow++-- CJP: need this for Types.ZmStar, where we use ZqBasic m Int+instance (Fact m, ToInteger.C i) => Reflects m i where+  value = fromIntegral <$> valueFact++instance {-# OVERLAPS #-} (Reifies rei a) => Reflects (rei :: *) a where+  value = tag $ reflect (Proxy::Proxy rei)
+ Crypto/Lol/Types/Complex.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances,+             GeneralizedNewtypeDeriving, MultiParamTypeClasses,+             NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables,+             StandaloneDeriving, TemplateHaskell, TypeFamilies,+             UndecidableInstances #-}++-- | Data type, functions, and instances for complex numbers.++module Crypto.Lol.Types.Complex (+  Complex+, roundComplex+, cis, real, imag, fromReal+) where++import           Algebra.Additive       as Additive (C)+import           Algebra.Field          as Field (C)+import           Algebra.IntegralDomain as IntegralDomain+import           Algebra.Ring           as Ring (C)+import           Algebra.ZeroTestable   as ZeroTestable (C)+import qualified Number.Complex         as C hiding (exp, signum)++import Crypto.Lol.Types.Numeric as LP++import Control.DeepSeq+import Data.Array.Repa.Eval         as R+import Data.Vector.Storable         (Storable)+import Data.Vector.Unboxed          (Unbox)+import Data.Vector.Unboxed.Deriving+import System.Random+import Test.QuickCheck++-- | Newtype wrapper (with slightly different instances) for+-- <https://hackage.haskell.org/package/numeric-prelude-0.4.2/docs/Number-Complex.html numeric-prelude Complex>.+newtype Complex a = Complex (C.T a) deriving (Additive.C, Ring.C, ZeroTestable.C, Field.C, Storable, Eq, Show, Arbitrary)++derivingUnbox "Complex"+  [t| forall a . (Unbox a) => Complex a -> (a, a) |]+  [| \ (Complex x) -> (C.real x, C.imag x) |]+  [| \ (r, i) -> Complex $ r C.+: i |]++-- a custom IntegralDomain instance, replacing the one provided by NP.+-- it always returns 0 as the remainder of a division.  If we were to+-- use the NP instance, sometimes precision issues yield nonzero+-- remainders, which makes, e.g., 'divGPow' think that division has+-- failed, when it has not.  This in turn causes 'divGCRT' to yield+-- Nothing, among other problems.+instance (Field a) => IntegralDomain.C (Complex a) where+  (Complex a) `divMod` (Complex b) = (Complex $ a / b, LP.zero)++-- we can't use Generics for NFData because NP doesn't export the+-- (deep) constructor for Complex.T+instance (NFData a) => NFData (Complex a) where+  rnf (Complex x) = let r = C.real x+                        i = C.imag x+                    in rnf r `seq` rnf i `seq` ()++instance (Random a) => Random (Complex a) where+    random g = let (a,g') = random g+                   (b,g'') = random g'+               in (Complex $ a C.+: b, g'')++    randomR = error "randomR not defined for (Complex t)"++instance (R.Elt a) => R.Elt (Complex a) where+    touch (Complex c) = do+        touch $ C.real c+        touch $ C.imag c+    zero = Complex $ R.zero C.+: R.zero+    one = Complex $ R.one C.+: R.zero++-- | Rounds the real and imaginary components to the nearest integer.+roundComplex :: (RealRing a, ToInteger b) => Complex a -> (b,b)+roundComplex (Complex x) = (round $ C.real x, round $ C.imag x)++-- | 'cis' @t@ is a complex value with magnitude 1 and phase t (modulo @2*Pi@).+cis :: Transcendental a => a -> Complex a+cis = Complex . C.cis++-- | Real component of a complex number.+real :: Complex a -> a+real (Complex a) = C.real a++-- | Imaginary component of a complex number.+imag :: Complex a -> a+imag (Complex a) = C.imag a++-- | Embeds a scalar as the real component of a complex number.+fromReal :: Additive a => a -> Complex a+fromReal = Complex . C.fromReal
+ Crypto/Lol/Types/FiniteField.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             GeneralizedNewtypeDeriving, MultiParamTypeClasses,+             NoImplicitPrelude, PolyKinds, RebindableSyntax,+             RoleAnnotations, ScopedTypeVariables, TypeFamilies,+             UndecidableInstances #-}++-- CJP: need PolyKinds to allow d to have non-* kind++-- | Basic (unoptimized) finite field arithmetic.++module Crypto.Lol.Types.FiniteField+( GF                            -- export type but not constructor+, PrimeField, GFCtx+, size, trace, toList, fromList+, IrreduciblePoly(..), X(..), (^^)+, TensorCoeffs(..)+) where++import Crypto.Lol.CRTrans+import Crypto.Lol.Factored+import Crypto.Lol.LatticePrelude+import Crypto.Lol.Reflects++import Algebra.Additive     as Additive (C)+import Algebra.Field        as Field (C)+import Algebra.Module       as Module (C)+import Algebra.Ring         as Ring (C)+import Algebra.ZeroTestable as ZeroTestable (C)+import MathObj.Polynomial++import Math.NumberTheory.Primes.Factorisation++import           Control.Applicative hiding ((*>))+import           Control.DeepSeq+import           Control.Monad+import qualified Data.Vector         as V++--import qualified Debug.Trace as DT++-- | A finite field of given degree over @F_p@.+newtype GF fp d = GF (Polynomial fp)+                  deriving (Eq, Show, Additive.C, ZeroTestable.C, NFData)++-- the second argument, though phantom, affects representation+type role GF representational representational++type PrimeField fp = (Enumerable fp, Field fp, Eq fp, ZeroTestable fp,+                      Prim (CharOf fp), IrreduciblePoly fp)++type GFCtx fp d = (PrimeField fp, Reflects d Int)++instance (GFCtx fp d) => Enumerable (GF fp d) where+  values = GF <$> fromCoeffs <$>+           -- d-fold cartesian product of Fp values+           replicateM (proxy value (Proxy::Proxy d)) values++instance (GFCtx fp d) => Ring.C (GF fp d) where++  one = GF one++  (*) = let poly = proxy irreduciblePoly (Proxy :: Proxy d)+        in \(GF f) (GF g) -> GF $ (f*g) `mod` poly++  fromInteger = GF . fromInteger++instance (GFCtx fp d) => Field.C (GF fp d) where++  recip = let g = proxy irreduciblePoly (Proxy :: Proxy d)+          in \(GF f) -> let (_,(a,_)) = extendedGCD f g+                           in GF a++instance (GFCtx fp d) => CRTrans (GF fp d) where++  crtInfo m = (,) <$> omegaPow <*> scalarInv+    where+      omegaPow =+        let size' = proxy size (Proxy :: Proxy (GF fp d))+            (q,r) = (size'-1) `quotRem` m+            gen = head $ filter isPrimitive values+            omega = gen^q+            omegaPows = V.iterateN m (*omega) one+        in if r == 0+           then Just $ (omegaPows V.!) . (`mod` m)+           else Nothing+      scalarInv = Just $ recip $ fromIntegral $ valueHat m++newtype TensorCoeffs a = Coeffs {unCoeffs :: [a]} deriving (Additive.C)+instance (Additive fp, Ring (GF fp d), Reflects d Int)+  => Module.C (GF fp d) (TensorCoeffs fp) where++  r *> (Coeffs fps) = +    let dval = proxy value (Proxy::Proxy d)+        n = length fps+    in if n `mod` dval /= 0 then+                error $ "FiniteField: d (= " ++ show dval +++                          ") does not divide n (= " ++ show n ++ ")"+       else Coeffs $ concat ((toList . (r *) . fromList) <$> chunksOf dval fps)++chunksOf :: Int -> [a] -> [[a]]+chunksOf _ [] = []+chunksOf n xs+  | n > 0 = let (h,t) = splitAt n xs in h : chunksOf n t+  | otherwise = error "chunksOf: non-positive n"++-- | Yield a list of length exactly @d@ (i.e., including trailing zeros)+-- of the @fp@-coefficients with respect to the power basis+toList :: forall fp d . (Reflects d Int, Additive fp) => GF fp d -> [fp]+toList = let dval = proxy value (Proxy::Proxy d)+         in \(GF p) -> let l = coeffs p+                       in l ++ (replicate (dval - length l) zero)++-- | Yield a field element given up to @d@ coefficients with respect+-- to the power basis.+fromList :: forall fp d . (Reflects d Int) => [fp] -> GF fp d+fromList = let dval = proxy value (Proxy::Proxy d)+           in \cs -> if length cs <= dval then GF $ fromCoeffs cs+                     else error $ "FiniteField.fromList: length " ++ +                              show (length cs) ++ " > degree " ++ show dval++sizePP :: forall fp d . (GFCtx fp d) => Tagged (GF fp d) PP+sizePP = tag (proxy valuePrime (Proxy::Proxy (CharOf fp)),+              proxy value (Proxy::Proxy d))++-- | The order of the field: @size (GF fp d) = p^d@+size :: (GFCtx fp d) => Tagged (GF fp d) Int+size = uncurry (^) <$> sizePP++isPrimitive :: forall fp d . (GFCtx fp d) => GF fp d -> Bool+isPrimitive = let q = proxy size (Proxy :: Proxy (GF fp d))+                  ps = map (fromIntegral . fst) $ factorise $+                       fromIntegral $ q-1+                  exps = map ((q-1) `div`) ps+              in \g -> not (isZero g) && all (\e -> g^e /= 1) exps++dotp :: (Ring a) => [a] -> [a] -> a+dotp a b = sum $ zipWith (*) a b++-- | Trace into the prime subfield.+trace :: forall fp d . (GFCtx fp d) => GF fp d -> fp+trace = let ts = proxy powTraces (Proxy::Proxy (GF fp d))+        in \(GF f) -> dotp ts (coeffs f)++-- | Traces of the power basis elements 1, x, x^2, ..., x^(d-1).+powTraces :: forall fp d . (GFCtx fp d) => Tagged (GF fp d) [fp]+powTraces =+  --DT.trace ("FiniteField.powTraces: p = " +++  --          show (proxy value (Proxy::Proxy (CharOf fp)) :: Int) +++  --          ", d = " ++ show (proxy value (Proxy::Proxy d) :: Int)) $+  let d = proxy value (Proxy :: Proxy d)+  in tag $ map trace' $ take d $+     iterate (* (GF (X ^^ 1))) (one :: GF fp d)++-- helper that computes trace via brute force: sum frobenius+-- automorphisms+trace' :: (GFCtx fp d) => GF fp d -> fp+trace' e = let (p,d) = witness sizePP e+               (GF t) = sum $ take d $ iterate (^p) e+               -- t is a constant polynomial+           in head $ coeffs t++-- | Represents fields over which we can get irreducible+-- polynomials of desired degrees.  (An instance of this class is+-- defined in 'Crypto.Lol.Types.IrreducibleChar2' and exported from+-- 'Crypto.Lol'.)+class Field fp => IrreduciblePoly fp where+  irreduciblePoly :: (Reflects d Int) => Tagged d (Polynomial fp)++-- | Convenience data type for writing 'IrreduciblePoly' instances.+data X = X++-- | Convenience function for writing 'IrreduciblePoly' instances.+(^^) :: Ring a => X -> Int -> Polynomial a+X ^^ i | i >= 0 = fromCoeffs $ replicate i 0 ++ [1]+_ ^^ _ = error "FiniteField.(^^) only defined for non-negative exponents."
+ Crypto/Lol/Types/IZipVector.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE ConstraintKinds, DataKinds, DeriveTraversable,+             FlexibleContexts, GeneralizedNewtypeDeriving, KindSignatures,+             MultiParamTypeClasses, RoleAnnotations, ScopedTypeVariables,+             TypeFamilies, UndecidableInstances #-}++-- | Provides applicative-like functions for indexed vectors++module Crypto.Lol.Types.IZipVector+( IZipVector, iZipVector, unIZipVector, unzipIZV+) where++import Crypto.Lol.Factored++import Algebra.ZeroTestable as ZeroTestable++import Control.DeepSeq+import Data.Data+import Data.Functor.Trans.Tagged+import Data.Vector               as V++-- | Indexed Zip Vector: a wrapper around a (boxed) 'Vector' that has+-- zip-py 'Applicative' behavior, analogous to+-- 'Control.Applicative.ZipList' for lists.  The index @m@ enforces+-- proper lengths (and is necessary to implement 'pure').++newtype IZipVector (m :: Factored) a =+  IZipVector { -- | Deconstructor+               unIZipVector :: Vector a}+  -- not deriving Read, Monoid, Alternative, Monad[Plus], IsList+  -- because of different semantics and/or length restriction+  deriving (Show, Eq, NFData, Functor,+            Foldable, Traversable, ZeroTestable.C)++-- the first argument, though phantom, affects representation+type role IZipVector representational representational++-- | Smart constructor that checks whether length of input is right+-- (should be totient of @m@).+iZipVector :: forall m a . (Fact m) => Vector a -> Maybe (IZipVector m a)+iZipVector = let n = proxy totientFact (Proxy::Proxy m)+            in \vec -> if n == V.length vec+                       then Just $ IZipVector vec+                       else Nothing++unzipIZV :: IZipVector m (a,b) -> (IZipVector m a, IZipVector m b)+unzipIZV (IZipVector v) = let (va,vb) = V.unzip v+                          in (IZipVector va, IZipVector vb)++-- don't export+repl :: forall m a . (Fact m) => a -> IZipVector m a+repl = let n = proxy totientFact (Proxy::Proxy m)+       in IZipVector . V.replicate n++-- Zip-py 'Applicative' instance.+instance (Fact m) => Applicative (IZipVector m) where+  pure = repl+  (IZipVector f) <*> (IZipVector a) = IZipVector $ V.zipWith ($) f a++-- no ZeroTestable instance for Vectors, so define here+instance (ZeroTestable.C a) => ZeroTestable.C (Vector a) where+  isZero = V.all isZero
+ Crypto/Lol/Types/IrreducibleChar2.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE FlexibleInstances, NoImplicitPrelude, PolyKinds,+             RebindableSyntax, ScopedTypeVariables, TypeFamilies,+             UndecidableInstances #-}++-- | Orphan instance of 'IrreduciblePoly' for characteristic-2 fields.++module Crypto.Lol.Types.IrreducibleChar2 () where++import Crypto.Lol.LatticePrelude+import Crypto.Lol.Reflects+import Crypto.Lol.Types.FiniteField++-- | Convenience function.+taggedProxy :: Tagged s (Proxy s)+taggedProxy = tag Proxy++-- CJP: we should perhaps prefer ternary (or 5-ary) polynomials over+-- Conway polynomials, because we don't use the special properties of+-- Conways, and reduction modulo sparse polynomials should be faster.++-- conway+--generate in Python (or choose any irreducible polynomial)+-- to generate with Sage, start sage and type:+--      conway_polynomial(p,e)+-- then copy and paste+instance (CharOf a ~ Prime2, Field a) => IrreduciblePoly a where+  irreduciblePoly = do+    pn <- taggedProxy+    let n = proxy value pn :: Int+    return $ case n of+      1 -> X^^1 + 1+      2 -> X^^2 + X^^1 + 1+      3 -> X^^3 + X^^1 + 1+      4 -> X^^4 + X^^1 + 1+      5 -> X^^5 + X^^2 + 1+      6 -> X^^6 + X^^4 + X^^3 + X^^1 + 1+      7 -> X^^7 + X^^1 + 1+      8 -> X^^8 + X^^4 + X^^3 + X^^2 + 1+      9 -> X^^9 + X^^4 + 1+      10 -> X^^10 + X^^6 + X^^5 + X^^3 + X^^2 + X^^1 + 1+      11 -> X^^11 + X^^2 + 1+      12 -> X^^12 + X^^7 + X^^6 + X^^5 + X^^3 + X^^1 + 1+      13 -> X^^13 + X^^4 + X^^3 + X^^1 + 1+      14 -> X^^14 + X^^7 + X^^5 + X^^3 + 1+      15 -> X^^15 + X^^5 + X^^4 + X^^2 + 1+      16 -> X^^16 + X^^5 + X^^3 + X^^2 + 1+      17 -> X^^17 + X^^3 + 1+      18 -> X^^18 + X^^12 + X^^10 + X^^1 + 1+      19 -> X^^19 + X^^5 + X^^2 + X^^1 + 1+      20 -> X^^20 + X^^10 + X^^9 + X^^7 + X^^6 + X^^5 + X^^4 + X^^1 + 1+      21 -> X^^21 + X^^6 + X^^5 + X^^2 + 1+      22 -> X^^22 + X^^12 + X^^11 + X^^10 + X^^9 + X^^8 + X^^6 + X^^5 + 1+      23 -> X^^23 + X^^5 + 1+      24 -> X^^24 + X^^16 + X^^15 + X^^14 + X^^13 + X^^10 + X^^9 + X^^7 + X^^5 + X^^3 + 1+      25 -> X^^25 + X^^8 + X^^6 + X^^2 + 1+      26 -> X^^26 + X^^14 + X^^10 + X^^8 + X^^7 + X^^6 + X^^4 + X^^1 + 1+      27 -> X^^27 + X^^12 + X^^10 + X^^9 + X^^7 + X^^5 + X^^3 + X^^2 + 1+      28 -> X^^28 + X^^13 + X^^7 + X^^6 + X^^5 + X^^2 + 1+      29 -> X^^29 + X^^2 + 1+      30 -> X^^30 + X^^17 + X^^16 + X^^13 + X^^11 + X^^7 + X^^5 + X^^3 + X^^2 + X^^1 + 1+      31 -> X^^31 + X^^3 + 1+      32 -> X^^32 + X^^15 + X^^9 + X^^7 + X^^4 + X^^3 + 1+      _ ->+        error $ "The IrreduciblePoly instance for N2 included with the library (and exported by Crypto.Lol) only contains " +++                "irreducible polynomials for characteristic-2 fields up to GF(2^^32). You need a polynomial " +++                "for GF(2^^" ++ (show n) ++ "). Define your own instance of IrreduciblePoly and do " +++                "not import Crypto.Lol."
+ Crypto/Lol/Types/Numeric.hs view
@@ -0,0 +1,210 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleInstances, GADTs,+             MultiParamTypeClasses, NoImplicitPrelude, RebindableSyntax,+             ScopedTypeVariables, TypeOperators #-}++-- we have some orphan instances here for instances of+-- package classes with Prelude data types+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- | This module imports NumericPrelude and defines constraint+-- synonyms for NumericPrelude classes to help with code readability,+-- and defines saner versions of some NumericPrelude functions++module Crypto.Lol.Types.Numeric+( module Crypto.Lol.Types.Numeric -- everything we define here+, module NumericPrelude         -- re-export+, Int64                         -- commonly used+) where++import Control.DeepSeq+import Control.Monad.Random++-- NumericPrelude has silly types for these functions+import           NumericPrelude         hiding (abs, max, min, (^))+import qualified NumericPrelude.Numeric (abs)+import qualified Prelude                (max, min)++import qualified Algebra.Absolute             (C)+import qualified Algebra.Additive             (C)+import qualified Algebra.Algebraic            (C)+import qualified Algebra.Field                (C)+import qualified Algebra.IntegralDomain       (C)+import qualified Algebra.Module               (C)+import qualified Algebra.PrincipalIdealDomain (C)+import qualified Algebra.RealField            (C)+import qualified Algebra.RealIntegral         (C)+import qualified Algebra.RealRing             (C)+import qualified Algebra.RealTranscendental   (C)+import qualified Algebra.Ring                 (C)+import qualified Algebra.ToInteger            (C)+import qualified Algebra.ToRational           (C, realToField)+import qualified Algebra.Transcendental       (C)+import qualified Algebra.ZeroTestable         (C)+import           MathObj.Polynomial++import Data.Int (Int64)++-- | The Prelude definition of 'max'.+max :: Ord a => a -> a -> a+max = Prelude.max++-- | The Prelude definition of 'min'.+min :: Ord a => a -> a -> a+min = Prelude.min++-- | The sane definition of 'abs' from+-- 'NumericPrelude.Numeric'+-- rather than the default from 'NumericPrelude'.+abs :: Absolute a => a -> a+abs = NumericPrelude.Numeric.abs++-- | The hidden NP function from 'Algebra.ToRational'.+realToField :: (Field b, ToRational a) => a -> b+realToField = Algebra.ToRational.realToField++-- use this if you need:+{- isZero -}+-- | Sane synonym for 'Algebra.ZeroTestable.C'.+type ZeroTestable a = (Algebra.ZeroTestable.C a)++{- - + negate -}+-- | Sane synonym for 'Algebra.Additive.C'.+type Additive a = (Algebra.Additive.C a)++{- Additive, plus: * fromIntegral -}+-- | Sane synonym for 'Algebra.Ring.C'.+type Ring a = (Algebra.Ring.C a)++{- Ring and Additive, plus: *> -}+-- | Sane synonym for 'Algebra.Module.C'.+type Module a v = (Algebra.Module.C a v)++{- Ring, plus: div, mod, divmod -}+-- | Sane synonym for 'Algebra.IntegralDomain.C'.+type IntegralDomain a = (Algebra.IntegralDomain.C a)++{- Ring, plus: abs signum toRational' -}+-- | Sane synonym for 'Algebra.ToRational.C'.+type ToRational a = (Algebra.ToRational.C a)++{- Ring, plus: / recip fromRational -}+-- | Sane synonym for 'Algebra.Field.C'.+type Field a = (Algebra.Field.C a)++{- Ring, plus: abs and rounding functions -}+-- | Sane synonym for 'Algebra.RealRing.C'.+type RealRing a = (Algebra.RealRing.C a)++{- Field, plus: abs signum round floor ceiling -}+-- | Sane synonym for 'Algebra.RealField.C'.+type RealField a = (Algebra.RealField.C a)++{- Field, plus: sqrt root ^/ -}+-- | Sane synonym for 'Algebra.Algebraic.C'.+type Algebraic a = (Algebra.Algebraic.C a)++{- Algebraic, plus: pi exp log sin atan -}+-- | Sane synonym for 'Algebra.Transcendental.C'.+type Transcendental a = (Algebra.Transcendental.C a)++{- Transcendental and RealField, plus atan2 -}+-- | Sane synonym for 'Algebra.RealTranscendental.C'.+type RealTranscendental a = (Algebra.RealTranscendental.C a)++{- Transcendental, plus: == <= >= < > -}+-- | Convenient synonym for @(Ord a, Transcendental a)@+type OrdFloat a = (Ord a, Transcendental a)++{- ToRational and Ring, plus: toInteger div mod divmod quot rem quotrem -}+-- | Sane synonym for 'Algebra.ToInteger.C'.+type ToInteger a = (Algebra.ToInteger.C a)++-- | Sane synonym for 'Algebra.Absolute.C'.+type Absolute a = (Algebra.Absolute.C a)++-- | Sane synonym for 'Algebra.RealIntegral.C'.+type RealIntegral a = (Algebra.RealIntegral.C a)++-- | Sane synonym for 'Algebra.PrincipalIdealDomain.C'.+type PID a = (Algebra.PrincipalIdealDomain.C a)++-- | Sane synonym for 'MathObj.Polynomial.T'.+type Polynomial a = MathObj.Polynomial.T a++-- | IntegralDomain instance for Double+instance Algebra.IntegralDomain.C Double where+    _ `div` 0 = error "cannot divide Double by 0\n"+    a `div` b = a / b+    _ `mod` _ = 0++-- NFData instance for Polynomial, missing from NP+instance (NFData r) => NFData (Polynomial r) where+  rnf = rnf . coeffs++-- | Our custom exponentiation, overriding NP's version that+-- requires 'Integer' exponent.+-- Copied from http://hackage.haskell.org/package/base-4.7.0.0/docs/src/GHC-Real.html#%5E+{-# SPECIALISE [1] (^) ::+        Integer -> Integer -> Integer,+        Integer -> Int -> Integer,+        Int -> Int -> Int,+        Int64 -> Int64 -> Int64+  #-}+(^) :: forall a i . (Ring a, ToInteger i) => a -> i -> a+x0 ^ y0 | y0 < 0    = error "Negative exponent"+        | y0 == 0   = 1+        | otherwise = f x0 y0+    where -- f : x0 ^ y0 = x ^ y+          f :: a -> i -> a -- a polymorphic local binding needs a sig+          f x y | even y    = f (x * x) (y `quot` 2)+                | y == 1    = x+                | otherwise = g (x * x) ((y - 1) `quot` 2) x+          -- g : x0 ^ y0 = (x ^ y) * z+          g :: a -> i -> a -> a+          g x y z | even y = g (x * x) (y `quot` 2) z+                  | y == 1 = x * z+                  | otherwise = g (x * x) ((y - 1) `quot` 2) (x * z)++-- | Inverse of @a@ modulo @q@, in range @0..q-1@.  (Argument order is+-- infix-friendly.)+modinv :: (PID i, Eq i) => i -> i -> Maybe i+modinv a q = let (d, (_, inv)) = extendedGCD q a+             in if d == one+                then Just $ inv `mod` q+                else Nothing++-- | Decompose an element into a list of "centered" digits with respect+-- to relative radices.+decomp :: (IntegralDomain z, Ord z) => [z] -> z -> [z]+decomp [] v = [v]+decomp (b:bs) v = let (q,r) = v `divModCent` b+                  in r : decomp bs q++-- | Deterministically round to the nearest multiple of @i@.+roundMult :: (RealField r, ToInteger i) => i -> r -> i+roundMult 1 r  = round r+roundMult i r = let r' = r / fromIntegral i in i * round r'++-- | Randomly round to the nearest larger or smaller multiple of @i@,+-- where the round-off term has expectation zero.+roundScalarCentered :: (RealField r, Random r, ToInteger i,+                        MonadRandom mon)+                      => i -> r -> mon i+roundScalarCentered p x =+  let x' = x / fromIntegral p+      mod1 = x' - floor x'+  in do prob <- getRandomR (zero, one)+        return $ p * if prob < mod1+                     then ceiling x'+                     else floor x'++-- | Variant of 'Algebra.IntegralDomain.divMod' in which the remainder+-- is in the range @[-b\/2,b\/2)@.+divModCent :: (IntegralDomain i, Ord i)+              => i              -- ^ dividend @a@+              -> i              -- ^ divisor @b@+              -> (i,i)          -- ^ (quotient, remainder)+divModCent = flip (\b -> +             let shift = b `div` 2+             in \a -> let (q,r) = (a+shift) `divMod` b+                      in (q,r-shift))
+ Crypto/Lol/Types/Random.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE GeneralizedNewtypeDeriving, PackageImports #-}++-- | Defines a newtype wrapper for crypto-api's 'CryptoRandomGen', and a corresponding 'RandomGen' instance.+--   'CryptoRandomGen' generators can only be used to get 'ByteString's; the 'RandomGen' instance allows them+--   to be used to generate any 'Random' type. Typical usage is with Control.Monad.Random's 'RandT' monad.++module Crypto.Lol.Types.Random (CryptoRand) where++import "crypto-api" Crypto.Random+import Data.Binary.Get+import Data.ByteString hiding (pack)+import Data.ByteString.Lazy (pack)+import System.Random++newtype CryptoRand g = CryptoRand g deriving (CryptoRandomGen)++intBytes = +  let bits = intLog 2 $ (1 + (fromIntegral (maxBound :: Int)) - (fromIntegral (minBound :: Int)) :: Integer)+  in if (bits `mod` 8) == 0 then bits `div` 8 else error "invalid Int bits in `intBytes`"++bytesToInt :: ByteString -> Int+bytesToInt bs = case intBytes of+  4 -> fromIntegral $ runGet getWord32host $ pack $ unpack bs+  8 -> fromIntegral $ runGet getWord64host $ pack $ unpack bs+  _ -> error "Unsupported Int size in `bytesToInt`"++-- | Yield @log_b(n)@ when it is a non-negative integer (otherwise+-- error).+intLog :: (Integral i) => i -> i -> Int+intLog _ 1 = 0+-- correct because ceil (lg (x)) == ceil (log (ceil (x)))+intLog b n | (n `mod` b) == 0 = 1 + intLog b (n `div` b)+           | otherwise = error "invalid arguments to intLog"++instance (CryptoRandomGen g) => RandomGen (CryptoRand g) where+  next (CryptoRand g) = case genBytes intBytes g of+    Right (bs, g') -> (bytesToInt bs, CryptoRand g')+    Left err -> error $ "Next error: " ++ show err++  genRange _ = (minBound, maxBound)++  split (CryptoRand g) = case splitGen g of+    Right (g1, g2) -> (CryptoRand g1, CryptoRand g2)+    Left err -> error $ "Split error: " ++ show err
+ Crypto/Lol/Types/ZPP.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE FlexibleContexts, TypeFamilies #-}++-- | A class for integers mod a prime power.++module Crypto.Lol.Types.ZPP+( ZPP(..)+) where++import Crypto.Lol.LatticePrelude+import Crypto.Lol.Types.FiniteField++-- | Represents integers modulo a prime power.+class (PrimeField (ZpOf zq), Ring zq) => ZPP zq where++  -- | An implementation of the integers modulo the prime base.+  type ZpOf zq++  -- | The prime and exponent of the modulus.+  modulusZPP :: Tagged zq PP++  -- | Lift from @Z_p@ to a representative.+  liftZp :: ZpOf zq -> zq+
+ Crypto/Lol/Types/ZmStar.hs view
@@ -0,0 +1,69 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             NoImplicitPrelude, PolyKinds, RebindableSyntax,+             ScopedTypeVariables, TypeFamilies, TypeOperators, +             UndecidableInstances #-}++-- | A collection of helper functions for working with @Z_m^*@++module Crypto.Lol.Types.ZmStar+( order, partitionCosets+) where++import Crypto.Lol.Factored+import Crypto.Lol.LatticePrelude as LP hiding (null)+import Crypto.Lol.Reflects+import Crypto.Lol.Types.ZqBasic++import Data.List as L (foldl', transpose)+import Data.Map  (Map, elems, empty, insertWith')+import Data.Set  as S (Set, difference, findMin, fromList, map, null)+++-- | The multiplicative order of @p@ (the argument) modulo @m@.+-- Requires @gcd(p,m)=1@.+order :: forall m . (Reflects m Int) => Int -> Tagged m Int+order p = tag $+  let mval = proxy value (Proxy::Proxy m)+  in if gcd p mval /= 1+     then error "p and m not coprime"+     else 1 + (length $ takeWhile (/= one) $+               tail $ iterate (* (fromIntegral p)) (one :: ZqBasic m Int))++-- given p, returns the cosets of Z_m^* / <p>+cosets :: forall zm . (Mod zm, ModRep zm ~ Int, Ord zm, Ring zm)+  => Int -> [Set zm]+cosets p =+  let mval = proxy modulus (Proxy::Proxy zm)+  in if gcd p mval /= 1+     then error "p and m not coprime"+     else let zmstar = fromList $ LP.map fromIntegral $ filter ((==) 1 . gcd mval) [1..mval]+              zp = fromIntegral p+              -- generates the coset containing x+              coset x = fromList $ x : takeWhile (/=x) (iterate (*zp) $ zp*x)+              -- repeatedly removes a (new) coset from the remaining elements+              genCosets s | null s = []+              genCosets s = let c = coset (findMin s)+                            in c : genCosets (difference s c)+          in genCosets zmstar++-- CJP: could tag this by '(p,m,m') for safety/memoization.++-- | Given @p@, returns a partition of the cosets of @Z_{m\'}^* \/ \<p>@+-- (specified by representatives), where the cosets in each component+-- are in bijective correspondence with the cosets of @Z_m^* \/ \<p>@ under+-- the natural (@mod m@) homomorphism.+partitionCosets :: forall m m' . (m `Divides` m')+  => Int -> Tagged '(m, m') [[Int]]+partitionCosets p =+  let m'cosets = cosets p+      -- a map from cosets of Z_m^* / <p> to their preimages under the+      -- natural homomorphism+      partition =+        L.foldl' (\cmap x -> insertWith' (++) (S.map (reduce . lift) x) [x] cmap)+          (empty :: Map (Set (ZqBasic m Int)) [Set (ZqBasic m' Int)])+          m'cosets+      -- transpose the map to get a list of list of sets, where for each+      -- inner list, there is exactly one m'-(co)set lying above each m-coset+      part' = transpose $ elems partition+     -- concat the inner sets to get a list of "CRT cosets" (indexed in Z_m'^*)+  in return $ LP.map (LP.map (lift . findMin)) part'
+ Crypto/Lol/Types/ZqBasic.hs view
@@ -0,0 +1,345 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,
+             FlexibleInstances, GeneralizedNewtypeDeriving,
+             MultiParamTypeClasses, NoImplicitPrelude, PolyKinds,
+             RebindableSyntax, RoleAnnotations, ScopedTypeVariables,
+             StandaloneDeriving, TypeFamilies, UndecidableInstances #-}
+
+-- | An implementation of modular arithmetic, i.e., the ring Zq.
+
+module Crypto.Lol.Types.ZqBasic
+( ZqBasic -- export the type, but not the constructor (for safety)
+) 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
+
+-- for the Unbox instances
+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
+
+-- for the Elt instance
+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)
+
+-- | The ring @Z_q@ of integers modulo 'q', using underlying integer
+-- type 'z'.
+newtype ZqBasic q z = ZqB z
+                    deriving (Eq, Ord, ZeroTestable.C, E.Elt, Show, NFData, Storable)
+
+-- the q argument, though phantom, matters for safety
+type role ZqBasic nominal representational
+
+--deriving instance (U.Unbox i) => G.Vector U.Vector (ZqBasic q i)
+--deriving instance (U.Unbox i) => M.MVector U.MVector (ZqBasic q i)
+--deriving instance (U.Unbox i) => U.Unbox (ZqBasic q i)
+
+-- convenience synonym for many instances
+type ReflectsTI q z = (Reflects q z, ToInteger z)
+
+{-# INLINABLE reduce' #-}
+reduce' :: forall q z . (ReflectsTI q z) => z -> ZqBasic q z
+reduce' = ZqB . (`mod` proxy value (Proxy::Proxy q))
+
+-- puts value in range [-q/2, q/2)
+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..(qval-1)]
+
+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)
+
+-- | Yield a /principal/ @m@th root of unity @omega_m \in @Z_q^*@.
+-- The implementation requires @q@ to be prime.  It works by finding a
+-- generator of @Z_q^*@ and raising it to the @(q-1)/m@ power.
+-- Therefore, outputs for different values of @m@ are consistent,
+-- i.e., @omega_{m'}^(m'/m) = omega_m@.
+
+principalRootUnity :: forall q z . (ReflectsTI q z, Enumerable (ZqBasic q z))
+                      => Int -> Maybe (Int -> ZqBasic q z)
+principalRootUnity =        -- use Integers for all intermediate calcs
+    let qval = fromIntegral $ (proxy value (Proxy::Proxy q) :: z)
+        -- order of Zq^* (assuming q prime)
+        order = qval-1
+        -- the primes dividing the order of Zq^*
+        pfactors = fst <$> factorise order
+        -- the powers we need to check
+        exps = div order <$> pfactors
+        -- whether an element is a generator of Zq^*
+        isGen x = (x^order == one) && all (\e -> x^e /= one) exps
+        -- for simplicity, require q to be prime
+    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       -- fail if q composite
+
+
+-- instance of CRTrans
+instance (ReflectsTI q z, PID z, Enumerable (ZqBasic q z))
+         => CRTrans (ZqBasic q z) where
+
+  crtInfo =
+    --DT.trace ("ZqBasic.crtInfo: q = " ++
+    --          show (proxy value (Proxy::Proxy q) :: z)) $
+    let qval :: z = proxy value (Proxy::Proxy q)
+    in \m -> (,) <$> principalRootUnity m <*>
+                     (reduce' <$> fromIntegral (valueHat m) `modinv` qval)
+
+-- instance of CRTEmbed
+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 of Additive
+instance (ReflectsTI q z, Additive z) => Additive.C (ZqBasic q z) where
+
+  {-# INLINABLE zero #-}
+  zero = ZqB zero
+
+  {-# INLINABLE (+) #-}
+  (+) = 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)
+
+  {-# INLINABLE negate #-}
+  negate (ZqB x) = reduce' $ negate x
+
+-- instance of Ring
+instance (ReflectsTI q z, Ring z) => Ring.C (ZqBasic q z) where
+  {-# INLINABLE (*) #-}
+  (ZqB x) * (ZqB y) = reduce' $ x * y
+    
+  {-# INLINABLE fromInteger #-}
+  fromInteger =
+    let qval = toInteger (proxy value (Proxy::Proxy q) :: z)
+    -- this is safe as long as type z can hold the value of q
+    in \x -> ZqB $ fromInteger $ x `mod` qval
+
+-- instance of Field
+instance (ReflectsTI q z, PID z, Show z) => Field.C (ZqBasic q z) where
+
+  {-# INLINABLE recip #-}
+  recip = let qval = proxy value (Proxy::Proxy q)
+              -- safe because modinv returns in range 0..qval-1
+          in \(ZqB x) -> ZqB $
+               fromMaybe (error $ "ZqB.recip fail: " ++
+                         show x ++ "\t" ++ show qval) $ modinv x qval
+
+-- (canonical) instance of IntegralDomain, needed for Cyclotomics
+instance (Field (ZqBasic q z)) => IntegralDomain.C (ZqBasic q z) where
+  divMod a b = (a/b, zero)
+
+-- Gadget-related instances
+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"
+
+-- BaseBGad instances
+
+gadlen :: (RealIntegral z) => z -> z -> Int
+gadlen _ q | isZero q = 0
+gadlen b q = 1 + (gadlen b $ q `div` b)
+
+-- | The base-@b@ gadget for modulus @q@, over integers (not mod
+-- anything).
+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 (k-1) bval
+              in tag . decomp radices . lift
+
+-- | Yield the error vector for a noisy multiple of the gadget (all
+-- over the integers). 
+correctZ :: forall z . (RealIntegral z)
+            => z                   -- ^ modulus @q@
+            -> z                   -- ^ base @b@
+            -> [z]                 -- ^ input vector @v = s \cdot g^t + e@
+            -> [z]                 -- ^ error @e@
+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
+      -- | Yield @w = round(\bar{B}^t \cdot v / q)@, along with the inner
+      -- product of @w@ with the top row of @q \bar{D}@.
+      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
+
+      -- | Yield @(q \bar{D}) \cdot w@, given precomputed first entry
+      qbarD :: [z] -> z -> [z]
+      qbarD [] x = [x]
+      qbarD (w0:ws) x = x : qbarD ws (b*x - q*w0)
+
+      -- | Yield the difference between the input vectors, along with
+      -- their final entry.
+      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 (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 of Random
+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 of Arbitrary
+instance (ReflectsTI q z, Random z) => Arbitrary (ZqBasic q z) where
+  arbitrary =
+    let qval :: z = proxy value (Proxy::Proxy q)
+    in fromIntegral <$> choose (0, qval-1)
+
+  shrink = shrinkNothing
+
+-- CJP: restored manual Unbox instances, until we have a better way
+-- (NewtypeDeriving or TH)
+
+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)
+
+-- Unbox, when underlying representation is
+instance U.Unbox z => U.Unbox (ZqBasic q z)
+
+{- purloined and tweaked from code in `vector` package that defines
+types as unboxed -}
+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
README view
@@ -1,9 +1,5 @@ Overview of key modules, roughly from highest- to lowest-level: -* SymmSHE.hs, an implementation of a symmetric-key,-  somewhat-homomorphic encryption scheme that is essentially-  equivalent to the one from the toolkit paper [LPR'13].- * Cyc.hs, which defines an interface for using cyclotomic fields,    rings R, and quotient rings Rq=R/qR; as well as many other   commonly used operations, e.g., converting
+ benchmarks/CycBenches.hs view
@@ -0,0 +1,115 @@+{-# LANGUAGE DataKinds, FlexibleContexts, +             NoImplicitPrelude, RebindableSyntax, +             ScopedTypeVariables, TypeFamilies, +             TypeOperators, UndecidableInstances #-}++module CycBenches (cycBenches) where++import Benchmarks+import Harness.Cyc+import Utils++import Control.Monad.Random++import Crypto.Lol+import Crypto.Lol.Types.Random+import Crypto.Random.DRBG++import Data.Singletons+import Data.Promotion.Prelude.List+import Data.Promotion.Prelude.Eq+import Data.Singletons.TypeRepStar++cycBenches :: (MonadRandom m) => m Benchmark+cycBenches = benchGroup "Cyc" [+  benchGroup "*"      $ applyBasic (Proxy::Proxy AllParams) $ hideArgs bench_mul,+  benchGroup "crt"    $ applyBasic (Proxy::Proxy AllParams) $ hideArgs bench_crt,+  benchGroup "crtInv" $ applyBasic (Proxy::Proxy AllParams) $ hideArgs bench_crtInv,+  benchGroup "l"      $ applyBasic (Proxy::Proxy AllParams) $ hideArgs bench_l,+  benchGroup "*g Pow" $ applyBasic (Proxy::Proxy AllParams) $ hideArgs bench_mulgPow,+  benchGroup "*g CRT" $ applyBasic (Proxy::Proxy AllParams) $ hideArgs bench_mulgCRT,+  benchGroup "lift"   $ applyLift  (Proxy::Proxy LiftParams) $ hideArgs bench_liftPow,+  benchGroup "error"  $ applyError (Proxy::Proxy ErrorParams) $ hideArgs $ bench_errRounded 0.1,+  benchGroup "twace"  $ applyTwoIdx (Proxy::Proxy TwoIdxParams) $ hideArgs bench_twacePow,+  benchGroup "embed"  $ applyTwoIdx (Proxy::Proxy TwoIdxParams) $ hideArgs bench_embedPow+  ]++-- no CRT conversion, just coefficient-wise multiplication+bench_mul :: (BasicCtx t m r) => Cyc t m r -> Cyc t m r -> Bench '(t,m,r)+bench_mul a b = +  let a' = adviseCRT a+      b' = adviseCRT b+  in bench (a' *) b'++-- convert input from Pow basis to CRT basis+bench_crt :: (BasicCtx t m r) => Cyc t m r -> Bench '(t,m,r)+bench_crt x = let y = advisePow x in bench adviseCRT y++-- convert input from CRT basis to Pow basis+bench_crtInv :: (BasicCtx t m r) => Cyc t m r -> Bench '(t,m,r)+bench_crtInv x = let y = adviseCRT x in bench advisePow y++-- convert input from Dec basis to Pow basis+bench_l :: (BasicCtx t m r) => Cyc t m r -> Bench '(t,m,r)+bench_l x = let y = adviseDec x in bench advisePow y++-- lift an element in the Pow basis+bench_liftPow :: forall t m r . (LiftCtx t m r) => Cyc t m r -> Bench '(t,m,r)+bench_liftPow x = let y = advisePow x in bench (liftCyc Pow :: Cyc t m r -> Cyc t m (LiftOf r)) y++-- multiply by g when input is in Pow basis+bench_mulgPow :: (BasicCtx t m r) => Cyc t m r -> Bench '(t,m,r)+bench_mulgPow x = let y = advisePow x in bench mulG y++-- multiply by g when input is in CRT basis+bench_mulgCRT :: (BasicCtx t m r) => Cyc t m r -> Bench '(t,m,r)+bench_mulgCRT x = let y = adviseCRT x in bench mulG y++-- generate a rounded error term+bench_errRounded :: forall t m r gen . (ErrorCtx t m r gen) +  => Double -> Bench '(t,m,r,gen)+bench_errRounded v = benchIO $ do+  gen <- newGenIO+  return $ evalRand (errorRounded v :: Rand (CryptoRand gen) (Cyc t m (LiftOf r))) gen++bench_twacePow :: forall t m m' r . (TwoIdxCtx t m m' r) +  => Cyc t m' r -> Bench '(t,m,m',r)+bench_twacePow x = +  let y = advisePow x +  in bench (twace :: Cyc t m' r -> Cyc t m r) y++bench_embedPow :: forall t m m' r . (TwoIdxCtx t m m' r) +  => Cyc t m r -> Bench '(t,m,m',r)+bench_embedPow x = +  let y = advisePow x +  in bench (embed :: Cyc t m r -> Cyc t m' r) y++type Tensors = '[CT,RT]+type MM'RCombos = +  '[ '(F4, F128, Zq 257),+     '(F1, PToF Prime281, Zq 563),+     '(F12, F32 * F9, Zq 512),+     '(F12, F32 * F9, Zq 577),+     '(F12, F32 * F9, Zq (577 ** 1153)),+     '(F12, F32 * F9, Zq (577 ** 1153 ** 2017)),+     '(F12, F32 * F9, Zq (577 ** 1153 ** 2017 ** 2593)),+     '(F12, F32 * F9, Zq (577 ** 1153 ** 2017 ** 2593 ** 3169)),+     '(F12, F32 * F9, Zq (577 ** 1153 ** 2017 ** 2593 ** 3169 ** 3457)),+     '(F12, F32 * F9, Zq (577 ** 1153 ** 2017 ** 2593 ** 3169 ** 3457 ** 6337)),+     '(F12, F32 * F9, Zq (577 ** 1153 ** 2017 ** 2593 ** 3169 ** 3457 ** 6337 ** 7489)),+     '(F12, F32 * F9 * F25, Zq 14401)+    ]+-- EAC: must be careful where we use Nub: apparently TypeRepStar doesn't work well with the Tensor constructors+type AllParams = ( '(,) <$> Tensors) <*> (Nub (Map RemoveM MM'RCombos))+type LiftParams = ( '(,) <$> Tensors) <*> (Nub (Filter Liftable (Map RemoveM MM'RCombos)))+type TwoIdxParams = ( '(,) <$> Tensors) <*> MM'RCombos++type ErrorParams = ( '(,) <$> '[HashDRBG]) <*> LiftParams++data Liftable :: TyFun (Factored, *) Bool -> *+type instance Apply Liftable '(m',r) = Int64 :== (LiftOf r)++data RemoveM :: TyFun (Factored, Factored, *) (Factored, *) -> *+type instance Apply RemoveM '(m,m',r) = '(m',r)++
+ benchmarks/Main.hs view
@@ -0,0 +1,12 @@++import CycBenches+import ZqBenches++import Criterion.Main+import Control.Monad++main :: IO ()+main = defaultMain =<< (sequence [+  zqBenches,+  cycBenches+  ])
+ benchmarks/ZqBenches.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,+             NoImplicitPrelude, RankNTypes, TypeFamilies #-}++module ZqBenches (zqBenches) where++import Crypto.Lol++import Control.Applicative+import Control.Monad+import Control.Monad.Random+import qualified Data.Vector.Unboxed as U+import qualified Data.Array.Repa as R+import GHC.TypeLits++import Utils+import Gen+import Benchmarks++type Arr = R.Array R.U R.DIM1++zqBenches :: MonadRandom rnd => rnd Benchmark+zqBenches = benchGroup "ZqBasic" [+  hideArgs bench_mul_unb (Proxy::Proxy (Zq 577)),+  hideArgs bench_mul_repa $ (Proxy::Proxy (Zq 577))+  ]++bench_mul_repa :: (Ring zq, U.Unbox zq) => Arr zq -> Arr zq -> Bench zq+bench_mul_repa a b = bench (R.computeUnboxedS . R.zipWith (*) a) b++bench_mul_unb :: (Ring zq, U.Unbox zq) => U.Vector zq -> U.Vector zq -> Bench zq+bench_mul_unb a b = bench (U.zipWith (*) a) b++vecLen = 100 :: Int++instance (U.Unbox zq, Random zq, MonadRandom rnd) => Generatable rnd (Arr zq) where+  genArg = R.fromListUnboxed (R.Z R.:. vecLen) <$> replicateM vecLen getRandom++instance (U.Unbox zq, Random zq, MonadRandom rnd) => Generatable rnd (U.Vector zq) where+  genArg = U.fromList <$> replicateM vecLen getRandom
lol.cabal view
@@ -5,7 +5,7 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             0.1.0.0+version:             0.2.0.0 synopsis:            A library for lattice cryptography. homepage:            https://github.com/cpeikert/Lol Bug-Reports:         https://github.com/cpeikert/Lol/issues@@ -18,14 +18,25 @@ stability:           experimental build-type:          Simple extra-source-files:  README, CHANGES.md,-                     src/Crypto/Lol/Cyclotomic/Tensor/CTensor/tensorTypes.h,-                     test-suite/CycTests.hs,-                     test-suite/SHETests.hs,-                     test-suite/TensorTests.hs,-                     test-suite/TestTypes.hs,-                     test-suite/ZqTests.hs-cabal-version:       >=1.10-description:         Λ ○ λ (Lol) is a general-purpose library for ring-based lattice cryptography.+                     benchmarks/CycBenches.hs,+                     benchmarks/ZqBenches.hs,+                     tests/CycTests.hs,+                     tests/ZqTests.hs,+                     tests/TensorTests.hs,+                     utils/Apply.hs,+                     utils/Benchmarks.hs,+                     utils/Gen.hs,+                     utils/Tests.hs,+                     utils/TestTypes.hs,+                     utils/Utils.hs,+                     utils/Harness/Cyc.hs,+                     Crypto/Lol/Cyclotomic/Tensor/CTensor/tensorTypes.h+cabal-version:       >= 1.10+description:         +    Λ ○ λ (Lol) is a general-purpose library for ring-based lattice cryptography.+    For a detailed description of interfaces and functionality, see +    <https://eprint.iacr.org/2015/1134 Λ ○ λ: A Functional Library for Lattice Cryptography>.+    For example cryptographic applications, see <https://hackage.haskell.org/package/lol-apps lol-apps>. source-repository head   type: git   location: https://github.com/cpeikert/Lol@@ -40,18 +51,23 @@   Description:  Compile via LLVM. This produces much better object code,                 but you need to have the LLVM compiler installed. -  Default:      False+  Default:      True +Flag opt+  Description: Turn on library optimizations+  Default:     True+  Manual:      False+ library-  hs-source-dirs:     src-  Include-dirs: src/Crypto/Lol/Cyclotomic/Tensor/CTensor-  C-sources: src/Crypto/Lol/Cyclotomic/Tensor/CTensor/basic.c, -             src/Crypto/Lol/Cyclotomic/Tensor/CTensor/crt.c, -             src/Crypto/Lol/Cyclotomic/Tensor/CTensor/g.c, -             src/Crypto/Lol/Cyclotomic/Tensor/CTensor/generalfuncs.c, -             src/Crypto/Lol/Cyclotomic/Tensor/CTensor/l.c, -             src/Crypto/Lol/Cyclotomic/Tensor/CTensor/random.c-  Includes: src/Crypto/Lol/Cyclotomic/Tensor/CTensor/tensorTypes.h+  Include-dirs: Crypto/Lol/Cyclotomic/Tensor/CTensor+  C-sources: Crypto/Lol/Cyclotomic/Tensor/CTensor/basic.c,+             Crypto/Lol/Cyclotomic/Tensor/CTensor/crt.c,+             Crypto/Lol/Cyclotomic/Tensor/CTensor/g.c,+             Crypto/Lol/Cyclotomic/Tensor/CTensor/generalfuncs.c,+             Crypto/Lol/Cyclotomic/Tensor/CTensor/l.c,+             Crypto/Lol/Cyclotomic/Tensor/CTensor/norm.c,+             Crypto/Lol/Cyclotomic/Tensor/CTensor/random.c+  Includes: Crypto/Lol/Cyclotomic/Tensor/CTensor/tensorTypes.h   default-language:   Haskell2010    if flag(useICC)@@ -65,96 +81,124 @@     ghc-options: -fllvm -optlo-O3    -- ghc optimizations-  ghc-options: -O3 -Odph -funbox-strict-fields -fwarn-dodgy-imports -rtsopts-  ghc-options: -fno-liberate-case -funfolding-use-threshold1000 -funfolding-keeness-factor1000+  if flag(opt)+    ghc-options: -O3 -Odph -funbox-strict-fields -fwarn-dodgy-imports -rtsopts+    ghc-options: -fno-liberate-case -funfolding-use-threshold1000 -funfolding-keeness-factor1000    exposed-modules:      Crypto.Lol+    Crypto.Lol.PosBin+    Crypto.Lol.Factored+    Crypto.Lol.Reflects     Crypto.Lol.CRTrans     Crypto.Lol.Gadget     Crypto.Lol.LatticePrelude-    -    Crypto.Lol.Applications.SymmSHE-    Crypto.Lol.Cyclotomic.Tensor-    Crypto.Lol.Factored      Crypto.Lol.Cyclotomic.Cyc     Crypto.Lol.Cyclotomic.UCyc-    Crypto.Lol.Cyclotomic.Utility-    +    Crypto.Lol.Cyclotomic.RescaleCyc     Crypto.Lol.Cyclotomic.Linear +    Crypto.Lol.Cyclotomic.Tensor     Crypto.Lol.Cyclotomic.Tensor.CTensor     Crypto.Lol.Cyclotomic.Tensor.RepaTensor     +    Crypto.Lol.Types.Random     Crypto.Lol.Types.FiniteField-    Crypto.Lol.Types.PrimeField     Crypto.Lol.Types.IrreducibleChar2-         Crypto.Lol.Types.ZPP     Crypto.Lol.Types.ZqBasic -    Crypto.Lol.Reflects-   other-modules:         -    Crypto.Lol.Types.ZmStar+    Crypto.Lol.FactoredDefs+    Crypto.Lol.PosBinDefs     Crypto.Lol.GaussRandom+    Crypto.Lol.Types.ZmStar     Crypto.Lol.Types.Complex+    Crypto.Lol.Types.Numeric     Crypto.Lol.Types.IZipVector     Crypto.Lol.Cyclotomic.Tensor.RepaTensor.CRT     Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Extension-    Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Gauss+    Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Dec     Crypto.Lol.Cyclotomic.Tensor.RepaTensor.GL     Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon-     Crypto.Lol.Cyclotomic.Tensor.CTensor.Extension-    Crypto.Lol.Types.Numeric+    Crypto.Lol.Cyclotomic.Tensor.CTensor.Backend    build-depends:-    arithmoi>=0.4.1.3 && <0.5,+    arithmoi >= 0.4.1.3 && <0.5,     base==4.8.*,-    constraints==0.4.*,-    containers>=0.5.6.2 && < 0.6,-    data-default>=0.3.0 && < 0.6,-    deepseq>=1.4.1.1 && <1.5,-    MonadRandom>=0.2 && < 0.5,-    mtl>=2.2.1 && < 2.3,-    numeric-prelude>=0.4.2 && < 0.5,-    QuickCheck>=2.8 && < 2.9,-    random>=1.1 && < 1.2,-    reflection>=1.5.1 && < 2.2,+    binary,+    bytestring,+    constraints,+    containers >= 0.5.6.2 && < 0.6,+    crypto-api,+    data-default >= 0.3.0 && < 0.6,+    deepseq >= 1.4.1.1 && <1.5,+    MonadRandom >= 0.2 && < 0.5,+    mtl >= 2.2.1 && < 2.3,+    numeric-prelude >= 0.4.2 && < 0.5,+    QuickCheck >= 2.8 && < 2.9,+    random >= 1.1 && < 1.2,+    reflection >= 1.5.1 && < 2.2,     repa==3.4.*,-    singletons>=1.1.2.1 && < 2.1,-    storable-record>=0.0.3 && < 0.1,-    storable-tuple>=0.0.1 && < 0.1,-    th-desugar>=1.5.4 && < 1.6,-    type-natural>=0.2.3.2 && < 0.4,-    tagged-transformer>=0.7 && < 0.9,-    transformers>=0.4.2.0 && < 0.5,+    singletons >= 1.1.2.1 && < 2.1,+    storable-record >= 0.0.3 && < 0.1,+    th-desugar >= 1.5.4 && < 1.6,+    tagged-transformer >= 0.7 && < 0.9,+    template-haskell  >=  2.2.0.0,+    transformers >= 0.4.2.0 && < 0.5,     vector==0.11.*,-    vector-th-unbox>=0.2.1.0 && < 0.3+    vector-th-unbox >= 0.2.1.0 && < 0.3    other-extensions: TemplateHaskell -test-suite lol-test-suite+test-suite test-lol   type:               exitcode-stdio-1.0-  hs-source-dirs:     test-suite+  hs-source-dirs:     tests,utils   default-language:   Haskell2010   main-is:            Main.hs -  -- ghc optimizations   ghc-options: -threaded -rtsopts    build-depends:     base,     constraints,+    deepseq,+    DRBG,     lol,     MonadRandom,-    QuickCheck>=2.8 && < 2.9,+    mtl,+    QuickCheck >= 2.8 && < 2.9,+    random,     repa,+    singletons,     test-framework >= 0.8 && < 0.9,     test-framework-quickcheck2 >= 0.3 && < 0.4,-    time>=1.2 && < 1.6,-    type-natural,     vector++Benchmark bench-lol+  type:               exitcode-stdio-1.0+  hs-source-dirs:     benchmarks,utils+  default-language:   Haskell2010+  main-is:            Main.hs++  -- if flag(llvm)+  --   ghc-options: -fllvm -optlo-O3+  ghc-options: -threaded -rtsopts+  -- ghc-options: -O2 -Odph -funbox-strict-fields -fwarn-dodgy-imports -rtsopts+  -- ghc-options: -fno-liberate-case -funfolding-use-threshold1000 -funfolding-keeness-factor1000++  build-depends:+    base,+    criterion,+    deepseq,+    DRBG,+    lol,+    MonadRandom,+    mtl,+    singletons,+    transformers,+    vector,+    repa                        
− src/Crypto/Lol.hs
@@ -1,21 +0,0 @@---- | Re-exports primary interfaces.--module Crypto.Lol -( module Crypto.Lol.Cyclotomic.Cyc-, module Crypto.Lol.Gadget-, module Crypto.Lol.LatticePrelude--, module Crypto.Lol.Types.ZqBasic-, module Crypto.Lol.Cyclotomic.Tensor.CTensor-, module Crypto.Lol.Cyclotomic.Tensor.RepaTensor-, module Crypto.Lol.Types.IrreducibleChar2) where--import Crypto.Lol.Cyclotomic.Cyc-import Crypto.Lol.Gadget-import Crypto.Lol.LatticePrelude--import Crypto.Lol.Types.ZqBasic-import Crypto.Lol.Cyclotomic.Tensor.CTensor-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor-import Crypto.Lol.Types.IrreducibleChar2
− src/Crypto/Lol/Applications/SymmSHE.hs
@@ -1,498 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, DeriveDataTypeable,-             FlexibleContexts, FlexibleInstances, GADTs,-             MultiParamTypeClasses, NoImplicitPrelude, ScopedTypeVariables,-             TypeFamilies, TypeOperators, UndecidableInstances #-}---- | Symmetric-key somewhat homomorphic encryption.--module Crypto.Lol.Applications.SymmSHE-(--- * Data types-SK, PT, CT                    -- don't export constructors!--- * Keygen, encryption, decryption-, genSK-, encrypt-, errorTerm, errorTermUnrestricted, decrypt, decryptUnrestricted--- * Encoding of plaintext-, toMSD, toLSD--- * Arithmetic with public values-, addScalar, addPublic, mulPublic--- * Modulus switching-, rescaleLinearCT, modSwitchPT--- * Key switching-, keySwitchLinear, keySwitchQuadCirc--- * Ring switching-, embedSK, embedCT, twaceCT-, tunnelCT--- * Constraint synonyms-, AddPublicCtx, MulPublicCtx, InnerKeySwitchCtx, KeySwitchCtx, KSHintCtx, ModSwitchPTCtx-, ToSDCtx, EncryptCtx, TunnelCtx, GenSKCtx, DecryptCtx-, ErrorTermCtx-) where--import qualified Algebra.Additive as Additive (C)-import qualified Algebra.Ring     as Ring (C)--import Crypto.Lol.Cyclotomic.Cyc-import Crypto.Lol.Cyclotomic.UCyc (forceDec)-import Crypto.Lol.Cyclotomic.Linear-import Crypto.Lol.Gadget-import Crypto.Lol.LatticePrelude    as LP hiding (sin)--import Control.Applicative  hiding ((*>))-import Control.DeepSeq-import Control.Monad        as CM-import Control.Monad.Random-import Data.Maybe-import Data.Traversable     as DT-import Data.Typeable--import MathObj.Polynomial as P---- | secret key-data SK r where-  SK  :: (ToRational v, NFData v) => v -> r -> SK r---- | plaintext-type PT rp = rp---- | Ciphertext encoding type-data Encoding = MSD | LSD deriving (Show, Eq)---- | Ciphertext over @R'_q@, encrypting a plaintext in @R_p (R=O_m)@.-data CT (m :: Factored) zp r'q =-  CT-  !Encoding                     -- MSD/LSD encoding-  !Int                          -- accumulated power of g_m' in c(s)-  !zp                           -- factor to mul by upon decryption-  !(Polynomial r'q)             -- the polynomial c(s)-  deriving (Typeable, Show)---- Note: do *not* give an Eq instance for CT, because it's not--- meaningful to compare ciphertexts for equality--instance (NFData zp, NFData r'q) => NFData (CT m zp r'q) where-  rnf (CT _ k sc cs) = rnf k `seq` rnf sc `seq` rnf cs--instance (NFData r) => NFData (SK r) where-  rnf (SK v s) = rnf v `seq` rnf s------------ Basic functions: Gen, Enc, Dec -------------- | Constraint synonym for generating a secret key.-type GenSKCtx t m z v =-  (ToInteger z, Fact m, CElt t z, ToRational v, NFData v)---- | Generates a secret key with (index-independent) scaled variance--- parameter @v@; see 'errorRounded'.-genSK :: (GenSKCtx t m z v, MonadRandom rnd)-         => v -> rnd (SK (Cyc t m z))-genSK v = liftM (SK v) $ errorRounded v---- | Constraint synonym for encryption.-type EncryptCtx t m m' z zp zq =-  (Mod zp, Ring zp, Ring zq, Lift zp (ModRep zp),-   Reduce z zq, Reduce (LiftOf zp) zq,-   CElt t zq, CElt t zp, CElt t z, CElt t (LiftOf zp),-   m `Divides` m')---- | Encrypt a plaintext under a secret key.-encrypt :: forall t m m' z zp zq rnd . (EncryptCtx t m m' z zp zq, MonadRandom rnd)-           => SK (Cyc t m' z) -> PT (Cyc t m zp) -> rnd (CT m zp (Cyc t m' zq))-encrypt (SK svar s) =-  let sq = adviseCRT $ reduce s-  in \pt -> do-    e <- errorCoset svar (embed pt :: PT (Cyc t m' zp))-    c1 <- getRandom-    return $! CT LSD zero one $ fromCoeffs [reduce e - c1 * sq, c1]---- | Constraint synonym for extracting the error term of a ciphertext.-type ErrorTermCtx t m' z zp zq =-  (Reduce z zq, Lift' zq, CElt t z, CElt t (LiftOf zq),-   ToSDCtx t m' zp zq)---- | Extract the error term of a ciphertext.-errorTerm :: (ErrorTermCtx t m' z zp zq)-             => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> Cyc t m' (LiftOf zq)-errorTerm (SK _ s) = let sq = reduce s in-  \ct -> let (CT LSD _ _ c) = toLSD ct-         in liftCyc Dec $ evaluate c sq---- for when we know the division must succeed-divG' :: (Fact m, CElt t r) => Cyc t m r -> Cyc t m r-divG' = fromJust . divG---- | Constraint synonym for decryption.-type DecryptCtx t m m' z zp zq =-  (ErrorTermCtx t m' z zp zq, Reduce (LiftOf zq) zp,-   m `Divides` m', CElt t zp)---- | Decrypt a ciphertext.-decrypt :: forall t m m' z zp zq . (DecryptCtx t m m' z zp zq)-           => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> PT (Cyc t m zp)-decrypt sk ct =-  let ct'@(CT LSD k l _) = toLSD ct-  in let e :: Cyc t m' zp = reduce $ errorTerm sk ct'-     in (scalarCyc l) * twace (iterate divG' e !! k)----- unrestricted versions ------- | More general form of 'errorTerm' that works for unrestricted--- output coefficient types.-errorTermUnrestricted :: -  (Reduce z zq, Lift' zq, CElt t z, ToSDCtx t m' zp zq)-  => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> Cyc t m' (LiftOf zq)-errorTermUnrestricted (SK _ s) = let sq = reduce s in-  \ct -> let (CT LSD _ _ c) = toLSD ct-             eval = evaluate c sq-         in cyc $ fmap lift $ forceDec $ unsafeUnCyc eval---- | More general form of 'decrypt' that works for unrestricted output--- coefficient types.-decryptUnrestricted :: - (Fact m, Fact m', CElt t zp, m `Divides` m',-  Reduce z zq, Lift' zq, CElt t z, ToSDCtx t m' zp zq, Reduce (LiftOf zq) zp)-  => SK (Cyc t m' z) -> CT m zp (Cyc t m' zq) -> PT (Cyc t m zp)--decryptUnrestricted (SK _ s) = let sq = reduce s in-  \ct -> let (CT LSD k l c) = toLSD ct-         in let eval = evaluate c sq-                e = cyc $ fmap (reduce . lift) $ forceDec $ unsafeUnCyc eval-                l' = scalarCyc l-            in l' * twace (iterate divG' e !! k)------------ LSD/MSD switching -------------- | Constraint synonym for converting between ciphertext encodings.-type ToSDCtx t m' zp zq = (Encode zp zq, Fact m', CElt t zq)--toLSD, toMSD :: ToSDCtx t m' zp zq- => CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)---- CJP: reduce duplication in these functions?  They differ in only two places---- | Convert a ciphertext to MSD encoding.-toMSD = let (zpScale, zqScale) = lsdToMSD-            rqScale = scalarCyc zqScale-        in \ct@(CT enc k l c) -> case enc of-          MSD -> ct-          LSD -> CT MSD k (zpScale * l) ((rqScale *) <$> c)---- | Convert a ciphertext to LSD encoding.-toLSD = let (zpScale, zqScale) = msdToLSD-            rqScale = scalarCyc zqScale-        in \ct@(CT enc k l c) -> case enc of-          LSD -> ct-          MSD -> CT LSD k (zpScale * l) ((rqScale *) <$> c)------------ Modulus switching -------------- | Rescale a linear polynomial in MSD encoding, for best noise--- behavior.-rescaleLinearMSD :: (RescaleCyc (Cyc t) zq zq', Fact m')-                    => Polynomial (Cyc t m' zq) -> Polynomial (Cyc t m' zq')-rescaleLinearMSD c = case coeffs c of-  [] -> fromCoeffs []-  [c0] -> fromCoeffs [rescaleCyc Dec c0]-  [c0,c1] -> let c0' = rescaleCyc Dec c0-                 c1' = rescaleCyc Pow c1-             in fromCoeffs [c0', c1']-  _ -> error $ "rescaleLinearMSD: list too long (not linear): " ++-       show (length $ coeffs c)---- | Rescale a linear ciphertext to a new modulus.-rescaleLinearCT :: (RescaleCyc (Cyc t) zq zq', ToSDCtx t m' zp zq)-           => CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq')-rescaleLinearCT ct = let CT MSD k l c = toMSD ct-                     in CT MSD k l $ rescaleLinearMSD c---- | Constraint synonym for modulus switching.-type ModSwitchPTCtx t m' zp zp' zq =-  (Lift' zp, Reduce (LiftOf zp) zp', ToSDCtx t m' zp zq)---- | Homomorphically divide a plaintext that is known to be a multiple--- of @(p\/p\')@ by that factor, thereby scaling the plaintext modulus--- from @p@ to @p\'@.-modSwitchPT :: (ModSwitchPTCtx t m' zp zp' zq)-            => CT m zp (Cyc t m' zq) -> CT m zp' (Cyc t m' zq)-modSwitchPT ct = let CT MSD k l c = toMSD ct in-    CT MSD k (reduce (lift l)) c------------ Key switching ------------type LWECtx t m' z zq =-  (ToInteger z, Reduce z zq, Ring zq, Fact m', CElt t z, CElt t zq)---- | An LWE sample for a given secret (corresponding to a linear--- ciphertext encrypting 0 in MSD form)-lweSample :: (LWECtx t m' z zq, MonadRandom rnd)-             => SK (Cyc t m' z) -> rnd (Polynomial (Cyc t m' zq))-lweSample (SK svar s) =-  -- adviseCRT because we call `replicateM (lweSample s)` below, but only want to do CRT once. -  let sq = adviseCRT $ negate $ reduce s -  in do-    e <- errorRounded svar-    c1 <- adviseCRT <$> getRandom -- we would like hints to be in CRT form-    return $ fromCoeffs [c1 * sq + reduce (e `asTypeOf` s), c1]---- | Constraint synonym for generating key-switch hints.-type KSHintCtx gad t m' z zq = -  (LWECtx t m' z zq, Reduce (DecompOf zq) zq, Gadget gad zq,-   CElt t (DecompOf zq))---- | Generate a hint that "encrypts" a value under a secret key, in--- the sense required for key-switching.  The hint works for any--- plaintext modulus, but must be applied on a ciphertext in MSD form.-ksHint :: (KSHintCtx gad t m' z zq, MonadRandom rnd)-          => SK (Cyc t m' z) -> Cyc t m' z-          -> rnd (Tagged gad [Polynomial (Cyc t m' zq)])-ksHint skout val = do -- rnd monad-  let valq = reduce val-      valgad = encode valq-  -- CJP: clunky, but that's what we get without a MonadTagged-  samples <- DT.mapM (\as -> replicateM (length as) (lweSample skout)) valgad-  return $ zipWith (+) <$> (map P.const <$> valgad) <*> samples--type KnapsackCtx t (m' :: Factored) z zq' =-  (Reduce z zq', Fact m', CElt t z, CElt t zq')---- poor man's module multiplication for knapsack-(*>>) :: Ring r => r -> Polynomial r -> Polynomial r-(*>>) r = fmap (r *)--knapsack :: forall t m' z zq' . (KnapsackCtx t m' z zq')-            => [Polynomial (Cyc t m' zq')] -> [Cyc t m' z] -> Polynomial (Cyc t m' zq')--- adviseCRT here because we are about to map (*) onto each polynomial coeff-knapsack hint xs = sum (zipWith (*>>) (adviseCRT <$> reduce <$> xs) hint)--type InnerKeySwitchCtx gad t m' zq zq' =-  (RescaleCyc (Cyc t) zq' zq, RescaleCyc (Cyc t) zq zq',-   Decompose gad zq', KnapsackCtx t m' (DecompOf zq') zq')---- Helper function: applies key-switch hint to a ring element.--- Signature is such that we should rescale input and output.-switch :: forall gad t m' zq' zq . (InnerKeySwitchCtx gad t m' zq zq')-  => Tagged gad [Polynomial (Cyc t m' zq')] -> Cyc t m' zq -> Polynomial (Cyc t m' zq)-switch hint c = rescaleLinearMSD $ untag $ knapsack <$>-                hint <*> decompose (rescaleCyc Pow c :: Cyc t m' zq')---- | Constraint synonym for key switching.-type KeySwitchCtx gad t m' zp zq zq' =-  (ToSDCtx t m' zp zq, InnerKeySwitchCtx gad t m' zq zq')---- | Switch a linear ciphertext under @s_in@ to a linear one under @s_out@-keySwitchLinear :: forall gad t m' zp zq zq' z rnd m .-  (KeySwitchCtx gad t m' zp zq zq', KSHintCtx gad t m' z zq', MonadRandom rnd)-  => SK (Cyc t m' z)                -- sout-  -> SK (Cyc t m' z)                -- sin-  -> TaggedT (gad, zq') rnd (CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq))-keySwitchLinear skout (SK _ sin) = tagT $ do-  hint :: Tagged gad [Polynomial (Cyc t m' zq')] <- ksHint skout sin-  return $ hint `deepseq`-    (\ct -> let CT MSD k l c = toMSD ct-                [c0,c1] = coeffs c-            in CT MSD k l $ P.const c0 + switch hint c1)---- | Switch a quadratic ciphertext (i.e., one with three components)--- to a linear one under the /same/ key.-keySwitchQuadCirc :: forall gad t m' zp zq zq' z m rnd .-  (KeySwitchCtx gad t m' zp zq zq', KSHintCtx gad t m' z zq', MonadRandom rnd)-  => SK (Cyc t m' z)-  -> TaggedT (gad, zq') rnd (CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq))-keySwitchQuadCirc sk@(SK _ s) = tagT $ do-  hint :: Tagged gad [Polynomial (Cyc t m' zq')] <- ksHint sk (s*s)-  return $ hint `deepseq` (\ct ->-    let CT MSD k l c = toMSD ct-        [c0,c1,c2] = coeffs c-    in CT MSD k l $ P.fromCoeffs [c0,c1] + switch hint c2)------------ Misc homomorphic operations ------------type AddScalarCtx t m' zp zq =-  (Lift' zp, Reduce (LiftOf zp) zq, ToSDCtx t m' zp zq)---- | Homomorphically add a public @Z_p@ value to an encrypted value.  The--- ciphertext must not carry any @g@ factors.-addScalar :: (AddScalarCtx t m' zp zq)-             => zp -> CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)-addScalar b ct =-  let (l,c) = case toLSD ct of-        CT LSD 0 l c -> (l,c)-        CT LSD _ _ _ -> error "cannot add public scalar to ciphertext with 'g' factors"-        _ -> error "internal error: addScalar"-      b' = scalarCyc (reduce $ lift $ b * recip l)-  in CT LSD 0 l $ c + P.const b'---- | Constraint synonym for adding a public value to an encrypted value-type AddPublicCtx t m m' zp zq =-  (Lift' zp, Reduce (LiftOf zp) zq, m `Divides` m',-   CElt t zp, CElt t (LiftOf zp), ToSDCtx t m' zp zq)---- | Homomorphically add a public @R_p@ value to an encrypted value.-addPublic :: forall t m m' zp zq . (AddPublicCtx t m m' zp zq)-          => Cyc t m zp -> CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)-addPublic b ct = let CT LSD k l c = toLSD ct in-  let linv = scalarCyc $ recip l-      -- multiply public value by appropriate power of g and divide by the-      -- scale, to match the form of the ciphertext-      b' :: Cyc t m zq = reduce $ liftCyc Pow $ linv * (iterate mulG b !! k)-  in CT LSD k l $ c + P.const (embed b')---- | Constraint synonym for multiplying a public value with an encrypted value-type MulPublicCtx t m m' zp zq =-  (Lift' zp, Reduce (LiftOf zp) zq, Ring zq, m `Divides` m',-   CElt t zp, CElt t (LiftOf zp), CElt t zq)---- | Homomorphically multiply an encrypted value by a public @R_p@ value.-mulPublic :: forall t m m' zp zq . (MulPublicCtx t m m' zp zq)-             => Cyc t m zp -> CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)-mulPublic a (CT enc k l c) =-  let a' = embed (reduce $ liftCyc Pow a :: Cyc t m zq)-  in CT enc k l $ (a' *) <$> c---- | Increment the internal g exponent without changing the encrypted--- message.-mulGCT :: (Fact m', CElt t zq)-          => CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)-mulGCT (CT enc k l c) = CT enc (k+1) l $ mulG <$> c------------ NumericPrelude instances ------------instance (Eq zp, m `Divides` m', ToSDCtx t m' zp zq)-         => Additive.C (CT m zp (Cyc t m' zq)) where--  zero = CT LSD 0 one zero--  -- the scales, g-exponents of ciphertexts, and MSD/LSD types must match.-  ct1@(CT enc1 k1 l1 c1) + ct2@(CT enc2 k2 l2 c2)-      -- for simplicity, we don't currently support this. Shouldn't be-      -- too complicated though.-      | l1 /= l2 = error "Cannot add ciphertexts with different scale values"-      | k1 < k2 = iterate mulGCT ct1 !! (k2-k1) + ct2-      | k1 > k2 = ct1 + iterate mulGCT ct2 !! (k1-k2)-      | enc1 == LSD && enc2 == MSD = toMSD ct1 + ct2-      | enc1 == MSD && enc2 == LSD = ct1 + toMSD ct2-      | otherwise = CT enc1 k1 l1 $ c1 + c2--  negate (CT enc k l c) = CT enc k l $ negate <$> c--instance (ToSDCtx t m' zp zq, Additive (CT m zp (Cyc t m' zq)))-  => Ring.C (CT m zp (Cyc t m' zq)) where--  one = CT LSD 0 one one--  -- need at least one ct to be in LSD form-  ct1@(CT MSD _ _ _) * ct2@(CT MSD _ _ _) = toLSD ct1 * ct2--  -- first is in LSD-  (CT LSD k1 l1 c1) * (CT d2 k2 l2 c2) =-    -- mul by g so error maintains invariant: error*g is "round"-    CT d2 (k1+k2+1) (l1*l2) (mulG <$> c1 * c2)--  -- else, second must be in LSD-  ct1 * ct2 = ct2 * ct1--{- CJP: do we want/need this?  We have mulPublic...--instance (MulPublicCtx t m m' zp zq, Reduce z' zp, CElt t z',-          l `Divides` m, Additive (CT m zp (c m' zq)), Ring (c l z'))-  => Module.C (c l z') (CT m zp (c m' zq)) where--  (*>) a = mulPublic (embed $ reduce a)--}------------ Ring switching ------------type AbsorbGCtx t m' zp zq =-  (Lift' zp, Reduce (LiftOf zp) zq, Ring zp, Ring zq, Fact m',-   CElt t (LiftOf zp), CElt t zp, CElt t zq)---- | "Absorb" the powers of g associated with the ciphertext, at the--- cost of some increase in noise. This is usually needed before--- changing the index of the ciphertext ring.-absorbGFactors :: forall t zp zq m m' . (AbsorbGCtx t m' zp zq)-                  => CT m zp (Cyc t m' zq) -> CT m zp (Cyc t m' zq)-absorbGFactors ct@(CT enc k l c)-  | k == 0 = ct-  | k > 0 = let d :: Cyc t m' zp = iterate divG' one !! k-                rep = adviseCRT $ reduce $ liftCyc Pow d-            in CT enc 0 l $ (rep *) <$> c-  | otherwise = error "k < 0 in absorbGFactors"---- | Embed a ciphertext in R' encrypting a plaintext in R to a--- ciphertext in T' encrypting a plaintext in T. The target ciphertext--- ring T' must contain both the the source ciphertext ring R' and the--- target plaintext ring T.-embedCT :: (CElt t zq,-            r `Divides` r', s `Divides` s', r `Divides` s, r' `Divides` s')-           => CT r zp (Cyc t r' zq) -> CT s zp (Cyc t s' zq)--- We could call absorbGFactors first, insead of error.  Embedding--- *essentially* maintains the invariant that noise*g is "round."--- While g'/g can be non-spherical, it only stretches by at most a--- factor of 2 per new odd prime.  We *cannot* multiply by g, then--- embed, then divide by g' because the result would not remain in R'.--- So this is the best we can do.-embedCT (CT d 0 l c) = CT d 0 l (embed <$> c)-embedCT _ = error "embedCT requires 0 factors of g; call aborbGFactors first"---- | Embed a secret key from a subring into a superring.-embedSK :: (CElt t z, m `Divides` m') => SK (Cyc t m z) -> SK (Cyc t m' z)-embedSK (SK v s) = SK v $ embed s---- | "Tweaked trace" function for ciphertexts.  Mathematically, the--- target plaintext ring @S@ must contain the intersection of the--- source plaintext ring @T@ and the target ciphertext ring @S\'@.--- Here we make the stricter requirement that @s = gcd(s\', t)@.-twaceCT :: (CElt t zq, r `Divides` r', s' `Divides` r',-            s ~ (FGCD s' r))-           => CT r zp (Cyc t r' zq) -> CT s zp (Cyc t s' zq)--- we could call absorbGFactors first, insead of error-twaceCT (CT d 0 l c) = CT d 0 l (twace <$> c)-twaceCT _ = error "twaceCT requires 0 factors of g; call absorbGFactors first"----- | Constraint synonym for ring tunneling.-type TunnelCtx t e r s e' r' s' z zp zq zq' gad =-  (ExtendLinIdx e r s e' r' s',     -- liftLin-   e' ~ (e * (r' / r)),             -- convenience; implied by prev constraint-   KSHintCtx gad t r' z zq',        -- ksHint-   Reduce z zq,                     -- Reduce on Linear-   Lift zp z,                       -- liftLin-   CElt t zp,                       -- liftLin-   KeySwitchCtx gad t s' zp zq zq') -- keySwitch---- | Homomorphically apply the @E@-linear function that maps the--- elements of the decoding basis of @R\/E@ to the corresponding--- @S@-elements in the input array.-tunnelCT :: forall gad t e r s e' r' s' z zp zq zq' rnd .-  (TunnelCtx t e r s e' r' s' z zp zq zq' gad,-   MonadRandom rnd)-  => Linear t zp e r s-  -> SK (Cyc t s' z)-  -> SK (Cyc t r' z)-  -> TaggedT (gad,zq') rnd (CT r zp (Cyc t r' zq) -> CT s zp (Cyc t s' zq))-tunnelCT f skout (SK _ sin) = tagT $ (do -- in rnd-  -- generate hints-  let f' = extendLin $ lift f :: Linear t z e' r' s'-      f'q = reduce f' :: Linear t zq e' r' s'-      -- choice of basis here must match coeffsCyc basis below-      ps = proxy powBasis (Proxy::Proxy e')-      comps = (evalLin f' . (adviseCRT sin *)) <$> ps-  hints :: [Tagged gad [Polynomial (Cyc t s' zq')]] <- CM.mapM (ksHint skout) comps-  return $ hints `deepseq` \ct' ->-    let CT MSD 0 s c = toMSD $ absorbGFactors ct'-        [c0,c1] = coeffs c-        -- apply E-linear function to constant term c0-        c0' = evalLin f'q c0-        -- apply E-linear function to c1 via key-switching-        -- this basis must match the basis used above to generate the hints-        c1s = coeffsCyc Pow c1 :: [Cyc t e' zq]-        -- CJP: don't embed the c1s before decomposing them (inside-        -- switch); instead decompose in smaller ring before-        -- embedding (it matters).-        -- We may need to generalize switch or define an-        -- alternative.-        c1s' = zipWith switch hints (embed <$> c1s)-        c1' = sum c1s'-    in CT MSD 0 s $ P.const c0' + c1')-      \\ lcmDivides (Proxy::Proxy r) (Proxy::Proxy e')
− src/Crypto/Lol/CRTrans.hs
@@ -1,181 +0,0 @@-{-# LANGUAGE FlexibleContexts, FlexibleInstances, RebindableSyntax,
-             ScopedTypeVariables, TypeFamilies #-}
-
--- | Classes and helper methods for the Chinese remainder transform
--- and ring extensions.
-
-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
-
--- | Information that characterizes the (invertible) Chinese remainder
--- transformation over a ring @r@, namely:
---
---     (1) a function that returns the @i@th power of some @m@th root
---     of unity (for any integer @i@)
---
---     (2) the multiplicative inverse of @\\hat{m}@ in @r@.
-
-type CRTInfo r = (Int -> r, r)
-
--- | A ring that (possibly) supports invertible Chinese remainder
--- transformations of various indices.
-
--- | The values of 'crtInfo' for different indices @m@ should be
--- consistent, in the sense that if @omega@, @omega'@ are respectively
--- the values returned for @m@, @m'@ where @m'@ divides @m@, then it
--- should be the case that @omega^(m/m')=omega'@.
-
-class Ring r => CRTrans r where
-
-  -- | 'CRTInfo' for a given index @m@. The method itself may be
-  -- slow, but the function it returns should be fast, e.g., via
-  -- internal memoization.  The default implementation returns
-  -- 'Nothing'.
-  crtInfo :: Int -> Maybe (CRTInfo r)
-  crtInfo = const Nothing
-
--- | A ring with a ring embedding into some ring @CRTExt r@ that has
--- an invertible CRT transformation for /every/ positive index @m@.
-class (Ring r, Ring (CRTExt r)) => CRTEmbed r where
-  type CRTExt r
-
-  -- | Embeds from @r@ to @CRTExt r@
-  toExt :: r -> CRTExt r
-  -- | Projects from @CRTExt r@ to @r@
-  fromExt :: CRTExt r -> r
-
--- CRTrans instance for product rings
-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))
-
--- CRTEmbed instance for product rings
-instance (CRTEmbed a, CRTEmbed b) => CRTEmbed (a,b) where
-  type CRTExt (a,b) = (CRTExt a, CRTExt b)
-  toExt = toExt *** toExt
-  fromExt = fromExt *** fromExt
-
--- | Default implementation of 'omegaPow' for 'Mod' types.  The
--- implementation finds an integer element of maximal multiplicative
--- order, and raises it to the appropriate power. Therefore, the
--- functions returned for different values of the first argument are
--- consistent, i.e., @omega_{m'}^(m'/m) = omega_m@.
-omegaPowMod :: forall r . (Mod r, Enumerable r, Ring r, Eq r)
-               => Int -> Maybe (Int -> r)
-omegaPowMod =                -- use Integers for all intermediate calcs
-
-  -- CJP: there's a mismatch here between the semantics of Mod and the
-  -- use of 'values'.  If r really represents *integers* modulo
-  -- something then we're fine, otherwise we might get weird behavior.
-
-    let -- the exponent of Z_q^*
-        exponent = carmichael $ fromIntegral (proxy modulus (Proxy::Proxy r))
-        -- all prime divisors of exponent
-        primes = map fst $ factorise exponent
-        -- the powers we need to check
-        exps = map (exponent `div`) primes
-        -- whether an element is a unit with maximal order
-        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)
-
--- | 'crtInfo' wrapper for 'Fact' types.
-crtInfoFact :: (Fact m, CRTrans r) => TaggedT m Maybe (CRTInfo r)
-crtInfoFact = (tagT . crtInfo) =<< pureT valueFact
-
--- | 'crtInfo' wrapper for 'PPow' types.
-crtInfoPPow :: (PPow pp, CRTrans r) => TaggedT pp Maybe (CRTInfo r)
-crtInfoPPow = (tagT . crtInfo) =<< pureT valuePPow
-
--- | 'crtInfo' wrapper for 'NatC' types.
-crtInfoNatC :: (NatC p, CRTrans r) => TaggedT p Maybe (CRTInfo r)
-crtInfoNatC = (tagT . crtInfo) =<< pureT valueNatC
-
--- | A function that returns the 'i'th embedding of @g_{p^e} = g_p@ for
--- @i@ in @Z*_{p^e}@.
-gEmbPPow :: forall pp r . (PPow pp, CRTrans r) => TaggedT pp Maybe (Int -> r)
-gEmbPPow = tagT $ case (sing :: SPrimePower pp) of
-  -- intentionally no match for zero exponents
-  (SPP (STuple2 sp (SS _))) -> withWitnessT gEmbNatC sp
-
--- | A function that returns the @i@th embedding of @g_p@ for @i@ in @Z*_p@,
--- i.e., @1-omega_p^i@.
-gEmbNatC :: (NatC p, CRTrans r) => TaggedT p Maybe (Int -> r)
-gEmbNatC = do
-  (f, _) <- crtInfoNatC
-  return $ \i -> one - f i      -- not checking that i /= 0 (mod p)
-
--- | @zqHasCRT m q@ says whether @Z_q@ has an /invertible/ CRT
--- transform of index @m@, i.e., @Z_q@ has an element of
--- multiplicative order @m@, and @mhat@ is invertible in @Z_q@.
-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
-
--- the complex numbers have roots of unity of any order
-instance (Transcendental a) => CRTrans (Complex a) where
-  crtInfo m = Just (omegaPowC m, recip $ fromIntegral $ valueHat m)
-
--- trivial CRTEmbed instance for complex numbers
-instance (Transcendental a) => CRTEmbed (Complex a) where
-  type CRTExt (Complex a) = Complex a
-  toExt = id
-  fromExt = id
-
--- Default CRTrans instances for real and integer types, which do
--- not have roots of unity (except in trivial cases). These are needed
--- to use FastCyc with these integer types.
-instance CRTrans Double
-instance CRTrans Int
-instance CRTrans Int64
-instance CRTrans Integer
--- can also do for Int8, Int16, Int32 etc.
-
--- CRTEmbed instances for real and integer types, embedding into
--- Complex.  These are needed to use FastCyc with these integer types.
-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
-  -- CJP: sufficient precision?  Not in general.
-  type CRTExt Integer = Complex Double
-  toExt = fromIntegral
-  fromExt = fst . roundComplex
− src/Crypto/Lol/Cyclotomic/Cyc.hs
@@ -1,184 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,-             FlexibleInstances, GADTs, GeneralizedNewtypeDeriving,-             MultiParamTypeClasses, NoImplicitPrelude, PolyKinds,-             RankNTypes, ScopedTypeVariables, StandaloneDeriving,-             TypeFamilies, TypeOperators, UndecidableInstances #-}---- | An implementation of cyclotomic rings with safe interface:--- functions and instances involving 'Cyc' expose nothing about the--- internal representations of ring elements (e.g., the basis they are--- represented in).  For an experts-only, "unsafe" implementation that--- offers limited exposure of internal representation, use--- 'Crypto.Lol.Cyclotomic.UCyc.UCyc'.--module Crypto.Lol.Cyclotomic.Cyc-( --- * Data type-  Cyc, U.CElt, cyc, unsafeUnCyc--- * Basic operations-, mulG, divG-, scalarCyc, liftCyc-, advisePow, adviseDec, adviseCRT--- * Error sampling-, tGaussian, errorRounded, errorCoset--- * Sub/extension rings-, embed, twace, powBasis, crtSet, coeffsCyc-, module Crypto.Lol.Cyclotomic.Utility-) where--import Algebra.Additive as Additive (C)-import Algebra.Ring     as Ring (C)--import           Crypto.Lol.Cyclotomic.UCyc    (CElt, UCyc)-import qualified Crypto.Lol.Cyclotomic.UCyc    as U-import           Crypto.Lol.Cyclotomic.Utility-import           Crypto.Lol.Gadget-import           Crypto.Lol.LatticePrelude     as LP-import           Crypto.Lol.Types.ZPP--import Control.Applicative    hiding ((*>))-import Control.DeepSeq-import Control.Monad.Random--import Data.Coerce--import Test.QuickCheck---- | Wrapper around 'UCyc' that exposes a narrower, safe interface.-newtype Cyc t m r = Cyc { -  -- | Unsafe deconstructor for 'Cyc'.-  unsafeUnCyc :: UCyc t m r }-                    deriving (Arbitrary, Random)---- See: https://ghc.haskell.org/trac/ghc/ticket/11008--- for why I have to use StandaloneDeriving here-deriving instance NFData (UCyc t m a) => NFData (Cyc t m a)-deriving instance Show (UCyc t m a) => Show (Cyc t m a)-deriving instance Eq (UCyc t m a) => Eq (Cyc t m a)-deriving instance Additive (UCyc t m a) => Additive.C (Cyc t m a)-deriving instance Ring (UCyc t m a) => Ring.C (Cyc t m a)-deriving instance Gadget gad (UCyc t m a) => Gadget gad (Cyc t m a)-deriving instance Correct gad (UCyc t m a) => Correct gad (Cyc t m a)---- | Smart constructor (to prevent clients from pattern-matching).-cyc :: UCyc t m r -> Cyc t m r-cyc = Cyc---- (try to) replace all occurrences of 'Cyc' with 'UCyc'-type family O a where-  O (Cyc t m a) = UCyc t m a-  O (a -> b) = O a -> O b-  O (m a) = m (O a)             -- works for concrete m, but not vars-  O a = a---- specialized 'coerce', to aid type inference-coerceCyc :: (Coercible (O a) a) => O a -> a-coerceCyc = coerce---- Can't seem to auto-derive these, due to constraints with GND and --- MPTCs.-instance (Reduce a b, Fact m, CElt t a, CElt t b)-         => Reduce (Cyc t m a) (Cyc t m b) where-  reduce = coerceCyc reduce---- CJP: will this pick the right overlapping instance for UCyc?  I--- think so...-instance (RescaleCyc (UCyc t) a b) => RescaleCyc (Cyc t) a b where-  rescaleCyc = coerceCyc rescaleCyc--instance (Decompose gad (UCyc t m zq),-          Reduce (Cyc t m (DecompOf zq)) (Cyc t m zq))-         => Decompose gad (Cyc t m zq) where--  type DecompOf (Cyc t m zq) = Cyc t m (DecompOf zq)-  decompose = coerceCyc decompose------------ Core cyclotomic operations ------------adviseCRT, advisePow, adviseDec :: (Fact m, CElt t r) => Cyc t m r -> Cyc t m r---- | Yield an equivalent element that /may/ be in a CRT--- representation.  This can serve as an optimization hint. E.g.,--- call 'adviseCRT' prior to multiplying the same value by many--- other values.-adviseCRT = coerceCyc U.adviseCRT---- | Same as 'adviseCRT', but for the powerful-basis representation.-advisePow = coerceCyc U.forcePow -- do it, but not required by contract---- | Same as 'adviseCRT', but for the powerful-basis representation.-adviseDec = coerceCyc U.forceDec----- | Multiply by the special element @g@ of the @m@th cyclotomic.-mulG :: (Fact m, CElt t r) => Cyc t m r -> Cyc t m r-mulG = coerceCyc U.mulG---- | Divide by @g@, returning 'Nothing' if not evenly divisible.--- WARNING: this implementation is not a constant-time algorithm, so--- information about the argument may be leaked through a timing--- channel.-divG :: (Fact m, CElt t r) => Cyc t m r -> Maybe (Cyc t m r)-divG = coerceCyc U.divG---- | Sample from the "tweaked" Gaussian error distribution @t*D@ in--- the decoding basis, where @D@ has scaled variance @v@.  Note: This--- implementation uses Double precision to generate the Gaussian--- sample, which may not be sufficient for rigorous proof-based--- security.-tGaussian :: (Fact m, OrdFloat q, Random q, CElt t q,-              ToRational v, MonadRandom rnd)-             => v -> rnd (Cyc t m q)-tGaussian = (Cyc <$>) . U.tGaussian---- | Generate an LWE error term with given scaled variance,--- deterministically rounded in the decoding basis.-errorRounded :: (ToInteger z, Fact m, CElt t z,-                 ToRational v, MonadRandom rnd)-                => v -> rnd (Cyc t m z)-errorRounded = (Cyc <$>) . U.errorRounded---- | Generate an LWE error term with given scaled variance @* p^2@ over--- the given coset, deterministically rounded in the decoding basis.-errorCoset ::-  (Mod zp, z ~ ModRep zp, Lift zp z, Fact m,-   CElt t zp, CElt t z, ToRational v, MonadRandom rnd)-  => v -> Cyc t m zp -> rnd (Cyc t m z)-errorCoset v = (Cyc <$>) . U.errorCoset v . unsafeUnCyc---- | Embed into the extension ring.-embed :: (m `Divides` m', CElt t r) => Cyc t m r -> Cyc t m' r-embed = coerceCyc U.embed---- | The "tweaked trace" (twace) function--- @Tw(x) = (mhat \/ m'hat) * Tr(g' \/ g * x)@,--- which fixes @R@ pointwise (i.e., @twace . embed == id@).-twace :: (m `Divides` m', CElt t r) => Cyc t m' r -> Cyc t m r-twace = coerceCyc U.twace---- | Return the given element's coefficient vector with respect to--- the (relative) powerful/decoding basis of the cyclotomic--- extension @O_m' / O_m@.-coeffsCyc :: (m `Divides` m', CElt t r)-             => Basis -> Cyc t m' r -> [Cyc t m r]-coeffsCyc = coerceCyc U.coeffsCyc---- | The relative powerful basis of @O_m' / O_m@.-powBasis :: (m `Divides` m', CElt t r) => Tagged m [Cyc t m' r]-powBasis = coerceCyc U.powBasis---- | The relative mod-@r@ "CRT set" of the extension.-crtSet :: (m `Divides` m', ZPP r, CElt t r, CElt t (ZPOf r))-          => Tagged m [Cyc t m' r]-crtSet = coerceCyc U.crtSet---- | Lift in the specified basis.-liftCyc :: (Lift b a, Fact m, CElt t a, CElt t b)-           => Basis -> Cyc t m b -> Cyc t m a-liftCyc = coerceCyc U.liftCyc---- | Embed a scalar from the base ring as a cyclotomic element.-scalarCyc :: (Fact m, CElt t a) => a -> Cyc t m a-scalarCyc = Cyc . U.scalarCyc--
− src/Crypto/Lol/Cyclotomic/Linear.hs
@@ -1,89 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,-             GeneralizedNewtypeDeriving, KindSignatures,-             MultiParamTypeClasses, NoImplicitPrelude, RoleAnnotations,-             ScopedTypeVariables, StandaloneDeriving,-             TypeFamilies, TypeOperators, UndecidableInstances #-}---- | Functions from one cyclotomic ring to another that are linear--- over a common subring.--module Crypto.Lol.Cyclotomic.Linear-( Linear, ExtendLinIdx-, linearDec, evalLin, extendLin-) where--import Crypto.Lol.Cyclotomic.Cyc-import Crypto.Lol.LatticePrelude--import Algebra.Additive as Additive (C)--import Control.Applicative-import Control.DeepSeq---- | An @E@-linear function from @R@ to @S@.-newtype Linear t z (e::Factored) (r::Factored) (s::Factored) = D [Cyc t s z]--deriving instance (NFData (Cyc t s z)) => NFData (Linear t z e r s)---- TODO: have constructor for both relative Pow basis of R/E?---- some params are phantom but matter for safety-type role Linear representational nominal representational representational nominal---- | Construct an @E@-linear function given a list of its output values--- (in @S@) on the relative decoding basis of @R/E@.  The number of--- elements in the list must not exceed the size of the basis.-linearDec :: forall t z e r s .-             (e `Divides` r, e `Divides` s, CElt t z)-             => [Cyc t s z] -> Linear t z e r s-linearDec ys = let ps = proxy powBasis (Proxy::Proxy e) `asTypeOf` ys-               in if length ys <= length ps then D (adviseCRT <$> ys)-               else error $ "linearDec: too many entries: "-                           ++ show (length ys) ++ " versus "-                           ++ show (length ps)---- | Evaluates the given linear function on the input.-evalLin :: forall t z e r s .-           (e `Divides` r, e `Divides` s, CElt t z)-           => Linear t z e r s -> Cyc t r z -> Cyc t s z-evalLin (D ys) r = sum (zipWith (*) ys $-                        embed <$> (coeffsCyc Dec r :: [Cyc t e z]))--instance Additive (Cyc t s z) => Additive.C (Linear t z e r s) where-  zero = D []--  (D as) + (D bs) = D $ sumall as bs-    where sumall [] ys = ys-          sumall xs [] = xs-          sumall (x:xs) (y:ys) = x+y : sumall xs ys--  negate (D as) = D $ negate <$> as--instance (Reduce z zq, Fact s, CElt t z, CElt t zq)-         => Reduce (Linear t z e r s) (Linear t zq e r s) where-  reduce (D ys) = D $ reduce <$> ys--instance (CElt t zp, CElt t z, z ~ LiftOf zp, Lift zp z, Fact s)-         => Lift' (Linear t zp e r s) where-  type LiftOf (Linear t zp e r s) = Linear t (LiftOf zp) e r s--  lift (D ys) = D $ liftCyc Pow <$> ys---- | A convenient constraint synonym for extending a linear function--- to larger rings.-type ExtendLinIdx e r s e' r' s' =-  (Fact r, e ~ FGCD r e', r' ~ FLCM r e', -- these imply R'=R\otimes_E E'-   e' `Divides` s', s `Divides` s') -- lcm(s,e')|s' <=> (S+E') \subseteq S'---- | Extend an @E@-linear function @R->S@ to an @E'@-linear function--- @R\'->S\'@.  (Mathematically, such extension only requires--- @lcm(r,e\') | r\'@ (not equality), but this generality would--- significantly complicate the implementation, and for our purposes--- there's no reason to use any larger @r'@.)-extendLin :: (ExtendLinIdx e r s e' r' s', CElt t z)-           => Linear t z e r s -> Linear t z e' r' s'--- CJP: this simple implementation works because R/E and R'/E' have--- identical decoding bases, because R' \cong R \otimes_E E'.  If we--- relax the constraint on E then we'd have to change the--- implementation to something more difficult.-extendLin (D ys) = D (embed <$> ys)
− src/Crypto/Lol/Cyclotomic/Tensor.hs
@@ -1,412 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,-             NoImplicitPrelude, RankNTypes, ScopedTypeVariables, -             TupleSections, TypeFamilies, TypeOperators, -             UndecidableInstances #-}---- | Interface for cyclotomic tensors, and helper functions for tensor--- indexing.--module Crypto.Lol.Cyclotomic.Tensor-( Tensor(..)--- * Top-level CRT functions-, hasCRTFuncs-, scalarCRT, mulGCRT, divGCRT, crt, crtInv, twaceCRT, embedCRT--- * Tensor indexing-, Matrix, indexM, twCRTs-, zmsToIndexFact-, indexInfo-, extIndicesPowDec, extIndicesCRT, extIndicesCoeffs-, baseIndicesPow, baseIndicesDec, baseIndicesCRT-, digitRev-)-where--import Crypto.Lol.CRTrans-import Crypto.Lol.LatticePrelude as LP hiding (lift, (*>))-import Crypto.Lol.Types.FiniteField--import           Control.Applicative-import           Control.DeepSeq-import           Control.Monad.Random-import           Data.Constraint-import           Data.Singletons.Prelude hiding ((:-))-import           Data.Traversable-import           Data.Tuple           (swap)-import qualified Data.Vector          as V-import qualified Data.Vector.Unboxed  as U---- | 'Tensor' encapsulates all the core linear transformations needed--- for cyclotomic ring arithmetic.---- | The type @t m r@ represents a cyclotomic coefficient tensor of--- index @m@ over base ring @r@.  Most of the methods represent linear--- transforms corresponding to operations in particular bases.--- CRT-related methods are wrapped in 'Maybe' because they are--- well-defined only when a CRT basis exists over the ring @r@ for--- index @m@.---- | The superclass constraint is for convenience, to ensure that we--- can sample error tensors of 'Double's.--class (TElt t Double, TElt t (Complex Double))-      => Tensor (t :: Factored -> * -> *) where--  -- | Constraints needed by @t@ to hold type @r@.-  type TElt t r :: Constraint--  -- | Properties that hold for any index. Use with '\\'.-  entailIndexT :: Tagged (t m r)-                  (Fact m :- (Applicative (t m), Traversable (t m)))-  -  -- | Properties that hold for any (legal) fully-applied tensor. Use-  -- with '\\'.-  entailEqT :: Tagged (t m r)-               ((Eq r, Fact m, TElt t r) :- (Eq (t m r)))-  entailZTT :: Tagged (t m r)-               ((ZeroTestable r, Fact m, TElt t r) :- (ZeroTestable (t m r)))-  entailRingT :: Tagged (t m r)-                 ((Ring r, Fact m, TElt t r) :- (Ring (t m r)))-  entailNFDataT :: Tagged (t m r)-                   ((NFData r, Fact m, TElt t r) :- (NFData (t m r)))-  entailRandomT :: Tagged (t m r)-                   ((Random r, Fact m, TElt t r) :- (Random (t m r)))--  -- | Converts a scalar to a tensor in the powerful basis-  scalarPow :: (Ring r, Fact m, TElt t r) => r -> t m r--  -- | 'l' converts from decoding-basis representation to-  -- powerful-basis representation; 'lInv' is its inverse.-  l, lInv :: (Ring r, Fact m, TElt t r) => t m r -> t m r--  -- | Multiply by @g@ in the powerful/decoding basis-  mulGPow, mulGDec :: (Ring r, Fact m, TElt t r) => t m r -> t m r--  -- | Divide by @g@ in the powerful/decoding basis.  The 'Maybe'-  -- output indicates that the operation may fail, which happens-  -- exactly when the input is not divisible by @g@.-  divGPow, divGDec :: (ZeroTestable r, IntegralDomain r, Fact m, TElt t r)-                      => t m r -> Maybe (t m r)--  -- | A tuple of all the operations relating to the CRT basis, in a-  -- single 'Maybe' value for safety.  Clients should typically not-  -- use this method directly, but instead call the corresponding-  -- top-level functions: the elements of the tuple correpond to the-  -- functions 'scalarCRT', 'mulGCRT', 'divGCRT', 'crt', 'crtInv'.-  crtFuncs :: (ZeroTestable r, IntegralDomain r, CRTrans r, Fact m, TElt t r) =>-              Maybe (    r -> t m r, -- scalarCRT-                     t m r -> t m r, -- mulGCRT-                     t m r -> t m r, -- divGCRT-                     t m r -> t m r, -- crt-                     t m r -> t m r) -- crtInv--  -- | Sample from the "skewed" Gaussian error distribution @t*D@-  -- in the decoding basis, where @D@ has scaled variance @v@.-  tGaussianDec :: (OrdFloat q, Random q, TElt t q,-                   ToRational v, Fact m, MonadRandom rnd)-                  => v -> rnd (t m q)--  -- | The @twace@ linear transformation, which is the same in both the-  -- powerful and decoding bases.-  twacePowDec :: (Ring r, m `Divides` m', TElt t r) => t m' r -> t m r--  -- | The @embed@ linear transformations, for the powerful and-  -- decoding bases.-  embedPow, embedDec :: (Ring r, m `Divides` m', TElt t r)-                        => t m r -> t m' r--  -- | A tuple of all the extension-related operations involving the-  -- CRT bases, for safety.  Clients should typically not use this-  -- method directly, but instead call the corresponding top-level-  -- functions: the elements of the tuple correpond to the functions-  -- 'twaceCRT', 'embedCRT'.-  crtExtFuncs :: (ZeroTestable r, IntegralDomain r, CRTrans r,-                  m `Divides` m', TElt t r) =>-                 Maybe (t m' r -> t m  r, -- twaceCRT-                        t m  r -> t m' r) -- embedCRT--  -- | Map a tensor in the powerful\/decoding\/CRT basis, representing-  -- an @O_m'@ element, to a vector of tensors representing @O_m@-  -- elements in the same kind of basis.-  coeffs :: (Ring r, m `Divides` m', TElt t r) => t m' r -> [t m r]--  -- | The powerful extension basis w.r.t. the powerful basis.-  powBasisPow :: (Ring r, TElt t r, m `Divides` m') => Tagged m [t m' r]--  -- | A list of tensors representing the mod-@p@ CRT set of the-  -- extension.-  crtSetDec :: (PrimeField fp, m `Divides` m',-                Coprime (PToF (CharOf fp)) m', TElt t fp)-               => Tagged m [t m' fp]--  -- | Potentially optimized version of 'fmap' when the input and-  -- output element types satisfy 'TElt'.-  fmapT :: (Fact m, TElt t a, TElt t b) => (a -> b) -> t m a -> t m b-  -- | Potentially optimized monadic 'fmap'.-  fmapTM :: (Monad mon, Fact m, TElt t a, TElt t b)-             => (a -> mon b) -> t m a -> mon (t m b)---- | Convenience value indicating whether 'crtFuncs' exists.-hasCRTFuncs :: forall t m r . (ZeroTestable r, IntegralDomain r, CRTrans r, -                               Tensor t, Fact m, TElt t r)-               => TaggedT (t m r) Maybe ()-hasCRTFuncs = tagT $ do-  (_ :: r -> t m r,_,_,_,_) <- crtFuncs-  return ()---- | Yield a tensor for a scalar in the CRT basis.  (This function is--- simply an appropriate entry from 'crtFuncs'.)-scalarCRT :: (ZeroTestable r, IntegralDomain r, CRTrans r, -              Tensor t, Fact m, TElt t r) => Maybe (r -> t m r)-scalarCRT = (\(f,_,_,_,_) -> f) <$> crtFuncs---mulGCRT, divGCRT, crt, crtInv ::-  (ZeroTestable r, IntegralDomain r, CRTrans r, Tensor t, Fact m, TElt t r)-  => Maybe (t m r -> t m r)--- | Multiply by @g@ in the CRT basis. (This function is simply an--- appropriate entry from 'crtFuncs'.)-mulGCRT = (\(_,f,_,_,_) -> f) <$> crtFuncs--- | Divide by @g@ in the CRT basis.  (This function is simply an--- appropriate entry from 'crtFuncs'.)-divGCRT = (\(_,_,f,_,_) -> f) <$> crtFuncs--- | The CRT transform.  (This function is simply an appropriate entry--- from 'crtFuncs'.)-crt = (\(_,_,_,f,_) -> f) <$> crtFuncs--- | The inverse CRT transform.  (This function is simply an--- appropriate entry from 'crtFuncs'.)-crtInv = (\(_,_,_,_,f) -> f) <$> crtFuncs---- | The "tweaked trace" function for tensors in the CRT basis:--- For cyclotomic indices m | m',--- @Tw(x) = (mhat\/m\'hat) * Tr(g\'\/g * x)@.--- (This function is simply an appropriate entry from 'crtExtFuncs'.)-twaceCRT :: forall t r m m' . (ZeroTestable r, IntegralDomain r, CRTrans r, -                               Tensor t, m `Divides` m', TElt t r)-            => Maybe (t m' r -> t m r)-twaceCRT = proxyT hasCRTFuncs (Proxy::Proxy (t m' r)) *>-           proxyT hasCRTFuncs (Proxy::Proxy (t m  r)) *>-           (fst <$> crtExtFuncs)---- | Embed a tensor with index @m@ in the CRT basis to a tensor with--- index @m'@ in the CRT basis.--- (This function is simply an appropriate entry from 'crtExtFuncs'.)-embedCRT :: forall t r m m' . (ZeroTestable r, IntegralDomain r, CRTrans r, -                               Tensor t, m `Divides` m', TElt t r)-            => Maybe (t m r -> t m' r)-embedCRT = proxyT hasCRTFuncs (Proxy::Proxy (t m' r)) *>-           proxyT hasCRTFuncs (Proxy::Proxy (t m  r)) *>-           (snd <$> crtExtFuncs)--fMatrix :: forall m r mon . (Fact m, Monad mon, Ring r)-           => (forall pp . (PPow pp) => TaggedT pp mon (MatrixC r))-           -> TaggedT m mon (Matrix r)-fMatrix mat = tagT $ go $ sUnF (sing :: SFactored m)-  where go :: Sing (pplist :: [PrimePower]) -> mon (Matrix r)-        go spps = case spps of-          SNil -> return MNil-          (SCons spp rest) -> do-            rest' <- go rest-            mat' <- withWitnessT mat spp-            return $ MKron rest' mat'---- deeply embedded DSL for Kronecker products of matrices--data MatrixC r = -  MC (Int -> Int -> r)           -- yields element i,j-  Int Int                        -- dims---- | A Kronecker product of zero of more matrices over @r@.-data Matrix r = MNil | MKron (Matrix r) (MatrixC r)---- | Extract the @(i,j)@ element of a 'Matrix'.-indexM :: Ring r => Matrix r -> Int -> Int -> r-indexM MNil 0 0 = LP.one-indexM (MKron m (MC mc r c)) i j =-  let (iq,ir) = i `divMod` r-      (jq,jr) = j `divMod` c-      in indexM m iq jq * mc ir jr---- | The "tweaked" CRT^* matrix: @CRT^* . diag(sigma(g_m))@.-twCRTs :: (Fact m, CRTrans r) => TaggedT m Maybe (Matrix r)-twCRTs = fMatrix twCRTsPPow---- | The "tweaked" CRT^* matrix (for prime powers): @CRT^* * diag(sigma(g_p))@.-twCRTsPPow :: (PPow pp, CRTrans r) => TaggedT pp Maybe (MatrixC r)-twCRTsPPow = do-  phi    <- pureT totientPPow-  iToZms <- pureT indexToZmsPPow-  jToPow <- pureT indexToPowPPow-  (wPow, _) <- crtInfoPPow-  gEmb <- gEmbPPow--  return $ MC (\j i -> let i' = iToZms i-                       in wPow (jToPow j * negate i') * gEmb i') phi phi---- Reindexing functions---- | Base-p digit reversal; input and output are in @[p^e]@.-digitRev :: PP -> Int -> Int-digitRev (_,0) 0 = 0--- CJP: use accumulator to avoid multiple exponentiations?-digitRev (p,e) j -  | e >= 1 = let (q,r) = j `divMod` p-             in r * (p^(e-1)) + digitRev (p,e-1) q--indexToPowPPow, indexToZmsPPow :: PPow pp => Tagged pp (Int -> Int)-indexToPowPPow = indexToPow <$> ppPPow-indexToZmsPPow = indexToZms <$> ppPPow---- | Convert a @Z_m^*@ index to a linear tensor index in @[m]@.-zmsToIndexFact :: Fact m => Tagged m (Int -> Int)-zmsToIndexFact = zmsToIndex <$> ppsFact---- | For a prime power @p^e@, map a tensor index to the corresponding--- power j in @[phi(p^e)]@, as in the powerful basis.-indexToPow :: PP -> Int -> Int--- CJP: use accumulator to avoid multiple exponentiations?-indexToPow (p,e) j = let (jq,jr) = j `divMod` (p-1)-                     in p^(e-1)*jr + digitRev (p,e-1) jq---- | For a prime power @p^e@, map a tensor index to the corresponding--- element i in @Z_{p^e}^*@.-indexToZms :: PP -> Int -> Int-indexToZms (p,_) i = let (i1,i0) = i `divMod` (p-1)-                       in p*i1 + i0 + 1 ---- | Convert a Z_m^* index to a linear tensor index.-zmsToIndex :: [PP] -> Int -> Int-zmsToIndex [] _ = 0-zmsToIndex (pp:rest) i = zmsToIndexPP pp (i `mod` valuePP pp)-                         + (totientPP pp) * zmsToIndex rest i---- | Inverse of 'indexToZms'.-zmsToIndexPP :: PP -> Int -> Int-zmsToIndexPP (p,_) i = let (i1,i0) = i `divMod` p-                       in (p-1)*i1 + i0 - 1---- Index correspondences for ring extensions---- | Correspondences between the linear indexes into a basis of O_m',--- and pair indices into (extension basis) \otimes (basis of O_m).--- The work the same for Pow,Dec,CRT bases because all these bases--- have that factorization.  The first argument is the list of--- @(phi(m),phi(m'))@ pairs for the (merged) prime powers of @m@,@m'@.-toIndexPair :: [(Int,Int)] -> Int -> (Int,Int)-fromIndexPair :: [(Int,Int)] -> (Int,Int) -> Int--toIndexPair [] 0 = (0,0)-toIndexPair ((phi,phi'):rest) i' =-  let (i'q,i'r) = i' `divMod` phi'-      (i'rq,i'rr) = i'r `divMod` phi-      (i'q1,i'q0) = toIndexPair rest i'q-  in (i'rq + i'q1*(phi' `div` phi), i'rr + i'q0*phi)--fromIndexPair [] (0,0) = 0-fromIndexPair ((phi,phi'):rest) (i1,i0) =-  let (i0q,i0r) = i0 `divMod` phi-      (i1q,i1r) = i1 `divMod` (phi' `div` phi)-      i = fromIndexPair rest (i1q,i0q)-  in (i0r + i1r*phi) + i*phi'---- | A collection of useful information for working with tensor--- extensions.  The first component is a list of triples @(p,e,e')@--- where @e@, @e'@ are respectively the exponents of prime @p@ in @m@,--- @m'@.  The next two components are @phi(m)@ and @phi(m')@.  The--- final component is a pair @(phi(p^e), phi(p^e'))@ for each triple--- in the first component.-indexInfo :: forall m m' . (m `Divides` m')-             => Tagged '(m, m') ([(Int,Int,Int)], Int, Int, [(Int,Int)])-indexInfo = let pps = proxy ppsFact (Proxy::Proxy m)-                pps' = proxy ppsFact (Proxy::Proxy m')-                mpps = mergePPs pps pps'-                phi = totientPPs pps-                phi' = totientPPs pps'-                tots = totients mpps-            in tag (mpps, phi, phi', tots)---- | A vector of @phi(m)@ entries, where the @i@th entry is the index--- into the powerful\/decoding basis of @O_m'@ of the--- @i@th entry of the powerful\/decoding basis of @O_m@.-extIndicesPowDec :: (m `Divides` m') => Tagged '(m, m') (U.Vector Int)-extIndicesPowDec = do-  (_, phi, _, tots) <- indexInfo-  return $ U.generate phi (fromIndexPair tots . (0,))---- | A vector of @phi(m)@ blocks of @phi(m')\/phi(m)@ consecutive--- entries. Each block contains all those indices into the CRT basis--- of @O_m'@ that "lie above" the corresponding index into the CRT--- basis of @O_m@.-extIndicesCRT :: forall m m' . (m `Divides` m')-                 => Tagged '(m, m') (U.Vector Int)-extIndicesCRT = do-  (_, phi, phi', tots) <- indexInfo-  return $ U.generate phi'-           (fromIndexPair tots . swap . (`divMod` (phi' `div` phi)))--baseWrapper :: forall m m' a . (m `Divides` m', U.Unbox a)-               => ([(Int,Int,Int)] -> Int -> a)-               -> Tagged '(m, m') (U.Vector a)-baseWrapper f = do-  (mpps, _, phi', _) <- indexInfo-  return $ U.generate phi' (f mpps)---- | A lookup table for 'toIndexPair' applied to indices @[phi(m')]@.-baseIndicesPow :: forall m m' . (m `Divides` m')-                  => Tagged '(m, m') (U.Vector (Int,Int))--- | A lookup table for 'baseIndexDec' applied to indices @[phi(m')]@.-baseIndicesDec :: forall m m' . (m `Divides` m')-                  => Tagged '(m, m') (U.Vector (Maybe (Int,Bool)))---- | Same as 'baseIndicesPow', but only includes the second component--- of each pair.-baseIndicesCRT :: forall m m' . (m `Divides` m')-                  => Tagged '(m, m') (U.Vector Int)--baseIndicesPow = baseWrapper (toIndexPair . totients)---- this one is more complicated; requires the prime powers-baseIndicesDec = baseWrapper baseIndexDec--baseIndicesCRT =-  baseWrapper (\pps -> snd . toIndexPair (totients pps))----- | The @i0@th entry of the @i1@th vector is 'fromIndexPair' @(i1,i0)@.-extIndicesCoeffs :: forall m m' . (m `Divides` m')-                    => Tagged '(m, m') (V.Vector (U.Vector Int))-extIndicesCoeffs = do-  (_, phi, phi', tots) <- indexInfo-  return $ V.generate (phi' `div` phi)-           (\i1 -> U.generate phi (\i0 -> fromIndexPair tots (i1,i0)))---- | Convenient reindexing functions---- | Maps an index of the extension ring array to its corresponding--- index in the base ring array (if it exists), with sign, under the--- decoding basis.-baseIndexDec :: [(Int,Int,Int)] -> Int -> Maybe (Int, Bool)-baseIndexDec [] 0 = Just (0,False)-baseIndexDec ((p,e,e'):rest) i'-   = let (i'q, i'r) = i' `divMod` totientPP (p,e')-         phi = totientPP (p,e)-         curr-           | p>2 && e==0 && e' > 0 = case i'r of-               0 -> Just (0,False)-               1 -> Just (0,True)-               _ -> Nothing-           | otherwise = if i'r < phi then Just (i'r,False) else Nothing-     in do-       (i,b) <- curr-       (j,b') <- baseIndexDec rest i'q-       return (i + phi*j, b /= b')---- the first list of pps must "divide" the other.  result is a list of--- all (prime, min e, max e).-mergePPs :: [PP] -> [PP] -> [(Int,Int,Int)]-mergePPs [] pps = LP.map (\(p,e) -> (p,0,e)) pps-mergePPs allpps@((p,e):pps) ((p',e'):pps')-  | p == p' && e <= e' = (p,  e, e') : mergePPs pps pps'-  | p > p'  = (p', 0, e') : mergePPs allpps pps'--totients :: [(Int, Int, Int)] -> [(Int,Int)]-totients = LP.map (\(p,e,e') -> (totientPP (p,e), totientPP (p,e')))
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor.hs
@@ -1,731 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, DeriveDataTypeable, GADTs,-             FlexibleContexts, FlexibleInstances, TypeOperators, PolyKinds,-             GeneralizedNewtypeDeriving, InstanceSigs, RoleAnnotations,-             MultiParamTypeClasses, NoImplicitPrelude, StandaloneDeriving,-             ScopedTypeVariables, TupleSections, TypeFamilies, RankNTypes,-             TypeSynonymInstances, UndecidableInstances,-             RebindableSyntax #-}---- | Wrapper for a C implementation of the 'Tensor' interface.--module Crypto.Lol.Cyclotomic.Tensor.CTensor-( CT--- Exports below here are due solely to ticket #10338. See CycTests for more details-, CRNS-, Dispatch-) where--import Algebra.Additive as Additive (C)-import Algebra.Ring     as Ring (C)--import Control.Applicative-import Control.DeepSeq-import Control.Monad-import Control.Monad.Identity-import Control.Monad.Random-import Control.Monad.Trans (lift)--import Data.Coerce-import Data.Constraint-import Data.Foldable as F-import Data.Int-import Data.Maybe-import Data.Traversable as T-import Data.Typeable-import Data.Vector.Generic           as V (zip, unzip)-import Data.Vector.Storable          as SV (Vector, replicate, replicateM, thaw, convert, foldl',-                                            unsafeToForeignPtr0, unsafeSlice, mapM, fromList,-                                            generate, foldl1',-                                            unsafeWith, zipWith, map, length, unsafeFreeze, thaw)-import Data.Vector.Storable.Internal (getPtr)-import Data.Vector.Storable.Mutable  as SM hiding (replicate)--import           Foreign.ForeignPtr-import           Foreign.Marshal.Array-import           Foreign.Ptr-import           Foreign.Storable        (Storable (..))-import qualified Foreign.Storable.Record as Store-import           Foreign.Storable.Tuple  ()-import           System.IO.Unsafe-import           Test.QuickCheck         hiding (generate)-import           Unsafe.Coerce--import Crypto.Lol.CRTrans-import Crypto.Lol.LatticePrelude as LP hiding (replicate, unzip, zip, lift)-import Crypto.Lol.Reflects-import Crypto.Lol.Cyclotomic.Tensor--import Crypto.Lol.Types.IZipVector-import Crypto.Lol.Types.ZqBasic-import Crypto.Lol.GaussRandom--import Crypto.Lol.Cyclotomic.Tensor.CTensor.Extension--import Algebra.ZeroTestable   as ZeroTestable (C)----- | Newtype wrapper around a Vector.-newtype CT' (m :: Factored) r = CT' { unCT :: Vector r } -                              deriving (Show, Eq, NFData, Typeable)---- the first argument, though phantom, affects representation-type role CT' representational nominal---- GADT wrapper that distinguishes between Unbox and unrestricted--- element types---- | An implementation of 'Tensor' backed by C code.-data CT (m :: Factored) r where -  CT :: Storable r => CT' m r -> CT m r-  ZV :: IZipVector m r -> CT m r-  deriving (Typeable)--instance Eq r => Eq (CT m r) where-  (ZV x) == (ZV y) = x == y-  (CT x) == (CT y) = x == y-  x@(CT _) == y = x == toCT y-  y == x@(CT _) = x == toCT y--deriving instance Show r => Show (CT m r)--toCT :: (Storable r) => CT m r -> CT m r-toCT v@(CT _) = v-toCT (ZV v) = CT $ zvToCT' v--toZV :: (Fact m) => CT m r -> CT m r-toZV (CT (CT' v)) = ZV $ fromMaybe (error "toZV: internal error") $-                    iZipVector $ convert v-toZV v@(ZV _) = v--zvToCT' :: forall m r . (Storable r) => IZipVector m r -> CT' m r-zvToCT' v = coerce $ (convert $ unIZipVector v :: Vector r)--wrap :: (Storable r) => (CT' l r -> CT' m r) -> (CT l r -> CT m r)-wrap f (CT v) = CT $ f v-wrap f (ZV v) = CT $ f $ zvToCT' v--wrapM :: (Storable r, Monad mon) => (CT' l r -> mon (CT' m r))-         -> (CT l r -> mon (CT m r))-wrapM f (CT v) = liftM CT $ f v-wrapM f (ZV v) = liftM CT $ f $ zvToCT' v---- convert an CT' *twace* signature to Tagged one-type family Tw (r :: *) :: * where-  Tw (CT' m' r -> CT' m r) = Tagged '(m,m') (Vector r -> Vector r)-  Tw (Maybe (CT' m' r -> CT' m r)) = TaggedT '(m,m') Maybe (Vector r -> Vector r)--type family Em r where-  Em (CT' m r -> CT' m' r) = Tagged '(m,m') (Vector r -> Vector r)-  Em (Maybe (CT' m r -> CT' m' r)) = TaggedT '(m,m') Maybe (Vector r -> Vector r)------------- NUMERIC PRELUDE INSTANCES -----------instance (Additive r, Storable r, CRNS r, Fact m)-  => Additive.C (CT m r) where-  (CT a@(CT' _)) + (CT b@(CT' _)) = CT $ (zipWrapper $ untag $ cZipDispatch dadd) a b  --pack $ SV.zipWith (+) (unpack a) (unpack b) -- Vector code ---  a + b = (toCT a) + (toCT b)-  negate (CT (CT' a)) = CT $ CT' $ SV.map negate a -- EAC: This probably should be converted to C code-  negate a = negate $ toCT a--  zero = CT $ repl zero--instance (Fact m, Ring r, Storable r, CRNS r)-  => Ring.C (CT m r) where-  (CT a@(CT' _)) * (CT b@(CT' _)) = CT $ (zipWrapper $ untag $ cZipDispatch dmul) a b  --pack $ SV.zipWith (*) (unpack a) (unpack b) -- Vector code ---  a * b = (toCT a) * (toCT b)--  fromInteger = CT . repl . fromInteger--instance (ZeroTestable r, Storable r, Fact m)-         => ZeroTestable.C (CT m r) where-  --{-# INLINABLE isZero #-} -  isZero (CT (CT' a)) = SV.foldl' (\ b x -> b && isZero x) True a-  isZero (ZV v) = isZero v------------ "Container" instances ------------instance Fact m => Functor (CT m) where-  -- Functor instance is implied by Applicative laws-  fmap f x = pure f <*> x--instance Fact m => Applicative (CT m) where-  pure = ZV . pure--  (ZV f) <*> (ZV a) = ZV (f <*> a)-  f@(ZV _) <*> v@(CT _) = f <*> toZV v--instance Fact m => Foldable (CT m) where-  -- Foldable instance is implied by Traversable-  foldMap = foldMapDefault--instance Fact m => Traversable (CT m) where-  traverse f r@(CT _) = T.traverse f $ toZV r-  traverse f (ZV v) = ZV <$> T.traverse f v--instance Tensor CT where--  type TElt CT r = (Storable r, CRNS r)--  entailIndexT = tag $ Sub Dict-  entailEqT = tag $ Sub Dict-  entailZTT = tag $ Sub Dict-  entailRingT = tag $ Sub Dict-  entailNFDataT = tag $ Sub Dict-  entailRandomT = tag $ Sub Dict---  scalarPow = CT . scalarPow' -- Vector code--  l = wrap $ lgWrapper $ untag $ lgDispatch dl-  lInv = wrap $ lgWrapper $ untag $ lgDispatch dlinv--  mulGPow = wrap mulGPow' -- mulGPow' already has lgWrapper-  mulGDec = wrap $ lgWrapper $ untag $ lgDispatch dmulgdec--  divGPow = wrapM $ divGPow'-  -- we divide by p in the C code (for divGDec only(?)), do NOT call checkDiv!-  divGDec = wrapM $ divGWrapper $ Just . (untag $ lgDispatch dginvdec)--  crtFuncs = (,,,,) <$>-    Just (CT . repl) <*>-    (liftM wrap $ crtWrapper $ (untag $ cZipDispatch dmul) <$> untagT gCoeffsCRT) <*>-    (liftM wrap $ crtWrapper $ (untag $ cZipDispatch dmul) <$> untagT gInvCoeffsCRT) <*>-    (liftM wrap $ untagT $ crt') <*>-    (liftM wrap $ crtWrapper $ untagT ctCRTInv) --  twacePowDec = wrap $ runIdentity $ coerceTw twacePowDec'-  embedPow = wrap $ runIdentity $ coerceEm embedPow'-  embedDec = wrap $ runIdentity $ coerceEm embedDec'--  tGaussianDec v = liftM CT $ gaussWrapper $ cDispatchGaussian v-  --tGaussianDec v = liftM CT $ coerceT' $ gaussianDec v--  crtExtFuncs = (,) <$> (liftM wrap $ coerceTw twaceCRT')-                    <*> (liftM wrap $ coerceEm embedCRT')--  coeffs = wrapM $ coerceCoeffs $ coeffs'--  powBasisPow = (CT <$>) <$> coerceBasis powBasisPow'--  crtSetDec = (CT <$>) <$> coerceBasis crtSetDec'--  fmapT f (CT v) = CT $ coerce (SV.map f) v-  fmapT f v@(ZV _) = fmapT f $ toCT v--  fmapTM f (CT (CT' arr)) = liftM (CT . CT') $ SV.mapM f arr-  fmapTM f v@(ZV _) = fmapTM f $ toCT v--coerceTw :: (Functor mon) => (TaggedT '(m, m') mon (Vector r -> Vector r)) -> mon (CT' m' r -> CT' m r)-coerceTw = (coerce <$>) . untagT--coerceEm :: (Functor mon) => (TaggedT '(m, m') mon (Vector r -> Vector r)) -> mon (CT' m r -> CT' m' r)-coerceEm = (coerce <$>) . untagT---- | Useful coersion for defining @coeffs@ in the @Tensor@--- interface. Using 'coerce' alone is insufficient for type inference.-coerceCoeffs :: (Fact m, Fact m') -  => Tagged '(m,m') (Vector r -> [Vector r]) -> CT' m' r -> [CT' m r]-coerceCoeffs = coerce---- | Useful coersion for defining @powBasisPow@ and @crtSetDec@ in the @Tensor@--- interface. Using 'coerce' alone is insufficient for type inference.-coerceBasis :: -  (Fact m, Fact m')-  => Tagged '(m,m') ([Vector r]) -> Tagged m [CT' m' r]-coerceBasis = coerce---- | Class to dispatch to the C backend for various element types.-class CRNS r where--  zipWrapper :: (Fact m, Additive r) => -    (forall a . (TElt CT a, Dispatch a, Additive a) => CT' m a -> CT' m a -> CT' m a)-    -> CT' m r -> CT' m r -> CT' m r--  crtWrapper :: (Fact m, CRTrans r, ZeroTestable r, IntegralDomain r) => -    (forall a . (TElt CT a, CRTrans a, Dispatch a, ZeroTestable a, IntegralDomain a) => Maybe (CT' m a -> CT' m a))-    -> Maybe (CT' m r -> CT' m r)--  lgWrapper :: (Fact m, Additive r) => -    (forall a . (TElt CT a, Dispatch a, Additive a) => CT' m a -> CT' m a)-    -> CT' m r -> CT' m r--  divGWrapper :: (Fact m, IntegralDomain r, ZeroTestable r) => -    (forall a . (TElt CT a, Dispatch a, IntegralDomain a, ZeroTestable a) => CT' m a -> Maybe (CT' m a))-    -> CT' m r -> Maybe (CT' m r)--  gaussWrapper :: (Fact m, MonadRandom rnd, Random r) => -    (forall a . (TElt CT a, Dispatch a, OrdFloat a, MonadRandom rnd, Random a) => rnd (CT' m a))-    -> rnd (CT' m r)--instance CRNS Double where-  zipWrapper f = f-  crtWrapper f = f-  lgWrapper f = f-  divGWrapper f = f-  gaussWrapper f = f--instance CRNS Int64 where-  zipWrapper f = f-  crtWrapper f = f-  lgWrapper f = f-  divGWrapper f = f-  gaussWrapper = error "Cannot call gaussianDec for Int64"--instance (TElt CT (Complex a), Dispatch (Complex a)) => CRNS (Complex a) where-  zipWrapper f = f-  crtWrapper f = f-  lgWrapper f = f-  divGWrapper f = f-  gaussWrapper = error "Cannot call gaussianDec for Complex"---- EAC: we need PolyKinds in paritcular for this instance-instance (TElt CT (ZqBasic q i), Dispatch (ZqBasic q i)) => CRNS (ZqBasic q i) where-  zipWrapper f = f-  crtWrapper f = f-  lgWrapper f = f-  divGWrapper f = f-  gaussWrapper = error "Cannot call gaussianDec for ZqBasic"--instance (Storable a, Storable b, -          CRNS a, CRNS b, -          CRTrans a, CRTrans b, -          ZeroTestable a, ZeroTestable b, -          IntegralDomain a, IntegralDomain b,-          Random a, Random b) -  => CRNS (a,b) where-  zipWrapper f (CT' x :: CT' m (a,b)) (CT' y) =-    let (a,b) = unzip x-        (c,d) = unzip y-        (CT' ac) = zipWrapper f (CT' a :: CT' m a) (CT' c)-        (CT' bd) = zipWrapper f (CT' b :: CT' m b) (CT' d)-    in CT' $ zip ac bd--  crtWrapper f = do-    fa <- crtWrapper f-    fb <- crtWrapper f-    return $ \ (CT' x :: CT' m (a,b)) -> -      let (a,b) = unzip x-          (CT' a') = fa (CT' a :: CT' m a)-          (CT' b') = fb (CT' b :: CT' m b)-      in CT' $ zip a' b'--  lgWrapper f (CT' x :: CT' m (a,b)) = -    let (a, b) = unzip x-        (CT' a') = lgWrapper f (CT' a :: CT' m a)-        (CT' b') = lgWrapper f (CT' b :: CT' m b)-    in CT' $ zip a' b'--  divGWrapper f (CT' x :: CT' m (a,b)) = -    let (a, b) = unzip x-    in do -- in Maybe-      (CT' a') <- divGWrapper f (CT' a :: CT' m a)-      (CT' b') <- divGWrapper f (CT' b :: CT' m b)-      return $ CT' $ zip a' b'--  gaussWrapper f = do-    (CT' a) <- gaussWrapper f-    (CT' b) <- gaussWrapper f-    return $ CT' $ zip a b--mulGPow' :: (TElt CT r, Fact m, Additive r) => CT' m r -> CT' m r-mulGPow' = lgWrapper $ untag $ lgDispatch dmulgpow--divGPow' :: forall m r . (TElt CT r, Fact m, IntegralDomain r, ZeroTestable r) => CT' m r -> Maybe (CT' m r)-divGPow' = divGWrapper $ untag $ checkDiv $ lgDispatch dginvpow--crt' :: forall m r . (TElt CT r, Fact m, CRTrans r, ZeroTestable r, IntegralDomain r) -  => TaggedT m Maybe (CT' m r -> CT' m r)-crt' = tagT $ crtWrapper $ do-  f <- proxyT ctCRT (Proxy::Proxy m)-  return $ CT' . f . unCT----{-# INLINE lgDispatch #-}-lgDispatch :: forall m r .-     (Storable r, Fact m, Additive r)-      => (Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ())-         -> Tagged m (CT' m r -> CT' m r)-lgDispatch f = do-  factors <- liftM marshalFactors ppsFact-  totm <- liftM fromIntegral totientFact-  let numFacts = fromIntegral $ SV.length factors-  return $ coerce $ \yin -> unsafePerformIO $ do -- in IO-    yout <- SV.thaw yin-    SM.unsafeWith yout (\pout ->-      SV.unsafeWith factors (\pfac ->-        f pout totm pfac numFacts))-    unsafeFreeze yout----{-# INLINE ctCRT #-}-ctCRT :: forall m r .-         (Storable r, CRTrans r, Dispatch r,-          Fact m)-         => TaggedT m Maybe (Vector r -> Vector r)-ctCRT = do -- in TaggedT m Maybe-  ru' <- ru-  factors <- pureT $ liftM marshalFactors ppsFact-  totm <- pureT $ liftM fromIntegral totientFact-  let numFacts = fromIntegral $ SV.length factors-  return $ \yin -> unsafePerformIO $ do -- in IO-    yout <- SV.thaw yin-    SM.unsafeWith yout (\pout ->-      SV.unsafeWith factors (\pfac ->-        withPtrArray ru' (\ruptr ->-          dcrt pout totm pfac numFacts ruptr)))-    unsafeFreeze yout---- CTensor CRT^(-1) functions take inverse rus---{-# INLINE ctCRTInv #-}-ctCRTInv :: (Storable r, CRTrans r, Dispatch r,-          Fact m)-         => TaggedT m Maybe (CT' m r -> CT' m r)-ctCRTInv = do -- in Maybe-  mhatInv <- liftM snd $ crtInfoFact-  ruinv' <- ruInv-  factors <- pureT $ liftM marshalFactors ppsFact-  totm <- pureT $ liftM fromIntegral totientFact-  let numFacts = fromIntegral $ SV.length factors-  -- EAC: can't use coerce here?-  return $ \(CT' yin) -> unsafePerformIO $ do-    yout <- SV.thaw yin-    SM.unsafeWith yout (\pout ->-      SV.unsafeWith factors (\pfac ->-        withPtrArray ruinv' (\ruptr ->-          dcrtinv pout totm pfac numFacts ruptr mhatInv)))-    CT' <$> unsafeFreeze yout--checkDiv :: forall m r . -  (IntegralDomain r, Storable r, ZeroTestable r, -   Fact m)-    => Tagged m (CT' m r -> CT' m r) -> Tagged m (CT' m r -> Maybe (CT' m r))-checkDiv f = do-  f' <- f-  oddRad' <- liftM fromIntegral oddRadicalFact-  return $ \x -> -    let (CT' y) = f' x-    in CT' <$> (SV.mapM (`divIfDivis` oddRad')) y--divIfDivis :: (IntegralDomain r, ZeroTestable r) => r -> r -> Maybe r-divIfDivis num den = let (q,r) = num `divMod` den-                     in if isZero r then Just q else Nothing--cZipDispatch :: (Storable r, Fact m, Additive r)-  => (Ptr r -> Ptr r -> Int64 -> IO ())-     -> Tagged m (CT' m r -> CT' m r -> CT' m r)-cZipDispatch f = do -- in Tagged m-  totm <- liftM fromIntegral $ totientFact-  return $ coerce $ \a b -> unsafePerformIO $ do-    yout <- SV.thaw a-    SM.unsafeWith yout (\pout ->-      SV.unsafeWith b (\pin ->-        f pout pin totm))-    unsafeFreeze yout--cDispatchGaussian :: forall m r var rnd .-         (Storable r, Transcendental r, Dispatch r, Ord r,-          Fact m, ToRational var, Random r, MonadRandom rnd)-         => var -> rnd (CT' m r)-cDispatchGaussian var = liftM CT' $ flip proxyT (Proxy::Proxy m) $ do -- in TaggedT m rnd-  -- get rus for (Complex r)-  ruinv' <- mapTaggedT (return . fromMaybe (error "complexGaussianRoots")) $ ruInv-  factors <- liftM marshalFactors $ pureT ppsFact-  totm <- pureT totientFact-  m <- pureT valueFact-  rad <- pureT radicalFact-  yin <- lift $ realGaussians (var * fromIntegral (m `div` rad)) totm-  let numFacts = fromIntegral $ SV.length factors-  return $ unsafePerformIO $ do -- in IO-    --let yin = create $ SM.new totm :: Vector r -- contents will be overwritten, so no need to initialize-    yout <- SV.thaw yin-    SM.unsafeWith yout (\pout ->-      SV.unsafeWith factors (\pfac ->-       withPtrArray ruinv' (\ruptr ->-        dgaussdec pout (fromIntegral totm) pfac numFacts ruptr)))-    unsafeFreeze yout--instance (Arbitrary r, Fact m, Storable r) => Arbitrary (CT' m r) where-  arbitrary = replM arbitrary-  shrink = shrinkNothing--instance (Storable r, Arbitrary (CT' m r)) => Arbitrary (CT m r) where-  arbitrary = CT <$> arbitrary--instance (Storable r, Random r, Fact m) => Random (CT' m r) where-  --{-# INLINABLE random #-}-  random = runRand $ replM (liftRand random)--  randomR = error "randomR nonsensical for CT'"--instance (Storable r, Random (CT' m r)) => Random (CT m r) where-  --{-# INLINABLE random #-}-  random = runRand $ liftM CT (liftRand random)--  randomR = error "randomR nonsensical for CT"--instance (NFData r) => NFData (CT m r) where-  rnf (CT v) = rnf v-  rnf (ZV v) = rnf v--repl :: forall m r . (Fact m, Storable r) => r -> CT' m r-repl = let n = proxy totientFact (Proxy::Proxy m)-       in coerce . SV.replicate n--replM :: forall m r mon . (Fact m, Storable r, Monad mon) -         => mon r -> mon (CT' m r)-replM = let n = proxy totientFact (Proxy::Proxy m)-        in liftM coerce . SV.replicateM n----{-# INLINE scalarPow' #-}-scalarPow' :: forall t m r v .-  (Fact m, Additive r, Storable r)-  => r -> CT' m r--- constant-term coefficient is first entry wrt powerful basis-scalarPow' = -  let n = proxy totientFact (Proxy::Proxy m)-  in \r -> CT' $ generate n (\i -> if i == 0 then r else zero)--ru, ruInv :: forall r m . -   (CRTrans r, Fact m, Storable r)-   => TaggedT m Maybe [Vector r]---{-# INLINE ru #-}-ru = do-  mval <- pureT valueFact-  wPow <- liftM fst $ crtInfoFact-  liftM (LP.map-    (\(p,e) -> do-        let pp = p^e-            pow = mval `div` pp-        generate pp (wPow . (*pow)))) $-      pureT ppsFact----{-# INLINE ruInv #-}-ruInv = do-  mval <- pureT valueFact-  wPow <- liftM fst $ crtInfoFact-  liftM (LP.map-    (\(p,e) -> do-        let pp = p^e-            pow = mval `div` pp-        generate pp (\i -> wPow $ (-i*pow)))) $-      pureT ppsFact--gCoeffsCRT, gInvCoeffsCRT :: (TElt CT r, CRTrans r, Fact m, ZeroTestable r, IntegralDomain r)-  => TaggedT m Maybe (CT' m r)-gCoeffsCRT = crt' <*> (return $ mulGPow' $ scalarPow' LP.one)--- It's necessary to call 'fromJust' here: otherwise --- sequencing functions in 'crtFuncs' relies on 'divGPow' having an--- implementation in C, which is not true for all types which have a C--- implementation of, e.g. 'crt'. In particular, 'Complex Double' has C support--- for 'crt', but not for 'divGPow'.--- This really breaks the contract of Tensor, so it's probably a bad idea.---   Someone can get the "crt" and can even pull the function "divGCRT" from Tensor,---   but it will fail when they try to apply it.--- As an implementation note if I ever do fix this: the division by rad(m) can be--- tricky for Double/Complex Doubles, so be careful! This is why we have a custom--- Complex wrapper around NP.Complex.-gInvCoeffsCRT = ($ fromJust $ divGPow' $ scalarPow' LP.one) <$> crt'---- we can't put this in Extension with the rest of the twace/embed fucntions because it needs access to --- the C backend-twaceCRT' :: forall m m' r .-             (TElt CT r, CRTrans r, m `Divides` m', ZeroTestable r, IntegralDomain r)-             => TaggedT '(m, m') Maybe (Vector r -> Vector r)-twaceCRT' = tagT $ do -- Maybe monad-  (CT' g') <- proxyT gCoeffsCRT (Proxy::Proxy m')-  (CT' gInv) <- proxyT gInvCoeffsCRT (Proxy::Proxy m)-  embed <- proxyT embedCRT' (Proxy::Proxy '(m,m'))-  indices <- pure $ proxy extIndicesCRT (Proxy::Proxy '(m,m'))-  (_, m'hatinv) <- proxyT crtInfoFact (Proxy::Proxy m')-  let phi = proxy totientFact (Proxy::Proxy m)-      phi' = proxy totientFact (Proxy::Proxy m')-      mhat = fromIntegral $ proxy valueHatFact (Proxy::Proxy m)-      hatRatioInv = m'hatinv * mhat-      reltot = phi' `div` phi-      -- tweak = mhat * g' / (m'hat * g)-      tweak = SV.map (* hatRatioInv) $ SV.zipWith (*) (embed gInv) g'-  return $ \ arr -> -- take true trace after mul-by-tweak-    let v = backpermute' indices (SV.zipWith (*) tweak arr)-    in generate phi $ \i -> foldl1' (+) $ SV.unsafeSlice (i*reltot) reltot v--------------- C-backend support--marshalFactors :: [PP] -> Vector CPP-marshalFactors = SV.fromList . LP.map (\(p,e) -> CPP (fromIntegral p) (fromIntegral e))---- http://stackoverflow.com/questions/6517387/vector-vector-foo-ptr-ptr-foo-io-a-io-a-withPtrArray :: (Storable a) => [Vector a] -> (Ptr (Ptr a) -> IO b) -> IO b-withPtrArray v f = do-  let vs = LP.map SV.unsafeToForeignPtr0 v-      ptrV = LP.map (\(fp,_) -> getPtr fp) vs-  res <- withArray ptrV f-  LP.mapM_ (\(fp,_) -> touchForeignPtr fp) vs-  return res--data CPP = CPP {p' :: !Int32, e' :: !Int16}--- stolen from http://hackage.haskell.org/packages/archive/numeric-prelude/0.4.0.3/doc/html/src/Number-Complex.html#T--- the NumericPrelude Storable instance for complex numbers-instance Storable CPP where-   sizeOf    = Store.sizeOf store-   alignment = Store.alignment store-   peek      = Store.peek store-   poke      = Store.poke store--store :: Store.Dictionary CPP-store = Store.run $-   liftA2 CPP-      (Store.element p')-      (Store.element e')--instance Show CPP where-    show (CPP p e) = "(" LP.++ (show p) LP.++ "," LP.++ (show e) LP.++ ")"--foreign import ccall unsafe "tensorLR" tensorLR ::                  Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorLInvR" tensorLInvR ::            Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorLRq" tensorLRq ::                Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Int64 -> IO ()-foreign import ccall unsafe "tensorLInvRq" tensorLInvRq ::          Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Int64 -> IO ()-foreign import ccall unsafe "tensorLDouble" tensorLDouble ::       Ptr Double -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorLInvDouble" tensorLInvDouble :: Ptr Double -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorLC" tensorLC ::       Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorLInvC" tensorLInvC :: Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16          -> IO ()--foreign import ccall unsafe "tensorGPowR" tensorGPowR ::         Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorGPowRq" tensorGPowRq ::       Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Int64 -> IO ()-foreign import ccall unsafe "tensorGDecR" tensorGDecR ::         Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorGDecRq" tensorGDecRq ::       Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Int64 -> IO ()-foreign import ccall unsafe "tensorGInvPowR" tensorGInvPowR ::   Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorGInvPowRq" tensorGInvPowRq :: Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Int64 -> IO ()-foreign import ccall unsafe "tensorGInvDecR" tensorGInvDecR ::   Ptr Int64 -> Int64 -> Ptr CPP -> Int16          -> IO ()-foreign import ccall unsafe "tensorGInvDecRq" tensorGInvDecRq :: Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Int64 -> IO ()---foreign import ccall unsafe "tensorGCRTRq" tensorGCRTRq ::       Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (ZqBasic q Int64)) -> Int64   -> IO ()---foreign import ccall unsafe "tensorGCRTC" tensorGCRTC ::         Ptr (Complex Double) ->   Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) -> IO ()---foreign import ccall unsafe "tensorGInvCRTRq" tensorGInvCRTRq :: Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (ZqBasic q Int64)) -> Int64   -> IO ()---foreign import ccall unsafe "tensorGInvCRTC" tensorGInvCRTC ::   Ptr (Complex Double) ->   Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) -> IO ()--foreign import ccall unsafe "tensorCRTRq" tensorCRTRq ::         Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (ZqBasic q Int64)) -> Int64 -> IO ()-foreign import ccall unsafe "tensorCRTC" tensorCRTC ::           Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) -> IO ()-foreign import ccall unsafe "tensorCRTInvRq" tensorCRTInvRq ::   Ptr (ZqBasic q Int64) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (ZqBasic q Int64)) -> Int64 -> Int64 -> IO ()-foreign import ccall unsafe "tensorCRTInvC" tensorCRTInvC ::     Ptr (Complex Double) -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) -> Double -> IO ()--foreign import ccall unsafe "tensorGaussianDec" tensorGaussianDec :: Ptr Double -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex Double)) ->  IO ()--foreign import ccall unsafe "mulRq" mulRq :: Ptr (ZqBasic q Int64) -> Ptr (ZqBasic q Int64) -> Int64 -> Int64 -> IO ()-foreign import ccall unsafe "mulC" mulC :: Ptr (Complex Double) -> Ptr (Complex Double) -> Int64 -> IO ()--foreign import ccall unsafe "addRq" addRq :: Ptr (ZqBasic q Int64) -> Ptr (ZqBasic q Int64) -> Int64 -> Int64 -> IO ()-foreign import ccall unsafe "addR" addR :: Ptr Int64 -> Ptr Int64 -> Int64 -> IO ()-foreign import ccall unsafe "addC" addC :: Ptr (Complex Double) -> Ptr (Complex Double) -> Int64 -> IO ()-foreign import ccall unsafe "addD" addD :: Ptr Double -> Ptr Double -> Int64 -> IO ()---- | Class to safely match Haskell types with the appropriate C function.-class Dispatch r where-  dcrt :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr r) -> IO ()-  dcrtinv :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr r) -> r -> IO ()-  dl :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()-  dlinv :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()-  dmulgpow :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()-  dmulgdec :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()-  dginvpow :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()-  dginvdec :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> IO ()-  dadd :: Ptr r -> Ptr r -> Int64 -> IO ()-  dmul :: Ptr r -> Ptr r -> Int64 -> IO ()-  dgcrt :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr r) -> IO ()-  dginvcrt :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr r) -> IO ()-  dgaussdec :: Ptr r -> Int64 -> Ptr CPP -> Int16 -> Ptr (Ptr (Complex r)) -> IO ()--instance (Reflects q Int64) => Dispatch (ZqBasic q Int64) where-  dcrt pout totm pfac numFacts ruptr = -    let q = proxy value (Proxy::Proxy q)-    in tensorCRTRq pout totm pfac numFacts ruptr q-  dcrtinv pout totm pfac numFacts ruptr minv =-    let q = proxy value (Proxy::Proxy q)-    --EAC: GHC doesn't like it if I change the type of minv to ZqBasic in the-    -- signature of tensorCRTInvRq, and the constructor of ZqBasic isn't exposed-    -- so using unsafeCoerce for now-    in tensorCRTInvRq pout totm pfac numFacts ruptr (unsafeCoerce minv) q-  dl pout totm pfac numFacts =-    let q = proxy value (Proxy::Proxy q)-    in tensorLRq pout totm pfac numFacts q-  dlinv pout totm pfac numFacts =-    let q = proxy value (Proxy::Proxy q)-    in tensorLInvRq pout totm pfac numFacts q-  dmulgpow pout totm pfac numFacts =-    let q = proxy value (Proxy::Proxy q)-    in tensorGPowRq pout totm pfac numFacts q-  dmulgdec pout totm pfac numFacts =-    let q = proxy value (Proxy::Proxy q)-    in tensorGDecRq pout totm pfac numFacts q-  dginvpow pout totm pfac numFacts =-    let q = proxy value (Proxy::Proxy q)-    in tensorGInvPowRq pout totm pfac numFacts q-  dginvdec pout totm pfac numFacts =-    let q = proxy value (Proxy::Proxy q)-    in tensorGInvDecRq pout totm pfac numFacts q-  dadd aout bout totm = -    let q = proxy value (Proxy::Proxy q)-    in addRq aout bout totm q-  dmul aout bout totm =-    let q = proxy value (Proxy::Proxy q)-    in mulRq aout bout totm q-  dgcrt pout totm pfac numFacts gcoeffs' = error "dgcrt zq"-    --let q = proxy value (Proxy::Proxy q)-    --in tensorGCRTRq pout totm pfac numFacts gcoeffs' q-  dginvcrt pout totm pfac numFacts gcoeffs' = error "dginvcrt zq"-    --let q = proxy value (Proxy::Proxy q)-    --in tensorGInvCRTRq pout totm pfac numFacts gcoeffs' q-  dgaussdec = error "cannot call CT gaussianDec on type ZqBasic"--instance Dispatch (Complex Double) where-  dcrt = tensorCRTC-  dcrtinv pout totm pfac numFacts ruptr minv = -    tensorCRTInvC pout totm pfac numFacts ruptr (real minv)-  dl = tensorLC-  dlinv = tensorLInvC-  dmulgpow = error "cannot call CT mulGPow on type Complex Double"-  dmulgdec = error "cannot call CT mulGDec on type Complex Double"-  dginvpow = error "cannot call CT divGPow on type Complex Double"-  dginvdec = error "cannot call CT divGDec on type Complex Double"-  dadd = addC-  dmul = mulC-  dgcrt = error "tensorGCRTC"-  dginvcrt = error "tensorGInvCRTC"-  dgaussdec = error "cannot call CT gaussianDec on type Comple Double"--instance Dispatch Double where-  dcrt = error "cannot call CT Crt on type Double"-  dcrtinv = error "cannot call CT CrtInv on type Double"-  dl = tensorLDouble-  dlinv = tensorLInvDouble-  dmulgpow = error "cannot call CT mulGPow on type Double"-  dmulgdec = error "cannot call CT mulGDec on type Double"-  dginvpow = error "cannot call CT divGPow on type Double"-  dginvdec = error "cannot call CT divGDec on type Double"-  dadd = addD-  dmul = error "cannot call CT (*) on type Double"-  dgcrt = error "cannot call CT mulGCRT on type Double"-  dginvcrt = error "cannot call CT divGCRT on type Double"-  dgaussdec = tensorGaussianDec--instance Dispatch Int64 where-  dcrt = error "cannot call CT Crt on type Int64"-  dcrtinv = error "cannot call CT CrtInv on type Int64"-  dl = tensorLR-  dlinv = tensorLInvR-  dmulgpow = tensorGPowR-  dmulgdec = tensorGDecR-  dginvpow = tensorGInvPowR-  dginvdec = tensorGInvDecR-  dadd = addR-  dmul = error "cannot call CT (*) on type Int64"-  dgcrt = error "cannot call CT mulGCRT on type Int64"-  dginvcrt = error "cannot call CT divGCRT on type Int64"-  dgaussdec = error "cannot call CT gaussianDec on type Int64"
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/Extension.hs
@@ -1,122 +0,0 @@-{-# LANGUAGE ConstraintKinds, FlexibleContexts, MultiParamTypeClasses,-             NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables,-             TypeFamilies, TypeOperators, DataKinds #-}---- | 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 <a,b,c,d> <0,3,2,3,1,0> = <a,d,c,d,b,a>-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 value (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
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/basic.c
@@ -1,162 +0,0 @@-#include "tensorTypes.h"-#ifdef CINTRIN-#include <immintrin.h>-#endif--#ifdef STATS-int mulCtr = 0;-struct timespec mulTime = {0,0};--int addCtr = 0;-struct timespec addTime = {0,0};-#endif--//a = zipWith (*) a b-void mulRq (hInt_t* a, hInt_t* b, hDim_t totm, hInt_t q) {-#ifdef STATS-    mulCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-    for(int i = 0; i < totm; i++) {-        a[i] = (a[i]*b[i])%q;-    }-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    mulTime = tsAdd(mulTime, tsSubtract(t1,s1));-#endif-}--void mulMq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q) {-#ifdef STATS-    mulCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-    hInt_t mask = (1<<logr)-1; // R-1--    for(int i = 0; i < totm; i++) {-        hInt_t x = a[i]*b[i];-        hInt_t s = k*(x & mask);-        hInt_t m = s & mask;-        a[i] = (x+m*q)>>logr;-    }--#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    mulTime = tsAdd(mulTime, tsSubtract(t1,s1));-#endif-}--void mulC (complex_t* a, complex_t* b, hDim_t totm) {-#ifdef STATS-    mulCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-    for(int i = 0; i < totm; i++)-    {-        CMPLX_IMUL(a[i],b[i]);-    }-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    mulTime = tsAdd(mulTime, tsSubtract(t1,s1));-#endif-}--//a = zipWith (+) a b-void addRq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hInt_t q) {-#ifdef STATS-    addCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-#ifdef CINTRIN-    __m128i qs = _mm_set1_epi64x(q);-    for(int i = 0; i < totm; i+=2) {-        __m128i xs = _mm_load_si128((const __m128i*)(a+i));-        __m128i ys = _mm_load_si128((const __m128i*)(b+i));-        __m128i zs = _mm_add_epi64(xs,ys);-        zs = _mm_rem_epi64(zs,qs);-        _mm_store_si128((__m128i*)(a+i),zs);-    }-#else-    for(int i = 0; i < totm; i++) {-        hInt_t temp = a[i]+b[i];-        if (temp >= q) a[i]=temp-q;-        else a[i] = temp;-    }-#endif-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    addTime = tsAdd(addTime, tsSubtract(t1,s1));-#endif-}--void addMq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q) {-#ifdef STATS-    addCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-    hInt_t twoq = q<<1;-    for(int i = 0; i < totm; i++) {-        hInt_t temp = (a[i]+b[i]);-        if (temp >= twoq) a[i]=temp-twoq;-        else a[i] = temp;-    }--#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    addTime = tsAdd(addTime, tsSubtract(t1,s1));-#endif-}--//a = zipWith (+) a b-void addR (hInt_t* a, hInt_t* b, hDim_t totm) {-#ifdef STATS-    addCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-    for(int i = 0; i < totm; i++)    {-        a[i] += b[i];-    }-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    addTime = tsAdd(addTime, tsSubtract(t1,s1));-#endif-}--void addC (complex_t* a, complex_t* b, hDim_t totm) {-#ifdef STATS-    addCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-    for(int i = 0; i < totm; i++)-    {-        CMPLX_IADD(a[i],b[i]);-    }-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    addTime = tsAdd(addTime, tsSubtract(t1,s1));-#endif-}--void addD (double* a, double* b, hDim_t totm) {-#ifdef STATS-    addCtr++;-    struct timespec s1,t1;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-    for(int i = 0; i < totm; i++)-    {-        a[i]+=b[i];-    }-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    addTime = tsAdd(addTime, tsSubtract(t1,s1));-#endif-}-
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/crt.c
@@ -1,1305 +0,0 @@-#include "tensorTypes.h"-#include <time.h>-#include <stdlib.h>--// there should be a special cases that do NOT require temp space to be allocated for all primes *smaller* than DFTP_GENERIC_SIZE-#define DFTP_GENERIC_SIZE 11--#ifdef STATS-int crtRqCtr = 0;-int crtInvRqCtr = 0;-int crtCCtr = 0;-int crtInvCCtr = 0;--struct timespec crttime1 = {0,0};-struct timespec crttime2 = {0,0};-struct timespec crttime3 = {0,0};-struct timespec crttime4 = {0,0};--struct timespec crtInvRqTime = {0,0};-struct timespec crtCTime = {0,0};-struct timespec crtInvCTime = {0,0};-#endif--hDim_t bitrev (PrimeExponent pe, hDim_t j) {-    hShort_t e;-    hDim_t p = pe.prime;-    hDim_t tempj = j;-    hDim_t acc = 0;--    for(e = pe.exponent-1; e >= 0; e--) {-        div_t qr = div(tempj,p);-        acc += qr.rem * ipow(p,e);-        tempj = qr.quot;-    }-    return acc;-}--void crtTwiddleRq (hInt_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, hInt_t* ru, hInt_t q)-{-    hDim_t p = pe.prime;-    hShort_t e = pe.exponent;-    -#ifdef DEBUG_MODE-    ASSERT(e != 0);-#endif-    pe.exponent -= 1; // used for an argument to bitrev-    -    if(p == 2)-    {-        hDim_t mprime = 1<<(e-1);-        hDim_t blockDim = rts*mprime; // size of block in block diagonal tensor matrix--        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0-        {-            hDim_t temp2 = i0*rts;-            hInt_t twid = ru[bitrev(pe, i0)];--            for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)-            {-                hDim_t temp3 = blockIdx*blockDim + temp2;-                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                {-                    hDim_t idx = temp3 + modOffset;-                    y[idx] = (y[idx]*twid) % q;-                }-            }-        }-    }-    else // This loop is faster, probably due to the division in the loop above.-    // cilk also slows it down-    {-        hDim_t mprime = ipow(p,e-1);-        hDim_t blockDim = rts*(p-1)*mprime; // size of block in block diagonal tensor matrix-        -        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0-        {-            hDim_t temp1 = i0*(p-1);-            for(hDim_t i1 = 0; i1 < (p-1); i1++) // loops over i%(p-1) for i = 0..(m'-1)-            {        -                hDim_t temp2 = (temp1+i1)*rts;-                hInt_t twid = ru[bitrev(pe, i0)*(i1+1)];--                for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)-                {-                    hDim_t temp3 = blockIdx*blockDim + temp2;-                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                    {-                        hDim_t idx = temp3 + modOffset;-                        y[idx] = (y[idx]*twid) % q;-                    }-                }-            }-        }-    }-}--// dim is power of p-void dftptwidRq (hInt_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t dim, hDim_t rustride, hInt_t* ru, hInt_t q)-{-    hDim_t idx;-    hDim_t p = pe.prime;--    pe.exponent -= 1; // used for an argument to bitrev--    if(p == 2) {-        hDim_t mprime = dim>>1; // divides evenly-        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset-        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0-        {-            hDim_t temp3 = rts*(i0*p+1);-            hInt_t twid = ru[bitrev(pe,i0)*rustride];--            for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-            {-                hDim_t temp2 = blockOffset*temp1 + temp3;-                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                {-                    idx = temp2 + modOffset;-                    y[idx] = (y[idx]*twid) % q;-                }-            }-        }-    }-    else-    {-        hDim_t mprime = dim/p; // divides evenly-        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset-        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0-        {-            for(hDim_t i1 = 1; i1 < p; i1++) // loops over i%p for i = 0..(dim-1), but we skip i1=0-            {-                hDim_t temp3 = rts*(i0*p+i1);-                hInt_t twid = ru[bitrev(pe,i0)*i1*rustride];--                for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-                {-                    hDim_t temp2 = blockOffset*temp1 + temp3;-                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                    {-                        idx = temp2 + modOffset;-                        y[idx] = (y[idx]*twid) % q;-                    }-                }-            }-        }-    }-}--//implied length of ru is rustride*p-//implied length of tempSpace is p, if p is not a special case-// temp is allowed to be NULL if p < DFTP_GENERIC_SIZE-void dftpRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, hInt_t* ru, hInt_t* tempSpace, hInt_t q)-{-    hDim_t tensorOffset;-    -    if(p == 2)-    {-        hDim_t temp1 = rts<<1;--        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hInt_t u = y[tensorOffset];-                hInt_t t = y[tensorOffset+rts];-                y[tensorOffset] = (u + t) % q;-                y[tensorOffset+rts] = (u - t) % q;-            }-        }-    }-    else if(p == 3)-    {-        hInt_t ru1 = ru[rustride];-        hInt_t ru2 = ru[rustride<<1];-        hDim_t temp1 = rts*3;--        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hInt_t y1, y2, y3;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                //q is <32 bits, so we can do 3 additions without overflow-                y[tensorOffset]          = (y1 + y2 + y3) % q;-                y[tensorOffset+rts]      = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q)) % q;-                y[tensorOffset+(rts<<1)] = (y1 + ((ru2*y2) % q) + ((ru1*y3) % q)) % q;-            }   -        }--    }-    else if(p == 5)-    {-        hDim_t temp1 = rts*5;-        hInt_t ru1 = ru[rustride];-        hInt_t ru2 = ru[rustride<<1];-        hInt_t ru3 = ru[rustride*3];-        hInt_t ru4 = ru[rustride<<2];--        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hInt_t y1, y2, y3, y4, y5;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];-                y5 = y[tensorOffset+(rts<<2)];-                y[tensorOffset]          = (y1 + y2 + y3 + y4 + y5) % q;-                y[tensorOffset+rts]      = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q) + ((ru4*y5) % q)) % q;-                y[tensorOffset+(rts<<1)] = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru1*y4) % q) + ((ru3*y5) % q)) % q;-                y[tensorOffset+rts*3]    = (y1 + ((ru3*y2) % q) + ((ru1*y3) % q) + ((ru4*y4) % q) + ((ru2*y5) % q)) % q;-                y[tensorOffset+(rts<<2)] = (y1 + ((ru4*y2) % q) + ((ru3*y3) % q) + ((ru2*y4) % q) + ((ru1*y5) % q)) % q;-            }-        }-    }-    else if(p == 7)-    {-        hDim_t temp1 = rts*7;-        hInt_t ru1 = ru[rustride];-        hInt_t ru2 = ru[rustride<<1];-        hInt_t ru3 = ru[rustride*3];-        hInt_t ru4 = ru[rustride<<2];-        hInt_t ru5 = ru[rustride*5];-        hInt_t ru6 = ru[rustride*6];--        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hInt_t y1, y2, y3, y4, y5, y6, y7;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];-                y5 = y[tensorOffset+(rts<<2)];-                y6 = y[tensorOffset+rts*5];-                y7 = y[tensorOffset+rts*6];-                y[tensorOffset]          = (y1 +     y2 +     y3 +     y4 +     y5 +     y6 +     y7) % q;-                y[tensorOffset+rts]      = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q) + ((ru4*y5) % q) + ((ru5*y6) % q) + ((ru6*y7) % q)) % q;-                y[tensorOffset+(rts<<1)] = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru6*y4) % q) + ((ru1*y5) % q) + ((ru3*y6) % q) + ((ru5*y7) % q)) % q;-                y[tensorOffset+rts*3]    = (y1 + ((ru3*y2) % q) + ((ru6*y3) % q) + ((ru2*y4) % q) + ((ru5*y5) % q) + ((ru1*y6) % q) + ((ru4*y7) % q)) % q;-                y[tensorOffset+(rts<<2)] = (y1 + ((ru4*y2) % q) + ((ru1*y3) % q) + ((ru5*y4) % q) + ((ru2*y5) % q) + ((ru6*y6) % q) + ((ru3*y7) % q)) % q;-                y[tensorOffset+rts*5]    = (y1 + ((ru5*y2) % q) + ((ru3*y3) % q) + ((ru1*y4) % q) + ((ru6*y5) % q) + ((ru4*y6) % q) + ((ru2*y7) % q)) % q;-                y[tensorOffset+rts*6]    = (y1 + ((ru6*y2) % q) + ((ru5*y3) % q) + ((ru4*y4) % q) + ((ru3*y5) % q) + ((ru2*y6) % q) + ((ru1*y7) % q)) % q;-            }   -        }-    }-    else-    {-        hDim_t temp1 = rts*p;-        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;                -                for(hDim_t row = 0; row < p; row++)-                {-                    hInt_t acc = 0;-                    //p is small (<< 30 bits), so we can do p additions of mod-q values without overflow-                    for(hDim_t col = 0; col < p; col++)-                    {-                        acc += ((y[tensorOffset+col*rts]*ru[((col*row) % p)*rustride])%q);-                    }-                    tempSpace[row] = acc % q;-                }-                -                for(hDim_t row = 0; row < p; row++)-                {-                    y[tensorOffset+rts*row] = tempSpace[row];-                }-            }-        }-    }-}--void crtpRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, hInt_t* ru, hInt_t q)-{-    hDim_t tensorOffset;-    if(p == 2)-    {-        return;-    }-    else if(p == 3)-    {-        hDim_t temp1 = rts*2;-        hInt_t ru1 = ru[rustride];-        hInt_t ru2 = ru[rustride<<1];--        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hInt_t y1, y2;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y[tensorOffset]     = (y1 + ((ru1*y2)%q)) % q;-                y[tensorOffset+rts] = (y1 + ((ru2*y2)%q)) % q;-            }   -        }-    }-    else if(p == 5)-    {-        hDim_t temp1 = rts*4;-        hInt_t ru1 = ru[rustride];-        hInt_t ru2 = ru[rustride<<1];-        hInt_t ru3 = ru[rustride*3];-        hInt_t ru4 = ru[rustride<<2];--        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hInt_t y1, y2, y3, y4;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];--                y[tensorOffset]          = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q)) % q;-                y[tensorOffset+rts]      = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru1*y4) % q)) % q;-                y[tensorOffset+(rts<<1)] = (y1 + ((ru3*y2) % q) + ((ru1*y3) % q) + ((ru4*y4) % q)) % q;-                y[tensorOffset+rts*3]    = (y1 + ((ru4*y2) % q) + ((ru3*y3) % q) + ((ru2*y4) % q)) % q;-            }   -        }-    }-    else if(p == 7)-    {-        hDim_t temp1 = rts*6;-        hInt_t ru1 = ru[rustride];-        hInt_t ru2 = ru[rustride<<1];-        hInt_t ru3 = ru[rustride*3];-        hInt_t ru4 = ru[rustride<<2];-        hInt_t ru5 = ru[rustride*5];-        hInt_t ru6 = ru[rustride*6];--        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hInt_t y1, y2, y3, y4, y5, y6;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];-                y5 = y[tensorOffset+(rts<<2)];-                y6 = y[tensorOffset+rts*5];-                y[tensorOffset]          = (y1 + ((ru1*y2) % q) + ((ru2*y3) % q) + ((ru3*y4) % q) + ((ru4*y5) % q) + ((ru5*y6) % q)) % q;-                y[tensorOffset+rts]      = (y1 + ((ru2*y2) % q) + ((ru4*y3) % q) + ((ru6*y4) % q) + ((ru1*y5) % q) + ((ru3*y6) % q)) % q;-                y[tensorOffset+(rts<<1)] = (y1 + ((ru3*y2) % q) + ((ru6*y3) % q) + ((ru2*y4) % q) + ((ru5*y5) % q) + ((ru1*y6) % q)) % q;-                y[tensorOffset+rts*3]    = (y1 + ((ru4*y2) % q) + ((ru1*y3) % q) + ((ru5*y4) % q) + ((ru2*y5) % q) + ((ru6*y6) % q)) % q;-                y[tensorOffset+(rts<<2)] = (y1 + ((ru5*y2) % q) + ((ru3*y3) % q) + ((ru1*y4) % q) + ((ru6*y5) % q) + ((ru4*y6) % q)) % q;-                y[tensorOffset+rts*5]    = (y1 + ((ru6*y2) % q) + ((ru5*y3) % q) + ((ru4*y4) % q) + ((ru3*y5) % q) + ((ru2*y6) % q)) % q;-            }-        }-    }-    else-    {-        hInt_t* tempSpace = (hInt_t*)malloc((p-1)*sizeof(hInt_t));-        hDim_t temp1 = rts*(p-1);-        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                -                for(hDim_t row = 1; row < p; row++)-                {-                    hInt_t acc = 0;-                    for(hDim_t col = 0; col < p-1; col++)-                    {-                        acc += ((y[tensorOffset+col*rts]*ru[((col*row) % p)*rustride]) % q);-                    }-                    tempSpace[row-1] = acc % q;-                }-                -                for(hDim_t row = 0; row < p-1; row++)-                {-                    y[tensorOffset+rts*row] = tempSpace[row];-                }-            }-        }-        free(tempSpace);-    }-}--//takes inverse rus-void crtpinvRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, hInt_t* ruinv, hInt_t q)-{-    if(p ==2)-    {-        // need this case so that we can divide overall by mhat^(-1)-        return;-    }-    else-    {-        hDim_t tensorOffset,i;-        hInt_t* tempSpace = (hInt_t*)malloc((p-1)*sizeof(hInt_t));-        hDim_t temp1 = rts*(p-1);-        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                -                for(i = 0; i < p-1; i++)-                {-                    hInt_t sum = 0;-                    int j;-                    for(j = 0; j < p-1; j++)-                    {-                        int ruIdx = ((j+1)*i) % p;-                        sum += ((y[tensorOffset+j*rts] * ruinv[ruIdx*rustride]) % q);-                    }-                    tempSpace[i] = sum % q;-                }--                hInt_t shift = 0;-                for(i = 0; i < p-1; i++)-                {-                    // we were given the inverse rus, so we need to negate the indices-                    shift += ((y[tensorOffset+i*rts] * ruinv[rustride*(p-(i+1))]) % q);-                }--                for(i = 0; i < p-1; i++)-                {-                    y[tensorOffset+i*rts] = (tempSpace[i] - shift) % q; -                }-            }-        }-    }-}--void ppDFTRq (hInt_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t rustride, hInt_t* ru, hInt_t q)-{-    hDim_t p = pe.prime;-    hShort_t e = pe.exponent;-    -    if(e == 0)-    {-        return;-    }-    -    hDim_t primeRuStride = rustride*ipow(p,e-1);-    hInt_t* temp = 0;-    if(p >= DFTP_GENERIC_SIZE)-    {-        temp = (hInt_t*)malloc(p*sizeof(hInt_t));-    }-    hShort_t i;-    -    hDim_t ltsScale = ipow(p,e-1);-    hDim_t rtsScale = 1;-    hDim_t twidRuStride = rustride;-    for(i = 0; i < e; i++)-    {-        hDim_t rtsDim = rts*rtsScale;-        dftpRq (y, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp, q);-        dftptwidRq (y, lts, rtsDim, pe, ltsScale*p, twidRuStride, ru, q);-        -        ltsScale /= p;-        rtsScale *= p;-        twidRuStride *= p;-        pe.exponent -= 1;-    }-    -    if(p >= DFTP_GENERIC_SIZE)-    {-        free(temp);-    }-}--void ppDFTInvRq (hInt_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t rustride, hInt_t* ru, hInt_t q)-{-    hDim_t p = pe.prime;-    hShort_t e = pe.exponent;-    -    if(e == 0)-    {-        return;-    }-    hDim_t primeRuStride = rustride*ipow(p,e-1);-    hInt_t* temp = 0;-    if(p >= DFTP_GENERIC_SIZE)-    {-        temp = (hInt_t*)malloc(p*sizeof(hInt_t));-    }-    hShort_t i;-    -    hDim_t ltsScale = 1;-    hDim_t rtsScale = ipow(p,e-1);-    hDim_t twidRuStride = primeRuStride;-    pe.exponent = 1;-    for(i = 0; i < e; i++)-    {-        hDim_t rtsDim = rts*rtsScale;-        hDim_t ltsScaleP = ltsScale*p;-        dftptwidRq (y, lts, rtsDim, pe, ltsScaleP, twidRuStride, ru, q);-        dftpRq (y, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp, q);-        -        ltsScale = ltsScaleP;-        rtsScale /= p;-        twidRuStride /= p;-        pe.exponent += 1;-    }-    -    if(p >= DFTP_GENERIC_SIZE)-    {-        free(temp);-    }-}--void ppcrtRq (void* y, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t q)-{-    hDim_t p = pe.prime;-    hDim_t e = pe.exponent;-#ifdef DEBUG_MODE-    ASSERT(e != 0);-#endif-    hDim_t mprime = ipow(p,e-1);-    -#ifdef DEBUG_MODE-    printf("lts is %" PRId32 "\trts is %" PRId32 "\n", lts, rts);-    printf("rus for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);-    hDim_t i;-    for(i = 0; i < ipow(p,e); i++) {-        printf("%" PRId64 ",", ((hInt_t*)ru)[i]);-    }-    printf("]\n");-#endif-    -    crtpRq ((hInt_t*)y, lts*mprime, rts, p, mprime, (hInt_t*)ru, q);-    crtTwiddleRq ((hInt_t*)y, lts, rts, pe, (hInt_t*)ru, q);-    pe.exponent -= 1;-    ppDFTRq ((hInt_t*)y, lts, rts*(p-1), pe, p, (hInt_t*)ru, q);-}--void ppcrtinvRq (void* y, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t q)-{-    hDim_t p = pe.prime;-    hDim_t e = pe.exponent;-#ifdef DEBUG_MODE-    ASSERT(e != 0);-#endif-    hDim_t mprime = ipow(p,e-1);-#ifdef DEBUG_MODE-    printf("lts is %" PRId32 "\trts is %" PRId32 "\n", lts, rts);-    printf("rus for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);-    hDim_t i;-    for(i = 0; i < ipow(p,e); i++) {-        printf("%" PRId64 ",", ((hInt_t*)ru)[i]);-    }-    printf("]\n");-#endif-    pe.exponent -= 1;-    ppDFTInvRq ((hInt_t*)y, lts, rts*(p-1), pe, p, (hInt_t*)ru, q);-    pe.exponent += 1;-    crtTwiddleRq ((hInt_t*)y, lts, rts, pe, (hInt_t*)ru, q);-    crtpinvRq ((hInt_t*)y, lts*mprime, rts, p, mprime, (hInt_t*)ru, q);-}--// EAC: Somebody who knows C/C++ should find a better way to handle pointers-to-pointers in a generic way-void tensorCRTRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** ru, hInt_t q)-{-    -    hDim_t i;-#ifdef STATS-    struct timespec s1,s2,s3,s4,t1,t2,t3,t4;--    crtRqCtr++;--    clock_gettime(CLOCK_REALTIME, &s1);-    clock_gettime(CLOCK_MONOTONIC, &s2);-    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &s3);-    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &s4);-#endif-#ifdef DEBUG_MODE-    printf("\n\nEntered tensorCRTRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\tq=%" PRId64 "\n[", totm, sizeOfPE, q);--    for(i = 0; i < totm; i++) {-        printf("%" PRId64 ",", y[i]);-    }-    printf("]\n[");-    for(i = 0; i < sizeOfPE; i++) {-        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);-    }-    printf("]\n");-#endif-    void** rus = (void**)malloc(sizeOfPE*sizeof(void*));-    -    for(i = 0; i < sizeOfPE; i++)-    {-        rus[i] = (void*) (ru[i]);-    }-	tensorFuserCRT (y, ppcrtRq, totm, peArr, sizeOfPE, rus, q);-	-	for(hDim_t j = 0; j < totm; j++)-	{-	    if(y[j]<0)-	    {-	        y[j]+=q;-	    }-#ifdef DEBUG_MODE-	    if(y[j]<0)-	    {-	        printf("TENSOR CRT^T INV\n");-	    }-#endif-	}--	free(rus);-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    clock_gettime(CLOCK_MONOTONIC, &t2);-    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t3);-    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t4);--    crttime1 = tsAdd(crttime1, tsSubtract(t1,s1));-    crttime2 = tsAdd(crttime2, tsSubtract(t2,s2));-    crttime3 = tsAdd(crttime3, tsSubtract(t3,s3));-    crttime4 = tsAdd(crttime4, tsSubtract(t4,s4));-#endif-}--//takes inverse rus-void tensorCRTInvRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** ruinv, hInt_t mhatInv, hInt_t q)-{-	hDim_t i;-#ifdef STATS-    struct timespec s1,t1;-    crtInvRqCtr++;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-#ifdef DEBUG_MODE-    printf("\n\nEntered tensorCRTInvRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\tminv=%" PRId64 "\tq=%" PRId64 "\n[", totm, sizeOfPE, mhatInv, q);-    for(i = 0; i < totm; i++) {-        printf("%" PRId64 ",", y[i]);-    }-    printf("]\n[");-    for(i = 0; i < sizeOfPE; i++) {-        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);-    }-    printf("]\n");-#endif--	void** rus = (void**)malloc(sizeOfPE*sizeof(void*));-    for(i = 0; i < sizeOfPE; i++)-    {-        rus[i] = (void*) (ruinv[i]);-    }-	-	tensorFuserCRT (y, ppcrtinvRq, totm, peArr, sizeOfPE, rus, q);--	for (hDim_t j = 0; j < totm; j++)-	{-	    y[j] = (y[j]*mhatInv)%q;-	    if(y[j] < 0)-	    {-	        y[j] +=q;-	    }-#ifdef DEBUG_MODE-	    if(y[j]<0)-	    {-	        printf("TENSOR CRT INV\n");-	    }-#endif-	}--	free(rus);-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    crtInvRqTime = tsAdd(crtInvRqTime, tsSubtract(t1,s1));-#endif-}---------------void crtTwiddleC (complex_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, complex_t* ru)-{-    hDim_t idx;-    hDim_t p = pe.prime;-    hShort_t e = pe.exponent;-    -#ifdef DEBUG_MODE-    ASSERT(e != 0);-#endif--    pe.exponent -= 1; // used for an argument to bitrev-    -    if(p == 2)-    {-        hDim_t mprime = 1<<(e-1);-        hDim_t blockDim = rts*mprime; // size of block in block diagonal tensor matrix--        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0-        {-            hDim_t temp2 = i0*rts;-            complex_t twid = ru[bitrev(pe,i0)];--            for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)-            {-                hDim_t temp3 = blockIdx*blockDim + temp2;-                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                {-                    idx = temp3 + modOffset;-                    CMPLX_IMUL(y[idx],twid);-                }-            }-        }-    }-    else-    {-        hDim_t mprime = ipow(p,e-1);-        hDim_t blockDim = rts*(p-1)*mprime; // size of block in block diagonal tensor matrix--        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/(p-1) for i = 0..(m'-1), we can skip i0 = 0-        {-            hDim_t temp1 = i0*(p-1);-            for(hDim_t i1 = 0; i1 < (p-1); i1++) // loops over i%(p-1) for i = 0..(m'-1)-            {        -                hDim_t temp2 = (temp1+i1)*rts;-                complex_t twid = ru[bitrev(pe,i0)*(i1+1)];--                for(hDim_t blockIdx = 0; blockIdx < lts; blockIdx++)-                {-                    hDim_t temp3 = blockIdx*blockDim + temp2;-                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                    {-                        idx = temp3 + modOffset;-                        CMPLX_IMUL(y[idx],twid);-                    }-                }-            }-        }-    }-}-    -// dim is power of p-void dftptwidC (complex_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t dim, hDim_t rustride, complex_t* ru)-{-    hDim_t idx;-    hDim_t p = pe.prime;-    pe.exponent -= 1; // used for an argument to bitrev-    -    if(p == 2)-    {-        hDim_t mprime = dim>>1; // divides evenly-        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset-        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0-        {-            hDim_t temp3 = rts*(i0*p+1);-            complex_t twid = ru[bitrev(pe,i0)*rustride];--            for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-            {-                hDim_t temp2 = blockOffset*temp1 + temp3;-                for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                {-                    idx = temp2 + modOffset;-                    CMPLX_IMUL(y[idx],twid);-                }-            }-        }-    }-    else-    {-        hDim_t mprime = dim/p; // divides evenly-        hDim_t temp1 = rts*dim; // for use in computing [modified] tensorOffset-        for(hDim_t i0 = 1; i0 < mprime; i0++) // loops over i/p for i = 0..(dim-1), but we skip i0=0-        {-            for(hDim_t i1 = 1; i1 < p; i1++) // loops over i%p for i = 0..(dim-1), but we skip i1=0-            {-                hDim_t temp3 = rts*(i0*p+i1);-                complex_t twid = ru[bitrev(pe,i0)*i1*rustride];--                for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-                {-                    hDim_t temp2 = blockOffset*temp1 + temp3;-                    for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-                    {-                        idx = temp2 + modOffset;-                        CMPLX_IMUL(y[idx],twid);-                    }-                }-            }-        }-    }-}--//implied length of ru is rustride*p-//implied length of tempSpace is p, if p is not a special case-void dftpC (complex_t* y, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ru, complex_t* tempSpace)-{-    hDim_t blockOffset, modOffset, tensorOffset;-    -    if(p == 2)-    {-        hDim_t temp1 = rts<<1;-        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                complex_t u = y[tensorOffset];-                complex_t t = y[tensorOffset+rts];-                y[tensorOffset] = CMPLX_ADD(u,t);-                y[tensorOffset+rts] = CMPLX_SUB(u,t);-            }-        }-    }-    else if(p == 3)-    {-        hDim_t temp1 = rts*3;-        complex_t ru1 = ru[rustride];-        complex_t ru2 = ru[rustride<<1];--        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                complex_t y1, y2, y3;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y[tensorOffset]          = CMPLX_ADD3(y1,               y2,                y3);-                y[tensorOffset+rts]      = CMPLX_ADD3(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3));-                y[tensorOffset+(rts<<1)] = CMPLX_ADD3(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru1,y3));-            }   -        }-    }-    else if(p == 5)-    {-        hDim_t temp1 = rts*5;-        complex_t ru1 = ru[rustride];-        complex_t ru2 = ru[rustride<<1];-        complex_t ru3 = ru[rustride*3];-        complex_t ru4 = ru[rustride<<2];--        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                complex_t y1, y2, y3, y4, y5;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];-                y5 = y[tensorOffset+(rts<<2)];-                y[tensorOffset]          = CMPLX_ADD5(y1,               y2,                y3,                y4,                y5);-                y[tensorOffset+rts]      = CMPLX_ADD5(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4), CMPLX_MUL(ru4,y5));-                y[tensorOffset+(rts<<1)] = CMPLX_ADD5(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru1,y4), CMPLX_MUL(ru3,y5));-                y[tensorOffset+rts*3]    = CMPLX_ADD5(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru4,y4), CMPLX_MUL(ru2,y5));-                y[tensorOffset+(rts<<2)] = CMPLX_ADD5(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru2,y4), CMPLX_MUL(ru1,y5));-            }   -        }-    }-    else if(p == 7)-    {-        hDim_t temp1 = rts*7;-        complex_t ru1 = ru[rustride];-        complex_t ru2 = ru[rustride<<1];-        complex_t ru3 = ru[rustride*3];-        complex_t ru4 = ru[rustride<<2];-        complex_t ru5 = ru[rustride*5];-        complex_t ru6 = ru[rustride*6];--        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                complex_t y1, y2, y3, y4, y5, y6, y7;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];-                y5 = y[tensorOffset+(rts<<2)];-                y6 = y[tensorOffset+rts*5];-                y7 = y[tensorOffset+rts*6];-                y[tensorOffset]          = CMPLX_ADD7(y1,               y2,                y3,                y4,                y5,                y6,                y7);-                y[tensorOffset+rts]      = CMPLX_ADD7(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4), CMPLX_MUL(ru4,y5), CMPLX_MUL(ru5,y6), CMPLX_MUL(ru6,y7));-                y[tensorOffset+(rts<<1)] = CMPLX_ADD7(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru6,y4), CMPLX_MUL(ru1,y5), CMPLX_MUL(ru3,y6), CMPLX_MUL(ru5,y7));-                y[tensorOffset+rts*3]    = CMPLX_ADD7(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru6,y3), CMPLX_MUL(ru2,y4), CMPLX_MUL(ru5,y5), CMPLX_MUL(ru1,y6), CMPLX_MUL(ru4,y7));-                y[tensorOffset+(rts<<2)] = CMPLX_ADD7(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru5,y4), CMPLX_MUL(ru2,y5), CMPLX_MUL(ru6,y6), CMPLX_MUL(ru3,y7));-                y[tensorOffset+rts*5]    = CMPLX_ADD7(y1, CMPLX_MUL(ru5,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru1,y4), CMPLX_MUL(ru6,y5), CMPLX_MUL(ru4,y6), CMPLX_MUL(ru2,y7));-                y[tensorOffset+rts*6]    = CMPLX_ADD7(y1, CMPLX_MUL(ru6,y2), CMPLX_MUL(ru5,y3), CMPLX_MUL(ru4,y4), CMPLX_MUL(ru3,y5), CMPLX_MUL(ru2,y6), CMPLX_MUL(ru1,y7));-            }   -        }-    }-    else-    {-        hDim_t temp1 = rts*p;-        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hDim_t row, col;-                -                for(row = 0; row < p; row++)-                {-                    complex_t acc = ((complex_t){0,0});-                    for(col = 0; col < p; col++)-                    {-                        CMPLX_IADD(acc, CMPLX_MUL(y[tensorOffset+col*rts], ru[((col*row) % p)*rustride]));-                    }-                    tempSpace[row] = acc;-                }-                -                for(row = 0; row < p; row++)-                {-                    y[tensorOffset+rts*row] = tempSpace[row];   -                }-            }-        }-    }-}--void crtpC (complex_t* y, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ru)-{-    hDim_t blockOffset, modOffset, tensorOffset;-    -    if(p == 2)-    {-        return;-    }-    else if(p == 3)-    {-        hDim_t temp1 = rts*2;-        complex_t ru1 = ru[rustride];-        complex_t ru2 = ru[rustride<<1];--        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                complex_t y1, y2;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y[tensorOffset]     = CMPLX_ADD(y1, CMPLX_MUL(ru1,y2));-                y[tensorOffset+rts] = CMPLX_ADD(y1, CMPLX_MUL(ru2,y2));-            }   -        }-    }-    else if(p == 5)-    {-        hDim_t temp1 = rts*4;-        complex_t ru1 = ru[rustride];-        complex_t ru2 = ru[rustride<<1];-        complex_t ru3 = ru[rustride*3];-        complex_t ru4 = ru[rustride<<2];--        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                complex_t y1, y2, y3, y4;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];-                y[tensorOffset]          = CMPLX_ADD4(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4));-                y[tensorOffset+rts]      = CMPLX_ADD4(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru1,y4));-                y[tensorOffset+(rts<<1)] = CMPLX_ADD4(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru4,y4));-                y[tensorOffset+rts*3]    = CMPLX_ADD4(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru2,y4));-            }   -        }-    }-    else if(p == 7)-    {-        hDim_t temp1 = rts*6;-        complex_t ru1 = ru[rustride];-        complex_t ru2 = ru[rustride<<1];-        complex_t ru3 = ru[rustride*3];-        complex_t ru4 = ru[rustride<<2];-        complex_t ru5 = ru[rustride*5];-        complex_t ru6 = ru[rustride*6];--        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                complex_t y1, y2, y3, y4, y5, y6;-                y1 = y[tensorOffset];-                y2 = y[tensorOffset+rts];-                y3 = y[tensorOffset+(rts<<1)];-                y4 = y[tensorOffset+3*rts];-                y5 = y[tensorOffset+(rts<<2)];-                y6 = y[tensorOffset+rts*5];-                y[tensorOffset]          = CMPLX_ADD6(y1, CMPLX_MUL(ru1,y2), CMPLX_MUL(ru2,y3), CMPLX_MUL(ru3,y4), CMPLX_MUL(ru4,y5), CMPLX_MUL(ru5,y6));-                y[tensorOffset+rts]      = CMPLX_ADD6(y1, CMPLX_MUL(ru2,y2), CMPLX_MUL(ru4,y3), CMPLX_MUL(ru6,y4), CMPLX_MUL(ru1,y5), CMPLX_MUL(ru3,y6));-                y[tensorOffset+(rts<<1)] = CMPLX_ADD6(y1, CMPLX_MUL(ru3,y2), CMPLX_MUL(ru6,y3), CMPLX_MUL(ru2,y4), CMPLX_MUL(ru5,y5), CMPLX_MUL(ru1,y6));-                y[tensorOffset+rts*3]    = CMPLX_ADD6(y1, CMPLX_MUL(ru4,y2), CMPLX_MUL(ru1,y3), CMPLX_MUL(ru5,y4), CMPLX_MUL(ru2,y5), CMPLX_MUL(ru6,y6));-                y[tensorOffset+(rts<<2)] = CMPLX_ADD6(y1, CMPLX_MUL(ru5,y2), CMPLX_MUL(ru3,y3), CMPLX_MUL(ru1,y4), CMPLX_MUL(ru6,y5), CMPLX_MUL(ru4,y6));-                y[tensorOffset+rts*5]    = CMPLX_ADD6(y1, CMPLX_MUL(ru6,y2), CMPLX_MUL(ru5,y3), CMPLX_MUL(ru4,y4), CMPLX_MUL(ru3,y5), CMPLX_MUL(ru2,y6));-            }   -        }-    }-    else-    {-        complex_t* tempSpace = (complex_t*)malloc((p-1)*sizeof(complex_t));-        hDim_t temp1 = rts*(p-1);-        for(blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;-                hDim_t row, col;-                -                for(row = 1; row < p; row++)-                {-                    complex_t acc = ((complex_t){0,0});-                    for(col = 0; col < p-1; col++)-                    {-                        CMPLX_IADD(acc, CMPLX_MUL(y[tensorOffset+col*rts], ru[((col*row) % p)*rustride]));-                    }-                    tempSpace[row-1] = acc;-                }-                -                for(row = 0; row < p-1; row++)-                {-                    y[tensorOffset+rts*row] = tempSpace[row];   -                }-            }-        }-        free(tempSpace);-    }-}--//takes inverse rus-void crtpinvC (complex_t* y, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ruinv)-{-    if(p ==2)-    {-        // need this case so that we can divide overall by mhat^(-1)-        return;-    }-    else-    {-        hDim_t tensorOffset,i;-        complex_t* tempSpace = (complex_t*)malloc(p*sizeof(complex_t));-        hDim_t temp1 = rts*(p-1);-        for(hDim_t blockOffset = 0; blockOffset < lts; blockOffset++)-        {-            hDim_t temp2 = blockOffset*temp1;-            for(hDim_t modOffset = 0; modOffset < rts; modOffset++)-            {-                tensorOffset = temp2 + modOffset;--                for(i = 0; i < p-1; i++)-                {-                    complex_t sum = ((complex_t){0,0});-                    int j;-                    for(j = 0; j < p-1; j++)-                    {-                        int ruIdx = (((j+1)*i) % p)*rustride;-                        CMPLX_IADD(sum, CMPLX_MUL(y[tensorOffset+j*rts],ruinv[ruIdx]));-                    }-                    tempSpace[i] = sum;-                }--                complex_t shift = ((complex_t){0,0});-                for(i = 0; i < p-1; i++)-                {-                    // we were given the inverse rus, so we need to negate the indices-                    int ruIdx = p-(i+1);-                    CMPLX_IADD(shift, CMPLX_MUL(y[tensorOffset+i*rts], ruinv[rustride*ruIdx]));-                }--                for(i = 0; i < p-1; i++)-                {-                    y[tensorOffset+i*rts] = CMPLX_SUB(tempSpace[i], shift); -                }-            }-        }-    }-}--void ppDFTC (complex_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t rustride, complex_t* ru)-{-    hDim_t p = pe.prime;-    hShort_t e = pe.exponent;-    -    if(e == 0)-    {-        return;-    }-    -    hDim_t primeRuStride = rustride*ipow(p,e-1);    -    complex_t* temp = 0;-    if(p >= DFTP_GENERIC_SIZE)-    {-        temp = (complex_t*)malloc(p*sizeof(complex_t));-    }-    hShort_t i;-    -    hDim_t ltsScale = ipow(p,e-1);-    hDim_t rtsScale = 1;-    hDim_t twidRuStride = rustride;-    for(i = 0; i < e; i++)-    {-        hDim_t rtsDim = rts*rtsScale;-        dftpC (y, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp);-        dftptwidC (y, lts, rtsDim, pe, ltsScale*p, twidRuStride, ru);-        -        ltsScale /= p;-        rtsScale *= p;-        twidRuStride *= p;-        pe.exponent -= 1;-    }-    -    if(p >= DFTP_GENERIC_SIZE)-    {-        free(temp);-    }-}--void ppDFTInvC (complex_t* y, hDim_t lts, hDim_t rts, PrimeExponent pe, hDim_t rustride, complex_t* ru)-{--    hDim_t p = pe.prime;-    hShort_t e = pe.exponent;-    -    if(e == 0)-    {-        return;-    }-    hDim_t primeRuStride = rustride*ipow(p,e-1);-    complex_t* temp = 0;-    if(p >= DFTP_GENERIC_SIZE)-    {-        temp = (complex_t*)malloc(p*sizeof(complex_t));-    }-    hShort_t i;-    -    hDim_t ltsScale = 1;-    hDim_t rtsScale = ipow(p,e-1);-    hDim_t twidRuStride = primeRuStride;-    pe.exponent = 1;-    for(i = 0; i < e; i++)-    {-        hDim_t rtsDim = rts*rtsScale;-        hDim_t ltsScaleP = ltsScale*p;-        dftptwidC (y, lts, rtsDim, pe, ltsScaleP, twidRuStride, ru);-        dftpC (y, lts*ltsScale, rtsDim, p, primeRuStride, ru, temp);-        -        ltsScale = ltsScaleP;-        rtsScale /= p;-        twidRuStride /= p;-        pe.exponent += 1;-    }-    -    if(p >= DFTP_GENERIC_SIZE)-    {-        free(temp);-    }-}--void ppcrtC (void* y, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t q)-{-    hDim_t p = pe.prime;-    hDim_t e = pe.exponent;-#ifdef DEBUG_MODE-    ASSERT(e != 0);-#endif-    hDim_t mprime = ipow(p,e-1);--#ifdef DEBUG_MODE-    printf("rus for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);-    hDim_t i;-    for(i = 0; i < ipow(p,e); i++) {-        printf("(%f,%f),", ((complex_t*)ru)[i].real, ((complex_t*)ru)[i].imag);-    }-    printf("]\n");-#endif--    crtpC ((complex_t*)y, lts*mprime, rts, p, mprime, (complex_t*)ru);-    crtTwiddleC ((complex_t*)y, lts, rts, pe, (complex_t*)ru);-    pe.exponent -= 1;-    ppDFTC ((complex_t*)y, lts, rts*(p-1), pe, p, (complex_t*)ru);-}--void ppcrtinvC (void* y, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t q)-{-    hDim_t p = pe.prime;-    hDim_t e = pe.exponent;-#ifdef DEBUG_MODE-    ASSERT(e != 0);-#endif-    hDim_t mprime = ipow(p,e-1);-    -    pe.exponent -= 1;-    ppDFTInvC ((complex_t*)y, lts, rts*(p-1), pe, p, (complex_t*)ru);-    pe.exponent += 1;-    crtTwiddleC ((complex_t*)y, lts, rts, pe, (complex_t*)ru);-    crtpinvC ((complex_t*)y, lts*mprime, rts, p, mprime, (complex_t*)ru);-}--void tensorCRTC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru)-{-#ifdef STATS-    struct timespec s1,t1;-    crtCCtr++;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-#ifdef DEBUG_MODE-    printf("\n\nEntered tensorCRTC\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);-    hDim_t j;-    for(j = 0; j < totm; j++) {-        printf("(%f,%f),", y[j].real, y[j].imag);-    }-    printf("]\n[");-    for(j = 0; j < sizeOfPE; j++) {-        printf("(%" PRId32 ",%" PRId16 "),", peArr[j].prime, peArr[j].exponent);-    }-    printf("]\n");-#endif-    void** rus = (void**)malloc(sizeOfPE*sizeof(void*));-    hShort_t i;-    for(i = 0; i < sizeOfPE; i++)-    {-        rus[i] = (void*) (ru[i]);-    }-	tensorFuserCRT (y, ppcrtC, totm, peArr, sizeOfPE, rus, 0);-	free(rus);-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    crtCTime = tsAdd(crtCTime, tsSubtract(t1,s1));-#endif-}--//takes inverse rus-void tensorCRTInvC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ruinv, double mhatInv)-{-#ifdef STATS-    struct timespec s1,t1;-    crtInvCCtr++;-    clock_gettime(CLOCK_REALTIME, &s1);-#endif-	hDim_t i;-	-	void** rus = (void**)malloc(sizeOfPE*sizeof(void*));-    for(i = 0; i < sizeOfPE; i++)-    {-        rus[i] = (void*) (ruinv[i]);-    }-	-	tensorFuserCRT (y, ppcrtinvC, totm, peArr, sizeOfPE, rus, 0);-	complex_t minvcmplx = ((complex_t){mhatInv,0});--	for (hDim_t j = 0; j < totm; j++)-	{-	    CMPLX_IMUL(y[j], minvcmplx);-	}-	-	free(rus);-#ifdef STATS-    clock_gettime(CLOCK_REALTIME, &t1);-    crtInvCTime = tsAdd(crtInvCTime, tsSubtract(t1,s1));-#endif-}
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/g.c
@@ -1,685 +0,0 @@-#include "tensorTypes.h"
-
-
-void gPowR (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p)
-{
-  hDim_t tmp1 = rts*(p-1);
-  hDim_t tmp2 = tmp1 - rts;
-  hDim_t blockOffset, modOffset;
-  hDim_t i;
-  for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-  {
-    hDim_t tmp3 = blockOffset * tmp1;
-    for (modOffset = 0; modOffset < rts; ++modOffset)
-    {
-      hDim_t tensorOffset = tmp3 + modOffset;
-      hInt_t last = y[tensorOffset + tmp2];
-      for (i = p-2; i != 0; --i)
-      {
-        hDim_t idx = tensorOffset + i * rts;
-        y[idx] += last - y[idx-rts];
-      }
-      y[tensorOffset] += last;
-    }
-  }
-}
-
-void gPowRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
-{
-	hDim_t tmp1 = rts*(p-1);
-	hDim_t tmp2 = tmp1 - rts;
-	hDim_t blockOffset, modOffset;
-	hDim_t i;
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-	{
-		hDim_t tmp3 = blockOffset * tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset)
-		{
-			hDim_t tensorOffset = tmp3 + modOffset;
-			hInt_t last = y[tensorOffset + tmp2];
-			for (i = p-2; i != 0; --i)
-			{
-				hDim_t idx = tensorOffset + i * rts;
-				y[idx] = (y[idx] + last - y[idx-rts]) % q;
-			}
-			y[tensorOffset] = (y[tensorOffset] + last) % q;
-		}
-	}
-}
-
-
-void ppGPowR (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-     
-	if (p != 2)
-	{
-		gPowR ((hInt_t*)y, lts*ipow(p,e-1), rts, p);
-	}
-}
-
-
-void ppGPowRq (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	if (p != 2)
-	{
-		gPowRq ((hInt_t*)y, lts*ipow(p,e-1), rts, p, q);
-	}
-}
-
-
-
-void gDecR (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p)
-{
-	hDim_t tmp1 = rts*(p-1);
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	hDim_t i;
-
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-	{
-		hDim_t tmp2 = blockOffset * tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset)
-		{
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hInt_t acc = y[tensorOffset];
-			for (i = p-2; i != 0; --i)
-			{
-				hDim_t idx = tensorOffset + i * rts;
-				acc += y[idx];
-				y[idx] -= y[idx-rts];
-			}
-			y[tensorOffset] += acc;
-		}
-	}
-}
-
-void gDecRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
-{
-	hDim_t tmp1 = rts*(p-1);
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	hDim_t i;
-
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-	{
-		hDim_t tmp2 = blockOffset * tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset)
-		{
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hInt_t acc = y[tensorOffset];
-			for (i = p-2; i != 0; --i)
-			{
-				hDim_t idx = tensorOffset + i * rts;
-        // acc is at most p*q << 64 bits, so no need to mod
-				acc = acc + y[idx];
-				y[idx] = (y[idx] - y[idx-rts]) % q;
-			}
-			y[tensorOffset] = (y[tensorOffset] + acc) % q;
-		}
-	}
-}
-
-void ppGDecR (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	if (p != 2)
-	{
-		gDecR ((hInt_t*)y, lts*ipow(p,e-1), rts, p);
-	}
-}
-
-void ppGDecRq (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	if (p != 2)
-	{
-		gDecRq ((hInt_t*)y, lts*ipow(p,e-1), rts, p, q);
-	}
-}
-
-
-void gInvPowR (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p)
-{
-	hDim_t tmp1 = rts * (p-1);
-	hDim_t blockOffset, modOffset;
-	hDim_t i;
-
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-	{
-		hDim_t tmp2 = blockOffset * tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset)
-		{
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hInt_t lelts = 0;
-			for (i = 0; i < p-1; ++i)
-			{
-				lelts += y[tensorOffset + i*rts];
-			}
-			hInt_t relts = 0;
-			for (i = p-2; i >= 0; --i)
-			{
-				hDim_t idx = tensorOffset + i*rts;
-				hInt_t z = y[idx];
-				y[idx] = (p-1-i) * lelts - (i+1)*relts;
-				lelts -= z;
-				relts += z;
-			}
-		}
-	}
-}
-
-void gInvPowRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
-{
-	hDim_t tmp1 = rts * (p-1);
-	hDim_t blockOffset, modOffset;
-	hDim_t i;
-
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-	{
-		hDim_t tmp2 = blockOffset * tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset)
-		{
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hInt_t lelts = 0;
-      //lelts is at most p*q, so we can mod once at the end
-			for (i = 0; i < p-1; ++i)
-			{
-				lelts = lelts + y[tensorOffset + i*rts];
-			}
-      lelts = lelts % q;
-      //in the next loop, lelts <= p*q and relts <= p*q
-      //products are <= p*p*q, and diff is <= 2*p*p*q
-      //so we assume 2*p^2 << 31 bits
-			hInt_t relts = 0;
-			for (i = p-2; i >= 0; --i)
-			{
-				hDim_t idx = tensorOffset + i*rts;
-				hInt_t z = y[idx];
-				y[idx] = (((p-1-i) * lelts) - ((i+1)*relts)) % q;
-				lelts -= z;
-				relts += z;
-			}
-		}
-	}
-}
-
-
-void ppGInvPowR (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	if (p != 2)
-	{
-		gInvPowR ((hInt_t*)y, lts*ipow(p,e-1), rts, p);
-	}
-}
-
-void ppGInvPowRq (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	if (p != 2)
-	{
-		gInvPowRq ((hInt_t*)y, lts*ipow(p,e-1), rts, p, q);
-	}
-}
-
-//do not call for p=2!
-void gCRTRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hInt_t* gcoeffs, hInt_t q)
-{
-    hDim_t gindex;
-    hDim_t blockOffset, modOffset, idx;
-    hDim_t temp1 = rts*(p-1);
-    
-    for(gindex = 0; gindex < p-1; gindex++)
-    {
-        hInt_t coeff = gcoeffs[gindex];
-        hDim_t temp3 = gindex*rts;
-        for(blockOffset = 0; blockOffset < lts; blockOffset++)
-        {
-            hDim_t temp2 = blockOffset*temp1 + temp3;
-            for(modOffset = 0; modOffset < rts; modOffset++)
-            {
-                idx = temp2 + modOffset;
-                y[idx] = (y[idx]*coeff)%q;
-            }
-        }
-    }
-}
-
-//do not call for p=2!
-void gCRTC (complex_t* y, hDim_t lts, hDim_t rts, hDim_t p, complex_t* gcoeffs)
-{
-    hDim_t gindex;
-    hDim_t blockOffset, modOffset, idx;
-    hDim_t temp1 = rts*(p-1);
-    
-    for(gindex = 0; gindex < p-1; gindex++)
-    {
-        complex_t coeff = gcoeffs[gindex];
-        hDim_t temp3 = gindex*rts;
-        for(blockOffset = 0; blockOffset < lts; blockOffset++)
-        {
-            hDim_t temp2 = blockOffset*temp1 + temp3;
-            for(modOffset = 0; modOffset < rts; modOffset++)
-            {
-                idx = temp2 + modOffset;
-                CMPLX_IMUL(y[idx],coeff);
-            }
-        }
-    }
-}
-
-void ppGCRTRq (void* y, hDim_t lts, hDim_t rts, PrimeExponent pe, void* gcoeffs, hInt_t q)
-{
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-    
-#ifdef DEBUG_MODE
-    printf("gcoeffs for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);
-    int i;
-    for(i = 0; i < ((p-1)*ipow(p,e-1)); i++) {
-        printf("%" PRId64 ",", ((hInt_t*)gcoeffs)[i]);
-    }
-    printf("]\n");
-#endif
-    
-	if (p != 2)
-	{
-		gCRTRq ((hInt_t*)y, lts*ipow(p,e-1), rts, p, (hInt_t*)gcoeffs, q);
-	}
-}
-
-void ppGCRTC (void* y, hDim_t lts, hDim_t rts, PrimeExponent pe, void* gcoeffs, hInt_t q)
-{
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-    
-#ifdef DEBUG_MODE
-    printf("gcoeffs for p=%" PRId32 ", e=%" PRId16 "\t[", pe.prime, pe.exponent);
-    int i;
-    for(i = 0; i < ((p-1)*ipow(p,e-1)); i++) {
-        printf("(%f,%f),", ((complex_t*)gcoeffs)[i].real, ((complex_t*)gcoeffs)[i].imag);
-    }
-    printf("]\n");
-#endif
-    
-	if (p != 2)
-	{
-		gCRTC ((complex_t*)y, lts*ipow(p,e-1), rts, p, (complex_t*)gcoeffs);
-	}
-}
-
-void gInvDecR (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p)
-{
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	hDim_t i;
-	hDim_t tmp1 = rts*(p-1);
-
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-	{
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset)
-		{
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hInt_t lastOut = 0;
-			for (i=1; i < p; ++i)
-			{
-				lastOut += i * y[tensorOffset + (i-1)*rts];
-			}
-			hInt_t acc = lastOut / p;
-			ASSERT (acc * p == lastOut);  // this line asserts that lastOut % p == 0, without calling % operator
-			for (i = p-2; i > 0; --i)
-			{
-				hDim_t idx = tensorOffset + i*rts;
-				hInt_t tmp = acc;
-				acc -= y[idx]; // we already divided acc by p, do not multiply y[idx] by p
-				y[idx] = tmp;
-			}
-			y[tensorOffset] = acc;
-		}
-	}
-}
-
-void gInvDecRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q)
-{
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	hDim_t i;
-	hDim_t tmp1 = rts*(p-1);
-	hInt_t reciprocalOfP = reciprocal (q,p);
-
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)
-	{
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset)
-		{
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hInt_t lastOut = 0;
-			for (i=1; i < p; ++i)
-			{
-				lastOut += (i * y[tensorOffset + (i-1)*rts]);
-			}
-      //in the previous loop, |lastOut| <= p*p*q
-      lastOut = lastOut % q;
-			hInt_t acc = (lastOut * reciprocalOfP) % q;
-      // |acc| <= p*q
-			for (i = p-2; i > 0; --i)
-			{
-				hDim_t idx = tensorOffset + i*rts;
-				hInt_t tmp = acc;
-				acc = acc - y[idx];
-				y[idx] = tmp % q;
-			}
-			y[tensorOffset] = acc % q;
-		}
-	}
-}
-
-void ppGInvDecR (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	if (p != 2)
-	{
-		gInvDecR ((hInt_t*)y, lts*ipow(p,e-1), rts, p);
-	}
-}
-
-void ppGInvDecRq (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q)
-{
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	if (p != 2)
-	{
-		gInvDecRq ((hInt_t*)y, lts*ipow(p,e-1), rts, p, q);
-	}
-}
-
-#ifdef STATS
-int gprCtr = 0;
-int gprqCtr = 0;
-int gdrCtr = 0;
-int gdrqCtr = 0;
-int giprCtr = 0;
-int giprqCtr = 0;
-int gidrCtr = 0;
-int gidrqCtr = 0;
-int gcrqCtr = 0;
-int gccCtr = 0;
-int gicrqCtr = 0;
-int giccCtr = 0;
-
-struct timespec gprTime = {0,0};
-struct timespec gprqTime = {0,0};
-struct timespec gdrTime = {0,0};
-struct timespec gdrqTime = {0,0};
-struct timespec giprTime = {0,0};
-struct timespec giprqTime = {0,0};
-struct timespec gidrTime = {0,0};
-struct timespec gidrqTime = {0,0};
-struct timespec gcrqTime = {0,0};
-struct timespec gccTime = {0,0};
-#endif
-
-void tensorGPowR (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
-{
-#ifdef STATS
-    gprCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppGPowR, totm, peArr, sizeOfPE, 0);
-
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gprTime = tsAdd(gprTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGPowRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q)
-{
-#ifdef STATS
-    gprqCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppGPowRq, totm, peArr, sizeOfPE, q);
-
-  hDim_t j;
-	for(j = 0; j < totm; j++)
-	{
-	    if(y[j]<0)
-	    {
-	        y[j]+=q;
-	    }
-	}
-
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gprqTime = tsAdd(gprqTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGDecR (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
-{
-#ifdef STATS
-    gdrCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppGDecR, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gdrTime = tsAdd(gdrTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGDecRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q)
-{
-#ifdef STATS
-    gdrqCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppGDecRq, totm, peArr, sizeOfPE, q);
-
-  hDim_t j;
-	for(j = 0; j < totm; j++)
-	{
-	    if(y[j]<0)
-	    {
-	        y[j]+=q;
-	    }
-	}
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gdrqTime = tsAdd(gdrqTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGInvPowR (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
-{
-#ifdef STATS
-    giprCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppGInvPowR, totm, peArr, sizeOfPE, 0);
-
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    giprTime = tsAdd(giprTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGInvPowRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q)
-{
-#ifdef STATS
-    giprqCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppGInvPowRq, totm, peArr, sizeOfPE, q);
-
-  hDim_t j;
-	for(j = 0; j < totm; j++)
-	{
-	    if(y[j]<0)
-	    {
-	        y[j]+=q;
-	    }
-	}
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    giprqTime = tsAdd(giprqTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGInvDecR (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE)
-{
-#ifdef STATS
-    gidrCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppGInvDecR, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gidrTime = tsAdd(gidrTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGInvDecRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q)
-{
-#ifdef STATS
-    gidrqCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-    tensorFuser (y, ppGInvDecRq, totm, peArr, sizeOfPE, q);
-
-  hDim_t j;
-	for(j = 0; j < totm; j++)
-	{
-	    if(y[j]<0)
-	    {
-	        y[j]+=q;
-	    }
-	}
-
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gidrqTime = tsAdd(gidrqTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorGCRTRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t q)
-{
-#ifdef STATS
-    gcrqCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-#ifdef DEBUG_MODE
-    printf("\n\nEntered tensorGCRTRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\tq=%" PRId64 "\n[", totm, sizeOfPE, q);
-    hDim_t j;
-    for(j = 0; j < totm; j++) {
-        printf("%" PRId64 ",", y[j]);
-    }
-    printf("]\n[");
-    for(j = 0; j < sizeOfPE; j++) {
-        printf("(%" PRId32 ",%" PRId16 "),", peArr[j].prime, peArr[j].exponent);
-    }
-    printf("]\n");
-#endif
-    void** vgcoeffs = (void**)malloc(sizeOfPE*sizeof(void*));
-    hDim_t i;
-    for(i = 0; i < sizeOfPE; i++)
-    {
-        vgcoeffs[i] = (void*) (gcoeffs[i]);
-    }
-
-    tensorFuserCRT (y, ppGCRTRq, totm, peArr, sizeOfPE, vgcoeffs, q);
-
-#ifdef DEBUG_MODE
-    for(j = 0; j < totm; j++)
-	{
-	    if(y[j]<0)
-	    {
-	        printf("tensorGCRTRq\n");
-	    }
-	}
-#endif
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gcrqTime = tsAdd(gcrqTime, tsSubtract(t1,s1));
-#endif
-}
-void tensorGCRTC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs)
-{
-#ifdef STATS
-    gccCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-#ifdef DEBUG_MODE
-    printf("\n\nEntered tensorGCRTC\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
-    hDim_t j;
-    for(j = 0; j < totm; j++) {
-        printf("(%f,%f),", (y[j]).real, (y[j]).imag);
-    }
-    printf("]\n[");
-    for(j = 0; j < sizeOfPE; j++) {
-        printf("(%" PRId32 ",%" PRId16 "),", peArr[j].prime, peArr[j].exponent);
-    }
-    printf("]\n");
-#endif
-    void** vgcoeffs = (void**)malloc(sizeOfPE*sizeof(void*));
-    hDim_t i;
-    for(i = 0; i < sizeOfPE; i++)
-    {
-        vgcoeffs[i] = (void*) (gcoeffs[i]);
-    }
-
-    tensorFuserCRT (y, ppGCRTC, totm, peArr, sizeOfPE, vgcoeffs, 0);
-
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    gccTime = tsAdd(gccTime, tsSubtract(t1,s1));
-#endif
-}
-void tensorGInvCRTRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t q)
-{
-#ifdef STATS
-    gicrqCtr++;
-#endif
-    tensorGCRTRq (y, totm, peArr, sizeOfPE, gcoeffs, q); //output is already shifted
-}
-void tensorGInvCRTC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs)
-{
-#ifdef STATS
-    giccCtr++;
-#endif
-    tensorGCRTC (y, totm, peArr, sizeOfPE, gcoeffs);
-}
-
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/generalfuncs.c
@@ -1,293 +0,0 @@-#include "tensorTypes.h"
-
-hDim_t ipow(hDim_t base, hShort_t exp)
-{
-#ifdef DEBUG_MODE
-    ASSERT(exp >= 0);
-#endif
-	hDim_t result = 1;
-    while (exp)
-    {
-        if (exp & 1)
-        {
-            result *= base;
-        }
-        exp >>= 1;
-        base *= base;
-    }
-    return result;
-}
-
-complex_t cmplxpow(complex_t base, hShort_t exp)
-{
-	complex_t result = (complex_t){1,0};
-    while (exp)
-    {
-        if (exp & 1)
-        {
-            CMPLX_IMUL(result,base);
-        }
-        exp >>= 1;
-        CMPLX_IMUL(base,base);
-    }
-    return result;
-}
-
-hInt_t qpow(hInt_t base, hShort_t exp, hInt_t q)
-{
-	hInt_t result = 1;
-    while (exp)
-    {
-        if (exp & 1)
-        {
-            result = (result*base)%q;
-        }
-        exp >>= 1;
-        base = (base*base)%q;
-    }
-    return result;
-}
-
-// a is the field size. we are looking for reciprocal of b
-hInt_t reciprocal (hInt_t a, hInt_t b)
-{
-	hInt_t fieldSize = a;
-
-	hInt_t y = 1;
-	hInt_t lasty = 0;
-	while (b != 0)
-	{
-		hInt_t quotient = a / b;
-		hInt_t tmp = a % b;
-		a = b;
-		b = tmp;
-		tmp = y;
-		y  = lasty - quotient*y;
-		lasty = tmp;
-	}
-	ASSERT (a==1);  // if this one fails, then b is not invertible mod a
-
-	// this actually returns EITHER the reciprocal OR reciprocal + fieldSize
-	hInt_t res = lasty + fieldSize;
-#ifdef DEBUG_MODE
-	ASSERT (0);
-	ASSERT ((res >= 0) && (res < fieldSize + fieldSize));
-	hInt_t test = res * b % fieldSize;
-	ASSERT (test == 1);
-#endif
-	return res;
-
-}
-
-//for square transforms
-void tensorFuser (void* y, funcPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q)
-{
-    hDim_t lts = totm;
-    hDim_t rts = 1;
-    hShort_t i;
-
-    for (i = 0; i < sizeOfPE; ++i)
-    {
-        PrimeExponent pe = peArr[i];
-        hDim_t ipow_pe = ipow(pe.prime, (pe.exponent-1));
-        hDim_t dim = (pe.prime-1) * ipow_pe;  // the totient of pe
-        lts /= dim;
-        (*f) (y, pe, lts, rts, q);
-        rts  *= dim;
-    }
-}
-
-void tensorFuserCRT (void* y, crtFuncPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, void** ru, hInt_t q)
-{
-    hDim_t lts = totm;
-    hDim_t rts = 1;
-    hShort_t i;
-
-    for (i = 0; i < sizeOfPE; ++i)
-    {
-        PrimeExponent pe = peArr[i];
-        hDim_t ipow_pe = ipow(pe.prime, (pe.exponent-1));
-        hDim_t dim = (pe.prime-1) * ipow_pe;  // the totient of pe
-        lts /= dim;
-        (*f) (y, lts, rts, pe, ru[i], q);
-        rts  *= dim;
-    }
-}
-
-struct  timespec  tsSubtract (struct  timespec  time1, struct  timespec  time2)
-{    /* Local variables. */
-    struct  timespec  result ;
-
-/* Subtract the second time from the first. */
-
-    if ((time1.tv_sec < time2.tv_sec) ||
-        ((time1.tv_sec == time2.tv_sec) &&
-         (time1.tv_nsec <= time2.tv_nsec))) {		/* TIME1 <= TIME2? */
-        result.tv_sec = result.tv_nsec = 0 ;
-    } else {						/* TIME1 > TIME2 */
-        result.tv_sec = time1.tv_sec - time2.tv_sec ;
-        if (time1.tv_nsec < time2.tv_nsec) {
-            result.tv_nsec = time1.tv_nsec + 1000000000L - time2.tv_nsec ;
-            result.tv_sec-- ;				/* Borrow a second. */
-        } else {
-            result.tv_nsec = time1.tv_nsec - time2.tv_nsec ;
-        }
-    }
-
-    return (result) ;
-}
-
-struct  timespec  tsAdd (struct  timespec  time1, struct  timespec  time2)
-{    /* Local variables. */
-    struct  timespec  result ;
-
-/* Add the two times together. */
-
-    result.tv_sec = time1.tv_sec + time2.tv_sec ;
-    result.tv_nsec = time1.tv_nsec + time2.tv_nsec ;
-    if (result.tv_nsec >= 1000000000L) {		/* Carry? */
-        result.tv_sec++ ;  result.tv_nsec = result.tv_nsec - 1000000000L ;
-    }
-
-    return (result) ;
-}
-
-const  char  *tsShow (struct  timespec  binaryTime, bool  inLocal, const  char  *format)
-{    /* Local variables. */
-    struct  tm  calendarTime ;
-#define  MAX_TIMES  4
-    static  char  asciiTime[MAX_TIMES][64] ;
-    static  int  current = 0 ;
-
-/* Convert the TIMESPEC to calendar time: year, month, day, etc. */
-
-#ifdef VXWORKS
-    if (inLocal)
-        localtime_r ((time_t *) &binaryTime.tv_sec, &calendarTime) ;
-    else
-        gmtime_r ((time_t *) &binaryTime.tv_sec, &calendarTime) ;
-#else
-    if (inLocal)
-        calendarTime = *(localtime ((time_t *) &binaryTime.tv_sec)) ;
-    else
-        calendarTime = *(gmtime ((time_t *) &binaryTime.tv_sec)) ;
-#endif
-
-/* Format the time in ASCII. */
-
-    current = (current + 1) % MAX_TIMES ;
-
-    if (format == NULL) {
-        strftime (asciiTime[current], 64, "%Y-%j-%H:%M:%S", &calendarTime) ;
-        sprintf (asciiTime[current] + strlen (asciiTime[current]),
-                 ".%06ld", (binaryTime.tv_nsec % 1000000000L) / 1000L) ;
-    } else {
-        strftime (asciiTime[current], 64, format, &calendarTime) ;
-        sprintf (asciiTime[current] + strlen (asciiTime[current]),
-                 ".%06ld", (binaryTime.tv_nsec % 1000000000L) / 1000L) ;
-    }
-
-    return (asciiTime[current]);
-}
-
-
-
-const char* timeformat = "%M:%S";
-
-void getStats() { 
-
-#ifdef STATS
-    struct timespec total;
-    printf("CRT Stats:\n");
-    printf("CRT_Rq times: Real:%s\tMono:%s\tProc:%s\tThread:%s\n", tsShow(crttime1, false, timeformat),tsShow(crttime2, false, timeformat),tsShow(crttime3, false, timeformat),tsShow(crttime4, false, timeformat));
-    printf("CTR_Rq: %d\t%s\t%d\t%s\n", crtRqCtr, tsShow(crttime1, false, timeformat), crtInvRqCtr, tsShow(crtInvRqTime, false, timeformat));
-    printf("CTR_C: %d\t%s\t%d\t%s\n", crtCCtr, tsShow(crtCTime, false, timeformat), crtInvCCtr, tsShow(crtInvCTime, false, timeformat));
-    
-    printf("\nG Stats:\n");
-    printf("GPow_R: %d\t%s\t%d\t%s\n", gprCtr, tsShow(gprTime, false, timeformat), giprCtr, tsShow(giprTime, false, timeformat));
-    printf("GPow_Rq: %d\t%s\t%d\t%s\n", gprqCtr, tsShow(gprqTime, false, timeformat), giprqCtr, tsShow(giprqTime, false, timeformat));
-    printf("GDec_R: %d\t%s\t%d\t%s\n", gdrCtr, tsShow(gdrTime, false, timeformat), gidrCtr, tsShow(gidrTime, false, timeformat));
-    printf("GDec_Rq: %d\t%s\t%d\t%s\n", gdrqCtr, tsShow(gdrqTime, false, timeformat), gidrqCtr, tsShow(gidrqTime, false, timeformat));
-    printf("GCRT_Rq: %d\t%d\t%s\n", gcrqCtr, gicrqCtr, tsShow(gcrqTime, false, timeformat));
-    printf("GCRT_C: %d\t%d\t%s\n", gccCtr, giccCtr, tsShow(gccTime, false, timeformat));
-
-    printf("\nL Stats:\n");
-    printf("L_R: %d\t%s\t%d\t%s\n", lrCtr, tsShow(lrTime, false, timeformat), lirCtr, tsShow(lirTime, false, timeformat));
-    printf("L_Rq: %d\t%s\t%d\t%s\n", lrqCtr, tsShow(lrqTime, false, timeformat), lirqCtr, tsShow(lirqTime, false, timeformat));
-    printf("L_D: %d\t%s\t%d\t%s\n", ldCtr, tsShow(ldTime, false, timeformat), lidCtr, tsShow(lidTime, false, timeformat));
-    printf("L_C: %d\t%s\t%d\t%s\n", lcCtr, tsShow(lcTime, false, timeformat), licCtr, tsShow(licTime, false, timeformat));
-
-    printf("\nBasic Stats:\n");
-    printf("Mul: %d\t%s\n", mulCtr, tsShow(mulTime, false, timeformat));
-    printf("Add: %d\t%s\n", addCtr, tsShow(addTime, false, timeformat));
-
-    total = tsAdd(crttime1, tsAdd(crtInvRqTime, tsAdd(crtCTime, tsAdd(crtInvCTime, tsAdd(gprTime, tsAdd(giprTime, tsAdd(gdrTime, tsAdd(gidrTime, tsAdd(gprqTime, tsAdd(giprqTime, tsAdd(gdrqTime, tsAdd(gidrqTime, tsAdd(gcrqTime, tsAdd(gccTime, tsAdd(lrTime, tsAdd(lirTime, tsAdd(lrqTime, tsAdd(lirqTime, tsAdd(ldTime, tsAdd(lidTime, tsAdd(lcTime, tsAdd(licTime, tsAdd(mulTime,addTime)))))))))))))))))))))));
-
-    printf("\nTotal C Time: %s\n\n", tsShow(total, false, timeformat));
-
-    crtRqCtr = 0;
-    crtInvRqCtr = 0;
-    crtCCtr = 0;
-    crtInvCCtr = 0;
-
-    gprCtr = 0;
-    gprqCtr = 0;
-    gdrCtr = 0;
-    gdrqCtr = 0;
-    giprCtr = 0;
-    giprqCtr = 0;
-    gidrCtr = 0;
-    gidrqCtr = 0;
-    gcrqCtr = 0;
-    gccCtr = 0;
-    gicrqCtr = 0;
-    giccCtr = 0;
-
-    lrqCtr = 0;
-    lrCtr = 0;
-    ldCtr = 0;
-    lcCtr = 0;
-    lirqCtr = 0;
-    lirCtr = 0;
-    lidCtr = 0;
-    licCtr = 0;
-
-    mulCtr = 0;
-    addCtr = 0;
-
-    mulTime = (struct timespec){0,0};
-    addTime = (struct timespec){0,0};
-
-    lrqTime = (struct timespec){0,0};
-    lrTime = (struct timespec){0,0};
-    ldTime = (struct timespec){0,0};
-    lcTime = (struct timespec){0,0};
-    lirqTime = (struct timespec){0,0};
-    lirTime = (struct timespec){0,0};
-    lidTime = (struct timespec){0,0};
-    licTime = (struct timespec){0,0};
-
-    gprTime = (struct timespec){0,0};
-    gprqTime = (struct timespec){0,0};
-    gdrTime = (struct timespec){0,0};
-    gdrqTime = (struct timespec){0,0};
-    giprTime = (struct timespec){0,0};
-    giprqTime = (struct timespec){0,0};
-    gidrTime = (struct timespec){0,0};
-    gidrqTime = (struct timespec){0,0};
-    gcrqTime = (struct timespec){0,0};
-    gccTime = (struct timespec){0,0};
-
-    crttime1 = (struct timespec){0,0};
-    crttime2 = (struct timespec){0,0};
-    crttime3 = (struct timespec){0,0};
-    crttime4 = (struct timespec){0,0};
-
-    crtInvRqTime = (struct timespec){0,0};
-    crtCTime = (struct timespec){0,0};
-    crtInvCTime = (struct timespec){0,0};
-#endif
-    fflush(stdout);
-}
-
-
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/l.c
@@ -1,410 +0,0 @@-#include "tensorTypes.h"
-
-void lpRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset) {
-			hDim_t idx = tmp2 + modOffset + rts;
-			for (i = 1; i < p-1; ++i) {
-        hInt_t temp = y[idx-rts] + y[idx];
-        if (temp >= q) y[idx]=temp-q;
-        else y[idx] = temp;
-				idx += rts;
-			}
-		}
-	}
-}
-
-void lpR (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)	{
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset) {
-			hDim_t idx = tmp2 + modOffset + rts;
-			for (i = 1; i < p-1; ++i) {
-				y[idx] += y[idx-rts];
-				idx += rts;
-			}
-		}
-	}
-}
-
-void lpDouble (double* y, hDim_t lts, hDim_t rts, hDim_t p) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset) {
-			hDim_t idx = tmp2 + modOffset + rts;
-			for (i = 1; i < p-1; ++i) {
-				y[idx] += y[idx-rts];
-				idx += rts;
-			}
-		}
-	}
-}
-
-void lpC (complex_t* y, hDim_t lts, hDim_t rts, hDim_t p) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++modOffset) {
-			hDim_t idx = tmp2 + modOffset + rts;
-			for (i = 1; i < p-1; ++i) {
-				CMPLX_IADD (y[idx], y[idx-rts]);
-				idx += rts;
-			}
-		}
-	}
-}
-
-void lpInvRq (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p, hInt_t q) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset)	{
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++ modOffset) {
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hDim_t idx = tensorOffset + (p-2) * rts;
-			for (i = p-2; i != 0; --i) {
-        hInt_t temp = y[idx] - y[idx-rts] + q;
-        if (temp >= q) y[idx]=temp-q;
-        else y[idx] = temp;
-				idx -= rts;
-			}
-		}
-	}
-}
-
-void lpInvR (hInt_t* y, hDim_t lts, hDim_t rts, hDim_t p) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++ modOffset) {
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hDim_t idx = tensorOffset + (p-2) * rts;
-			for (i = p-2; i != 0; --i) {
-				y[idx] -= y[idx-rts] ;
-				idx -= rts;
-			}
-		}
-	}
-}
-
-void lpInvDouble (double* y, hDim_t lts, hDim_t rts, hDim_t p) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++ modOffset) {
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hDim_t idx = tensorOffset + (p-2) * rts;
-			for (i = p-2; i != 0; --i) {
-				y[idx] -= y[idx-rts] ;
-				idx -= rts;
-			}
-		}
-	}
-}
-
-void lpInvC (complex_t* y, hDim_t lts, hDim_t rts, hDim_t p) {
-	hDim_t blockOffset;
-	hDim_t modOffset;
-	int i;
-
-	hDim_t tmp1 = rts*(p-1);
-	for (blockOffset = 0; blockOffset < lts; ++blockOffset) {
-		hDim_t tmp2 = blockOffset*tmp1;
-		for (modOffset = 0; modOffset < rts; ++ modOffset) {
-			hDim_t tensorOffset = tmp2 + modOffset;
-			hDim_t idx = tensorOffset + (p-2) * rts;
-			for (i = p-2; i != 0; --i) {
-				CMPLX_ISUB (y[idx], y[idx-rts]);
-				idx -= rts;
-			}
-		}
-	}
-}
-
-void ppLRq (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpRq ((hInt_t*)y, lts*ipow(p,e-1), rts, p, q);
-}
-
-void ppLR (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpR ((hInt_t*)y, lts*ipow(p,e-1), rts, p);
-}
-
-void ppLDouble (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpDouble ((double*)y, lts*ipow(p,e-1), rts, p);
-}
-
-void ppLC (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpC ((complex_t*)y, lts*ipow(p,e-1), rts, p);
-}
-
-
-void ppLInvRq (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpInvRq ((hInt_t*)y, lts*ipow(p,e-1), rts, p, q);
-}
-
-void ppLInvR (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpInvR ((hInt_t*)y, lts*ipow(p,e-1), rts, p);
-}
-
-void ppLInvDouble (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpInvDouble ((double*)y, lts*ipow(p,e-1), rts, p);
-}
-
-void ppLInvC (void* y, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q) {
-#ifdef DEBUG_MODE
-	ASSERT (q==0);
-#endif
-    hDim_t p = pe.prime;
-    hShort_t e = pe.exponent;
-	lpInvC ((complex_t*)y, lts*ipow(p,e-1), rts, p);
-}
-
-#ifdef STATS
-int lrqCtr = 0;
-int lrCtr = 0;
-int ldCtr = 0;
-int lcCtr = 0;
-int lirqCtr = 0;
-int lirCtr = 0;
-int lidCtr = 0;
-int licCtr = 0;
-
-struct timespec lrqTime = {0,0};
-struct timespec lrTime = {0,0};
-struct timespec ldTime = {0,0};
-struct timespec lcTime = {0,0};
-struct timespec lirqTime = {0,0};
-struct timespec lirTime = {0,0};
-struct timespec lidTime = {0,0};
-struct timespec licTime = {0,0};
-#endif
-
-
-void tensorLRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q) {
-#ifdef STATS
-    lrqCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-#ifdef DEBUG_MODE
-    hDim_t i;
-    printf("\n\nEntered tensorLRq\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\tq=%" PRId64 "\n[", totm, sizeOfPE, q);
-    /*for(i = 0; i < totm; i++) {
-        printf("%" PRId64 ",", y[i]);
-    }*/
-    printf("]\n[");
-    for(i = 0; i < sizeOfPE; i++) {
-        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
-    }
-    printf("]\n");
-#endif
-	tensorFuser (y, ppLRq, totm, peArr, sizeOfPE, q); // don't need to shift here
-#ifdef DEBUG_MODE
-	for(i = 0; i < totm; i++) {
-	    if(y[i]<0) {
-	        printf("tensorLRq\n");
-	    }
-	}
-#endif
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    lrqTime = tsAdd(lrqTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorLR (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
-#ifdef STATS
-    lrCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-#ifdef DEBUG_MODE
-    printf("\n\nEntered tensorLR\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
-    hDim_t i;
-    for(i = 0; i < totm; i++) {
-        printf("%" PRId64 ",", y[i]);
-    }
-    printf("]\n[");
-    for(i = 0; i < sizeOfPE; i++) {
-        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
-    }
-    printf("]\n");
-#endif
-	tensorFuser (y, ppLR, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    lrTime = tsAdd(lrTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorLDouble (double* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
-#ifdef STATS
-    ldCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-#ifdef DEBUG_MODE
-    printf("\n\nEntered tensorLDouble\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
-    hDim_t i;
-    for(i = 0; i < totm; i++) {
-        printf("%f,", y[i]);
-    }
-    printf("]\n[");
-    for(i = 0; i < sizeOfPE; i++) {
-        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
-    }
-    printf("]\n");
-#endif
-	tensorFuser (y, ppLDouble, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    ldTime = tsAdd(ldTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorLC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
-#ifdef STATS
-    lcCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-#ifdef DEBUG_MODE
-    printf("\n\nEntered tensorLC\ttotm=%" PRId32 "\tnumFacts=%" PRId16 "\n[", totm, sizeOfPE);
-    hDim_t i;
-    for(i = 0; i < totm; i++) {
-        printf("(%f,%f),", y[i].real, y[i].imag);
-    }
-    printf("]\n[");
-    for(i = 0; i < sizeOfPE; i++) {
-        printf("(%" PRId32 ",%" PRId16 "),", peArr[i].prime, peArr[i].exponent);
-    }
-    printf("]\n");
-#endif
-	tensorFuser (y, ppLC, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    lcTime = tsAdd(lcTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorLInvRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q) {
-#ifdef STATS
-    lirqCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppLInvRq, totm, peArr, sizeOfPE, q);  // don't need to shift here
-#ifdef DEBUG_MODE
-	hDim_t i;
-	for(i = 0; i < totm; i++)
-	{
-	    if(y[i]<0)
-	    {
-	        printf("tensorLInvRq\n");
-	    }
-	}
-#endif
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    lirqTime = tsAdd(lirqTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorLInvR (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
-#ifdef STATS
-    lirCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppLInvR, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    lirTime = tsAdd(lirTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorLInvDouble (double* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
-#ifdef STATS
-    lidCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppLInvDouble, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    lidTime = tsAdd(lidTime, tsSubtract(t1,s1));
-#endif
-}
-
-void tensorLInvC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE) {
-#ifdef STATS
-    licCtr++;
-    struct timespec s1,t1;
-    clock_gettime(CLOCK_REALTIME, &s1);
-#endif
-	tensorFuser (y, ppLInvC, totm, peArr, sizeOfPE, 0);
-#ifdef STATS
-    clock_gettime(CLOCK_REALTIME, &t1);
-    licTime = tsAdd(licTime, tsSubtract(t1,s1));
-#endif
-}
-
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/random.c
@@ -1,72 +0,0 @@--#include <math.h>-#include <stdlib.h>-#include "tensorTypes.h"--// this function takes *inverse* RUs, so no negation is needed on the indexing-// I had been negating the ru-idx, but this was causing a *negative* mod, resulting in a hard-to-find bug-void primeD (double *y, hDim_t lts, hDim_t rts, hDim_t p, hDim_t rustride, complex_t* ruinv)-{-	if(p == 2)-  {-      return;-  }-  hDim_t blockOffset, modOffset, tensorOffset;-	double *tempSpace = (double*)malloc((p-1)*sizeof(double));-  hDim_t temp1 = rts*(p-1);-  for(blockOffset = 0; blockOffset < lts; blockOffset++)-  {-    hDim_t temp2 = blockOffset*temp1;-    for(modOffset = 0; modOffset < rts; modOffset++)-    {-      tensorOffset = temp2 + modOffset;-      hDim_t row, col;-      -      for(row = 0; row < p-1; row++)-      {-        double acc = 0;-        for(col = 1; col <= (p>>1); col++)-        {-          acc += 2 * ruinv[((row*col) % p)*rustride].real * y[tensorOffset+rts*(col-1)];-        }-        for(col = (p>>1)+1; col <= p-1; col++)-        {-          acc += 2 * ruinv[((row*col) % p)*rustride].imag * y[tensorOffset+rts*(col-1)];-        }-        tempSpace[row] = acc/sqrt(2);-      }-      -      for(row = 0; row < p-1; row++)-      {-        y[tensorOffset+rts*row] = tempSpace[row];-      }-    }-  }-  free(tempSpace);-}--void ppD (void *y, hDim_t lts, hDim_t rts, PrimeExponent pe, void *ruinv, hInt_t q)-{-    hDim_t p = pe.prime;-    hDim_t e = pe.exponent;-#ifdef DEBUG_MODE-    ASSERT(e != 0);-#endif-    hDim_t mprime = ipow(p,e-1);-    primeD (y, lts*mprime, rts, p, mprime, (complex_t*)ruinv);-}--//the contents of y will be destroyed, but should be initialized in Haskell-land to independent Guassians over the reals-void tensorGaussianDec (double *y, hDim_t totm, PrimeExponent *peArr, hShort_t sizeOfPE, complex_t** ruinv)-{-  void** ruinvs = (void**)malloc(sizeOfPE*sizeof(void*));-  hShort_t i;-  for(i = 0; i < sizeOfPE; i++)-  {-      ruinvs[i] = (void*) (ruinv[i]);-  }-    -	tensorFuserCRT (y, ppD, totm, peArr, sizeOfPE, ruinvs, 0);-	-	free(ruinvs);-}
− src/Crypto/Lol/Cyclotomic/Tensor/CTensor/tensorTypes.h
@@ -1,224 +0,0 @@-
-#ifndef TENSORTYPES_H_
-#define TENSORTYPES_H_
-
-
-// remove next line for more efficient code
-//#define DEBUG_MODE
-
-
-#include <stdbool.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-
-#define ASSERT(EXP) { \
-	if (!(EXP)) { \
-		fprintf (stderr, "Assertion in file '%s' line %d : " #EXP "  is false\n", __FILE__, __LINE__); \
-		exit(-1); \
-	} \
-}
-
-
-//timers and counters
-#ifdef STATS
-extern int crtRqCtr;
-extern int crtInvRqCtr;
-extern int crtCCtr;
-extern int crtInvCCtr;
-
-extern int gprCtr;
-extern int gprqCtr;
-extern int gdrCtr;
-extern int gdrqCtr;
-extern int giprCtr;
-extern int giprqCtr;
-extern int gidrCtr;
-extern int gidrqCtr;
-extern int gcrqCtr;
-extern int gccCtr;
-extern int gicrqCtr;
-extern int giccCtr;
-
-extern int lrqCtr;
-extern int lrCtr;
-extern int ldCtr;
-extern int lcCtr;
-extern int lirqCtr;
-extern int lirCtr;
-extern int lidCtr;
-extern int licCtr;
-
-extern int mulCtr;
-extern struct timespec mulTime;
-extern int addCtr;
-extern struct timespec addTime;
-
-extern struct timespec lrqTime;
-extern struct timespec lrTime;
-extern struct timespec ldTime;
-extern struct timespec lcTime;
-extern struct timespec lirqTime;
-extern struct timespec lirTime;
-extern struct timespec lidTime;
-extern struct timespec licTime;
-
-extern struct timespec crttime1;
-extern struct timespec crttime2;
-extern struct timespec crttime3;
-extern struct timespec crttime4;
-extern struct timespec crtInvRqTime;
-extern struct timespec crtCTime;
-extern struct timespec crtInvCTime;
-
-extern struct timespec gprTime;
-extern struct timespec gprqTime;
-extern struct timespec gdrTime;
-extern struct timespec gdrqTime;
-extern struct timespec giprTime;
-extern struct timespec giprqTime;
-extern struct timespec gidrTime;
-extern struct timespec gidrqTime;
-extern struct timespec gcrqTime;
-extern struct timespec gccTime;
-#endif
-
-typedef int64_t hInt_t ;
-typedef int32_t hDim_t ;
-typedef int16_t hShort_t ;
-typedef int8_t hByte_t ;
-
-typedef struct
-{
-	hDim_t prime;
-	hShort_t exponent;
-}  PrimeExponent;
-
-
-typedef struct
-{
-	double real;
-	double imag;
-} complex_t;
-
-//complex_t _add (complex_t a, complex_t b);
-//complex_t _mul (complex_t a, complex_t b);
-
-#define CMPLX_ADD(a,b)  ((complex_t){((a).real + (b).real), ((a).imag + (b).imag)})
-#define CMPLX_ADD3(a,b,c)  ((complex_t){((a).real + (b).real + (c).real), ((a).imag + (b).imag + (c).imag)})
-#define CMPLX_ADD4(a,b,c,d)  ((complex_t){((a).real + (b).real + (c).real + (d).real), ((a).imag + (b).imag + (c).imag + (d).imag)})
-#define CMPLX_ADD5(a,b,c,d,e)  ((complex_t){((a).real + (b).real + (c).real + (d).real + (e).real), ((a).imag + (b).imag + (c).imag + (d).imag + (e).imag)})
-#define CMPLX_ADD6(a,b,c,d,e,f)  ((complex_t){((a).real + (b).real + (c).real + (d).real + (e).real + (f).real), ((a).imag + (b).imag + (c).imag + (d).imag + (e).imag + (f).imag)})
-#define CMPLX_ADD7(a,b,c,d,e,f,g)  ((complex_t){((a).real + (b).real + (c).real + (d).real + (e).real + (f).real + (g).real), ((a).imag + (b).imag + (c).imag + (d).imag + (e).imag + (f).imag + (g).imag)})
-
-#define CMPLX_SUB(a,b)  ((complex_t){((a).real - (b).real), ((a).imag - (b).imag)})
-#define CMPLX_MUL(a,b)  ((complex_t){((a).real*(b).real - (a).imag*(b).imag), \
-	                                  (a).real*(b).imag + (a).imag*(b).real})
-#define CMPLX_DIV(a,b)  ((complex_t){((a).real*(b).real + (a).imag*(b).imag)/((b).real*(b).real+(b).imag*(b).imag), \
-                                     ((a).imag*(b).real - (a).real*(b).imag)/((b).real*(b).real+(b).imag*(b).imag)})
-
-// 'inside' operators
-#define CMPLX_IADD(a,b)  { (a).real += (b).real;  (a).imag += (b).imag; }
-#define CMPLX_ISUB(a,b)  { (a).real -= (b).real;  (a).imag -= (b).imag; }
-#define CMPLX_IMUL(a,b)  { double temp = ((a).real*(b).real - (a).imag*(b).imag); \
-	                       (a).imag = ((a).real*(b).imag + (a).imag*(b).real); \
-	                       (a).real = temp; }
-
-
-/*
-// check if both vectors are identical
-bool eqInt (hInt_t a[], hInt_t b[], size_t n);
-// operations on integer vectors point-wise
-void addInt (hInt_t result[], hInt_t a[], hInt_t b[], size_t n);
-void mulInt (hInt_t result[], hInt_t a[], hInt_t b[], size_t n);
-*/
-
-// calculates base ** exp
-hDim_t ipow(hDim_t base, hShort_t exp);
-complex_t cmplxpow(complex_t base, hShort_t exp);
-hInt_t qpow(hInt_t base, hShort_t exp, hInt_t q);
-
-hInt_t reciprocal (hInt_t a, hInt_t b);
-
-struct  timespec  tsSubtract (struct  timespec  time1, struct  timespec  time2);
-struct  timespec  tsAdd (struct  timespec  time1, struct  timespec  time2);
-const  char  *tsShow (struct  timespec  binaryTime, bool  inLocal, const  char  *format);
-
-void getStats();
-
-void mulRq (hInt_t* a, hInt_t* b, hDim_t totm, hInt_t q);
-void mulMq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q);
-void mulC (complex_t* a, complex_t* b, hDim_t totm);
-
-void addR (hInt_t* a, hInt_t* b, hDim_t totm);
-void addRq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hInt_t q);
-void addMq (hInt_t* a, const hInt_t* b, const hDim_t totm, const hByte_t logr, const hInt_t k, const hInt_t q);
-void addC (complex_t* a, complex_t* b, hDim_t totm);
-void addD (double* a, double* b, hDim_t totm);
-
-typedef void (*funcPtr) (void* outputVec, PrimeExponent pe, hDim_t lts, hDim_t rts, hInt_t q);
-void tensorFuser (void* y, funcPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q);
-
-typedef void (*crtFuncPtr) (void* y, hDim_t lts, hDim_t rts, PrimeExponent pe, void* ru, hInt_t q);
-void tensorFuserCRT (void* y, crtFuncPtr f, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, void** ru, hInt_t q);
-
-void tensorGPowR (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorGPowRq (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q);
-
-void tensorGDecR (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorGDecRq (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q);
-
-void tensorGInvPowR (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorGInvPowRq (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q);
-
-void tensorGInvDecR (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorGInvDecRq (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q);
-
-void tensorGCRTRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t q);
-
-void tensorGInvCRTRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** gcoeffs, hInt_t q);
-
-void tensorGCRTC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs);
-
-void tensorGInvCRTC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** gcoeffs);
-
-
-
-void tensorLRq (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q);
-
-void tensorLR (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorLDouble (double* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorLC (complex_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorLInvRq (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t q);
-
-void tensorLInvR (hInt_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorLInvDouble (double* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-void tensorLInvC (complex_t* x, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE);
-
-
-
-void tensorCRTRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** ru, hInt_t q);
-
-void tensorCRTC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru);
-
-void tensorCRTInvRq (hInt_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, hInt_t** ru, hInt_t minv, hInt_t q);
-
-void tensorCRTInvC (complex_t* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru, double minv);
-
-void tensorGaussianDec (double* y, hDim_t totm, PrimeExponent* peArr, hShort_t sizeOfPE, complex_t** ru);
-
-
-#endif /* TENSORTYPES_H_ */
-
− src/Crypto/Lol/Cyclotomic/Tensor/RepaTensor.hs
@@ -1,199 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, DeriveDataTypeable,-             FlexibleContexts, FlexibleInstances, GADTs, InstanceSigs,-             MultiParamTypeClasses, NoImplicitPrelude, RebindableSyntax,-             RoleAnnotations, ScopedTypeVariables, StandaloneDeriving,-             TypeFamilies, TypeOperators, UndecidableInstances #-}---- | A pure, repa-based implementation of the Tensor interface.--module Crypto.Lol.Cyclotomic.Tensor.RepaTensor-( RT ) where--import Crypto.Lol.Cyclotomic.Tensor                      as T-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.CRT-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Extension-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Gauss-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.GL-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon  as RT-import Crypto.Lol.LatticePrelude                         as LP hiding-                                                                ((!!))-import Crypto.Lol.Types.IZipVector--import Algebra.Additive     as Additive (C)-import Algebra.Ring         as Ring (C)-import Algebra.ZeroTestable as ZeroTestable (C)--import Control.Applicative-import Control.DeepSeq       (NFData (rnf))-import Control.Monad         (liftM)-import Control.Monad.Random-import Data.Coerce-import Data.Constraint-import Data.Foldable         as F-import Data.Maybe-import Data.Traversable      as T-import Data.Typeable-import Data.Vector.Unboxed   as U hiding (force)-import Test.QuickCheck---- | An implementation of 'Tensor' backed by repa.-data RT (m :: Factored) r where-  RT :: Unbox r => !(Arr m r) -> RT m r-  ZV :: IZipVector m r -> RT m r-  deriving (Typeable)--deriving instance Show r => Show (RT m r)--instance Eq r => Eq (RT m r) where-  (ZV a) == (ZV b) = a == b-  (RT a) == (RT b) = a == b-  a@(RT _) == b = a == toRT b-  a == b@(RT _) = toRT a == b--zvToArr :: Unbox r => IZipVector m r -> Arr m r-zvToArr v = let vec = convert $ unIZipVector v-            in Arr $ fromUnboxed (Z :. U.length vec) vec---- converts to RT constructor-toRT :: Unbox r => RT m r -> RT m r-toRT v@(RT _) = v-toRT (ZV v) = RT $ zvToArr v--toZV :: Fact m => RT m r -> RT m r-toZV (RT (Arr v)) = ZV $ fromMaybe (error "toZV: internal error") $-                    iZipVector $ convert $ toUnboxed v-toZV v@(ZV _) = v--wrap :: Unbox r => (Arr l r -> Arr m r) -> RT l r -> RT m r-wrap f (RT v) = RT $ f v-wrap f (ZV v) = RT $ f $ zvToArr v--wrapM :: (Unbox r, Monad mon) => (Arr l r -> mon (Arr m r))-         -> RT l r -> mon (RT m r)-wrapM f (RT v) = liftM RT $ f v-wrapM f (ZV v) = liftM RT $ f $ zvToArr v--instance Tensor RT where--  type TElt RT r = (Unbox r, Elt r)--  entailIndexT  = tag $ Sub Dict-  entailEqT = tag $ Sub Dict-  entailZTT = tag $ Sub Dict-  entailRingT = tag $ Sub Dict-  entailNFDataT = tag $ Sub Dict-  entailRandomT = tag $ Sub Dict--  scalarPow = RT . scalarPow'--  l = wrap fL-  lInv = wrap fLInv--  mulGPow = wrap fGPow-  mulGDec = wrap fGDec--  divGPow = wrapM  fGInvPow-  divGDec = wrapM  fGInvDec--  crtFuncs = (,,,,) <$>-             (liftM (RT .) scalarCRT') <*>-             (wrap <$> mulGCRT') <*>-             (wrap <$> divGCRT') <*>-             (wrap <$> fCRT) <*>-             (wrap <$> fCRTInv)--  -- instance sigs are the cleanest way to handle many weird types-  -- coming up--  tGaussianDec :: forall v rnd m q .-                  (Fact m, OrdFloat q, Random q, TElt RT q,-                   ToRational v, MonadRandom rnd) => v -> rnd (RT m q)-  tGaussianDec = liftM RT . tGaussianDec'--  twacePowDec = wrap twacePowDec'--  embedPow = wrap embedPow'-  embedDec = wrap embedDec'--  crtExtFuncs = (,) <$> (liftM wrap twaceCRT')-                    <*> (liftM wrap embedCRT')--  coeffs = wrapM coeffs'--  powBasisPow = (RT <$>) <$> powBasisPow'--  crtSetDec = (RT <$>) <$> crtSetDec'--  fmapT f (RT v) = RT $ (coerce $ force . RT.map f) v-  fmapT f v@(ZV _) = fmapT f $ toRT v--  -- Repa arrays don't have mapM, so apply to underlying Unboxed-  -- vector instead-  fmapTM f (RT (Arr arr)) = liftM (RT . Arr . fromUnboxed (extent arr)) $-                            U.mapM f $ toUnboxed arr-  fmapTM f v@(ZV _) = fmapTM f $ toRT v------------ "Container" instances ------------instance Fact m => Functor (RT m) where-  -- Functor instance is implied by Applicative-  fmap f x = pure f <*> x--instance Fact m => Applicative (RT m) where-  pure = ZV . pure--  -- RT can never hold an a -> b-  (ZV f) <*> (ZV a) = ZV (f <*> a)-  f@(ZV _) <*> v@(RT _) = f <*> toZV v--instance Fact m => Foldable (RT m) where-  -- Foldable instance is implied by Traversable-  foldMap = foldMapDefault--instance Fact m => Traversable (RT m) where-  traverse f r@(RT _) = T.traverse f $ toZV r-  traverse f (ZV v) = ZV <$> T.traverse f v------------- Numeric Prelude instances -------------- CJP: should Elt, Unbox be constraints on these instances?  It's--- possible to zipWith on IZipVector, so it's not *necessary* to--- convert toRT.--instance (Fact m, Additive r, Unbox r, Elt r) => Additive.C (RT m r) where-  (RT a) + (RT b) = RT $ coerce (\x -> force . RT.zipWith (+) x) a b-  a + b = toRT a + toRT b--  negate (RT a) = RT $ (coerce $ force . RT.map negate) a-  negate a = negate $ toRT a--  zero = RT $ repl zero--instance (Fact m, Ring r, Unbox r, Elt r) => Ring.C (RT m r) where-  (RT a) * (RT b) = RT $ coerce (\x -> force . RT.zipWith (*) x) a b-  a * b = (toRT a) * (toRT b)--  fromInteger = RT . repl . fromInteger--instance (Fact m, ZeroTestable r, Unbox r, Elt r) => ZeroTestable.C (RT m r) where-  -- not using 'zero' to avoid Additive r constraint-  isZero (RT (Arr a)) = isZero $ foldAllS (\ x y -> if isZero x then y else x) (a RT.! (Z:.0)) a-  isZero (ZV v) = isZero v------------ Miscellaneous instances -------------- CJP: shouldn't these instances be defined in RTCommon, where the--- Arr data type is defined?  Here they are orphans.--instance (Unbox r, Random (Arr m r)) => Random (RT m r) where-  random = runRand $ liftM RT (liftRand random)--  randomR = error "randomR nonsensical for RT"--instance (Unbox r, Arbitrary (Arr m r)) => Arbitrary (RT m r) where-  arbitrary = RT <$> arbitrary--instance (NFData r) => NFData (RT m r) where-  rnf (RT v) = rnf v-  rnf (ZV v) = rnf v
− src/Crypto/Lol/Cyclotomic/Tensor/RepaTensor/CRT.hs
@@ -1,185 +0,0 @@-{-# LANGUAGE ConstraintKinds, FlexibleContexts, GADTs, NoImplicitPrelude,-             ScopedTypeVariables #-}---- | Functions to support the chinese remainder transform on Repa arrays--module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.CRT-( scalarCRT'-, fCRT, fCRTInv-, mulGCRT', divGCRT'-, gCRT, gInvCRT-) where--import Crypto.Lol.CRTrans-import Crypto.Lol.Cyclotomic.Tensor-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.GL-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon as RT-import Crypto.Lol.LatticePrelude                        as LP--import Control.Applicative-import Data.Coerce-import Data.Singletons.Prelude-import Data.Type.Natural       as N hiding (Z, one, zero)---- | Embeds a scalar into the CRT-basis when such basis exists-scalarCRT' :: forall m r . (Fact m, CRTrans r, Unbox r)-              => Maybe (r -> Arr m r)-scalarCRT'-  = let pps = proxy ppsFact (Proxy::Proxy m)-        sz = Z :. totientPPs pps-    in pure $ Arr . force . fromFunction sz . const---- | Multiplies an array in the CRT basis by 'g', when the CRT basis exists-mulGCRT' :: forall m r . (Fact m, CRTrans r, Unbox r, Elt r)-            => Maybe (Arr m r -> Arr  m r)-mulGCRT' = (coerce (\x -> force . RT.zipWith (*) x) `asTypeOf` asTypeOf) <$> gCRT---- | Divides an array in the CRT basis by 'g', when the CRT basis exists.-divGCRT' :: (Fact m, CRTrans r, IntegralDomain r, ZeroTestable r,-             Unbox r, Elt r) => Maybe (Arr m r -> Arr m r)-divGCRT' =  (coerce (\x -> force . RT.zipWith (*) x) `asTypeOf` asTypeOf) <$> gInvCRT---- | The CRT-basis representation of 'g'-gCRT :: (Fact m, CRTrans r, Unbox r, Elt r)-        => Maybe (Arr m r)-gCRT = fCRT <*> pure (fGPow $ scalarPow' LP.one)---- EAC: This was defined using (a safe call to) fromJust---- | The CRT-basis representation of 'g^{ -1 }'-gInvCRT:: (Fact m, CRTrans r, IntegralDomain r,-           ZeroTestable r, Unbox r, Elt r)-          => Maybe (Arr m r)-gInvCRT = fCRT <*> fGInvPow (scalarPow' LP.one)---fCRT, fCRTInv ::-  forall m r . (Fact m, CRTrans r, Unbox r, Elt r)-  => Maybe (Arr m r -> Arr m r)--- | The chinese remainder transform on Repa arrays.--- Exists if and only if crt exists for all prime powers-fCRT = evalM $ fTensor ppCRT---- divide by mhat after doing crtInv'--- | The inverse chinese remainder transform on Repa arrays.--- Exists if and only if crt exists for all prime powers-fCRTInv = do -- in Maybe-  (_, mhatInv) :: (CRTInfo r) <- proxyT crtInfoFact (Proxy :: Proxy m)-  let totm = proxy totientFact (Proxy :: Proxy m)-      divMhat = trans totm $ RT.map (*mhatInv)-  evalM $ (divMhat .*) <$> fTensor ppCRTInv'--ppDFT, ppDFTInv', ppCRT, ppCRTInv' ::-  forall pp r . (PPow pp, CRTrans r, Unbox r, Elt r)-  => TaggedT pp Maybe (Trans r)--ppDFT = case (sing :: SPrimePower pp) of-  (SPP (STuple2 _ SZ)) -> return $ Id 1-  spp@(SPP (STuple2 sp (SS se1))) ->-    tagT $ do-      let spp' = SPP (STuple2 sp se1)-      pp'dft <- withWitnessT ppDFT spp'-      pptwid <- withWitnessT (ppTwid False) spp-      pdft <- withWitnessT pDFT sp-      return $ (pp'dft @* Id (dim pdft)) .* pptwid .* (Id (dim pp'dft) @* pdft)--ppDFTInv' = case (sing :: SPrimePower pp) of-  (SPP (STuple2 _ SZ)) -> return $ Id 1-  spp@(SPP (STuple2 sp (SS se1))) ->-    tagT $ do-      let spp' = SPP (STuple2 sp se1)-      pp'dftInv' <- withWitnessT ppDFTInv' spp'-      pptwidInv <- withWitnessT (ppTwid True) spp-      pdftInv' <- withWitnessT pDFTInv' sp-      return $-        (Id (dim pp'dftInv') @* pdftInv') .* pptwidInv .*-        (pp'dftInv' @* Id (dim pdftInv'))--ppCRT = case (sing :: SPrimePower pp) of-  (SPP (STuple2 _ SZ)) -> return $ Id 1-  spp@(SPP (STuple2 sp (SS se1))) ->-    tagT $ do-      let spp' = SPP (STuple2 sp se1)-      pp'dft <- withWitnessT ppDFT spp'-      pptwid <- withWitnessT (ppTwidHat False) spp-      pcrt <- withWitnessT pCRT sp-      return $-        (pp'dft @* Id (dim pcrt)) .* pptwid .*-        -- save some work when p=2-        (if dim pcrt > 1 then Id (dim pp'dft) @* pcrt else Id (dim pp'dft))--ppCRTInv' = case (sing :: SPrimePower pp) of-  (SPP (STuple2 _ SZ)) -> return $ Id 1-  spp@(SPP (STuple2 sp (SS se1))) ->-    tagT $ do-      let spp' = SPP (STuple2 sp se1)-      pp'dftInv' <- withWitnessT ppDFTInv' spp'-      pptwidInv <- withWitnessT (ppTwidHat True) spp-      pcrtInv' <- withWitnessT pCRTInv' sp-      return $ -- special case for p=2 (necessary for scaling!)-        (if dim pcrtInv' > 1-         then Id (dim pp'dftInv') @* pcrtInv' else Id (dim pp'dftInv')) .*-        pptwidInv .* (pp'dftInv' @* Id (dim pcrtInv'))---- DFT_p, CRT_p, (scaled) DFT_p^-1, etc.-pDFT, pDFTInv', pCRT, pCRTInv' ::-  forall p r . (NatC p, CRTrans r, Unbox r, Elt r)-  => TaggedT p Maybe (Trans r)--pDFT = let pval = proxy valueNatC (Proxy::Proxy p)-       in do (omegaPPow, _) <- crtInfoNatC-             return $ trans pval $ mulMat $ force $-                                   fromFunction (Z :. pval :. pval)-                                   (\(Z:.i:.j) -> omegaPPow (i*j))--pDFTInv' = let pval = proxy valueNatC (Proxy::Proxy p)-           in do (omegaPPow, _) <- crtInfoNatC-                 return $ trans pval $ mulMat $ force $-                                       fromFunction (Z :. pval :. pval)-                                       (\(Z:.i:.j) -> omegaPPow (-i*j))--pCRT = let pval = proxy valueNatC (Proxy::Proxy p)-       in do (omegaPPow, _) <- crtInfoNatC-             return $ trans (pval-1) $ mulMat $ force $-                                     fromFunction (Z :. pval-1 :. pval-1)-                                     (\(Z:.i:.j) -> omegaPPow ((i+1)*j))---- crt_p * this = pI, for all values of p.  For p=2 this isn't the--- matrix we "want," but it doesn't matter because we don't use it in--- ppCRTInv'-pCRTInv' =-  let pval = proxy valueNatC (Proxy::Proxy p)-  in do (omegaPPow, _) <- crtInfoNatC-        return $ trans (pval-1) $  mulMat $ force $-                                fromFunction (Z :. pval-1 :. pval-1)-                                (\(Z:.i:.j) -> omegaPPow (negate i*(j+1)) --                                               omegaPPow (j+1))---- twiddle factors for DFT_pp and CRT_pp decompositions-ppTwid, ppTwidHat ::-  forall pp r . (PPow pp, CRTrans r, Unbox r, Elt r)-  => Bool -> TaggedT pp Maybe (Trans r)--ppTwid inv =-  let pp@(p,e) = proxy ppPPow (Proxy :: Proxy pp)-      ppval = valuePP pp-  in do-    (omegaPPPow, _) <- crtInfoPPow-    return $ trans ppval $ mulDiag $ force $-                           fromFunction (Z :. ppval)-                           (\(Z:.i) -> let (iq,ir) = i `divMod` p-                                           pow = (if inv then negate else id)-                                                 ir * digitRev (p,e-1) iq-                                       in omegaPPPow pow)--ppTwidHat inv =-  let pp@(p,e) = proxy ppPPow (Proxy :: Proxy pp)-      pptot = totientPP pp-  in do-    (omegaPPPow, _) <- crtInfoPPow-    return $ trans pptot $ mulDiag $ force $-                           fromFunction (Z :. pptot)-                           (\(Z:.i) -> let (iq,ir) = i `divMod` (p-1)-                                           pow = (if inv then negate else id)-                                                 (ir+1) * digitRev (p,e-1) iq-                                       in omegaPPPow pow)
− src/Crypto/Lol/Cyclotomic/Tensor/RepaTensor/Extension.hs
@@ -1,193 +0,0 @@-{-# LANGUAGE BangPatterns, ConstraintKinds, DataKinds, FlexibleContexts,-             FlexibleInstances, MultiParamTypeClasses, NoImplicitPrelude,-             ScopedTypeVariables, TemplateHaskell, TypeFamilies,-             TypeOperators #-}---- | RT-specific functions for embedding/twacing in various bases--module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Extension-( twacePowDec', twaceCRT', embedPow', embedDec', embedCRT'-, coeffs', powBasisPow', crtSetDec' --, fromCoeffs'-) where--import           Crypto.Lol.LatticePrelude              as LP hiding (lift, (!!))-import           Crypto.Lol.CRTrans-import           Crypto.Lol.Reflects-import qualified Crypto.Lol.Cyclotomic.Tensor                      as T-import           Crypto.Lol.Cyclotomic.Tensor.RepaTensor.CRT-import           Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon as RT-import           Crypto.Lol.Types.FiniteField-import           Crypto.Lol.Types.ZmStar--import Control.Applicative-import Control.Arrow       (first, (***))--import           Data.Coerce-import           Data.Default-import           Data.Maybe-import           Data.Reflection (reify)-import qualified Data.Vector                  as V-import qualified Data.Vector.Unboxed          as U-import           Data.Vector.Unboxed.Deriving---- Default instances-instance Default Z where def = Z-instance (Default a, Default b) => Default (a:.b) where def = def:.def---- derived Unbox instances-derivingUnbox "DIM1"-  [t| (Z:.Int) -> Int |]-  [| \(Z:.i) -> i |]-  [| (Z :.) |]---- | 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 . (m `Divides` m', Unbox r)-                 => Arr m' r -> Arr m r-twacePowDec'-  = let indices = proxy extIndicesPowDec (Proxy::Proxy '(m, m'))-    in coerce $ \ !arr -> force $ backpermute (extent indices) (indices !) arr---- | The "tweaked trace" function in the CRT--- basis of the m'th cyclotomic ring to the mth cyclotomic ring when --- @m | m'@.-twaceCRT' :: forall m m' r .-             (m `Divides` m', CRTrans r, IntegralDomain r,-              ZeroTestable r, Unbox r, Elt r)-             => Maybe (Arr m' r -> Arr m r)-twaceCRT' = do           -- Maybe monad-  g' :: Arr m' r <- gCRT-  gInv <- gInvCRT-  embed :: Arr m r -> Arr m' r <- embedCRT'-  (_, m'hatinv) <- proxyT crtInfoFact (Proxy::Proxy m')-  let hatRatioInv = m'hatinv * fromIntegral (proxy valueHatFact (Proxy::Proxy m))-      -- tweak = mhat * g' / (m'hat * g)-      tweak = (coerce $ \x -> force . RT.map (* hatRatioInv) . RT.zipWith (*) x) (embed gInv) g' :: Arr m' r-      indices = proxy extIndicesCRT (Proxy::Proxy '(m, m'))-  return $ -    -- take true trace after mul-by-tweak-    coerce (\ !arr -> sumS . backpermute (extent indices) (indices !) . RT.zipWith (*) arr) tweak--embedPow', embedDec' :: forall m m' r .-             (m `Divides` m', Unbox r, Additive r)-             => Arr m r -> Arr m' r--- | Embeds an array in the powerful basis of the the mth cyclotomic ring--- to an array in the powerful basis of the m'th cyclotomic ring when @m | m'@-embedPow'-  = let indices = proxy baseIndicesPow (Proxy::Proxy '(m, m'))-    in coerce $ \ !arr -> force $ fromFunction (extent indices)-                       (\idx -> let (j0,j1) = (indices ! idx)-                                in if j0 == 0 then arr ! j1 else zero)--- | Embeds an array in the decoding basis of the the mth cyclotomic ring--- to an array in the decoding basis of the m'th cyclotomic ring when @m | m'@-embedDec'-  = let indices = proxy baseIndicesDec (Proxy::Proxy '(m, m'))-    in coerce $ \ !arr -> force $-                       fromFunction (extent indices)-                         (\idx -> maybe zero-                                  (\(sh,b) -> if b then negate (arr ! sh)-                                              else arr ! sh)-                                  (indices ! idx))---- | Embeds an array in the CRT basis of the the mth cyclotomic ring--- to an array in the CRT basis of the m'th cyclotomic ring when @m | m'@-embedCRT' :: forall m m' r . (m `Divides` m', CRTrans r, Unbox r)-             => Maybe (Arr m r -> Arr m' r)-embedCRT' = do -- in Maybe-  -- first check existence of CRT transform of index m'-  proxyT crtInfoFact (Proxy::Proxy m') :: Maybe (CRTInfo r)-  let idxs = proxy baseIndicesCRT (Proxy::Proxy '(m,m'))-  return $ coerce $ \ !arr -> (force $ backpermute (extent idxs) (idxs !) arr)---- | maps an array in the powerful/decoding basis, representing an--- O_m' element, to an array of arrays representing O_m elements in--- the same type of basis-coeffs' :: forall m m' r . (m `Divides` m', Unbox r)-             => Arr m' r -> [Arr m r]-coeffs' =-  let indices = proxy extIndicesCoeffs (Proxy::Proxy '(m, m'))-  in coerce $ \ !arr -> V.toList $-  V.map (\idxs -> force $ backpermute (extent idxs) (idxs !) arr) indices---- | The powerful extension basis, wrt the powerful basis.--- Outputs a list of arrays in O_m' that are an O_m basis for O_m'-powBasisPow' :: forall m m' r . (m `Divides` m', Ring r, Unbox r)-                => Tagged m [Arr m' r]-powBasisPow' = return $  -  let (_, phi, phi', _) = proxy T.indexInfo (Proxy::Proxy '(m,m'))-      idxs = proxy T.baseIndicesPow (Proxy::Proxy '(m,m'))-  in LP.map (\k -> Arr $ force $ fromFunction (Z :. phi')-                         (\(Z:.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 arrays 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', Unbox fp)-              => Tagged m [Arr m' fp]-crtSetDec' = return $ -  let m'p = Proxy :: Proxy m'-      p = proxy value (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) ->-       let twCRTs' :: T.Matrix (GF fp d)-             = fromMaybe (error "internal error: crtSetDec': twCRTs") $ proxyT T.twCRTs m'p-           zmsToIdx = proxy T.zmsToIndexFact m'p-           elt j i = T.indexM twCRTs' j (zmsToIdx i)-           trace' = trace :: GF fp d -> fp-           cosets = proxy (partitionCosets p) (Proxy::Proxy '(m,m'))-       in LP.map (\is -> Arr $ force $ fromFunction (Z :. phi) -                          (\(Z:.j) -> hinv * trace'-                                      (sum $ LP.map (elt j) is))) cosets----- convert memoized reindexing Vectors to Arrays, for convenience and speed--extIndicesPowDec :: forall m m' . (m `Divides` m')-                    => Tagged '(m, m') (Array U DIM1 DIM1)-extIndicesPowDec = do-  idxs <- T.extIndicesPowDec-  return $ fromUnboxed (Z :. U.length idxs) $ U.map (Z:.) idxs--extIndicesCRT :: forall m m' . (m `Divides` m')-                 => Tagged '(m, m') (Array U DIM2 DIM1)-extIndicesCRT =-  let phi = proxy totientFact (Proxy::Proxy m)-      phi' = proxy totientFact (Proxy::Proxy m')-  in do-    idxs <- T.extIndicesCRT-    return $ fromUnboxed (Z :. phi :. phi' `div` phi) $ U.map (Z:.) idxs--baseIndicesPow :: forall m m' . (m `Divides` m')-                  => Tagged '(m, m') (Array U DIM1 (Int,DIM1))--baseIndicesDec :: forall m m' . (m `Divides` m')-                  => Tagged '(m, m') (Array U DIM1 (Maybe (DIM1, Bool)))--baseIndicesCRT :: forall m m' . (m `Divides` m')-                  => Tagged '(m, m') (Array U DIM1 DIM1)--baseIndicesPow = do-  idxs <- T.baseIndicesPow-  return $ fromUnboxed (Z :. U.length idxs) $ U.map (id *** (Z:.)) idxs--baseIndicesDec = do-  idxs <- T.baseIndicesDec-  return $ fromUnboxed (Z :. U.length idxs) $ U.map (liftA (first (Z:.))) idxs--baseIndicesCRT = do-  idxs <- T.baseIndicesCRT-  return $ fromUnboxed (Z :. U.length idxs) $ U.map (Z:.) idxs--extIndicesCoeffs :: forall m m' . (m `Divides` m')-                    => Tagged '(m, m') (V.Vector (Array U DIM1 DIM1))-extIndicesCoeffs = -  V.map (\arr -> fromUnboxed (Z :. U.length arr) $ -                 U.map (Z:.) arr) <$> T.extIndicesCoeffs
− src/Crypto/Lol/Cyclotomic/Tensor/RepaTensor/GL.hs
@@ -1,112 +0,0 @@-{-# LANGUAGE BangPatterns, ConstraintKinds, FlexibleContexts, GADTs,-             MultiParamTypeClasses, NoImplicitPrelude, RankNTypes,-             RebindableSyntax, ScopedTypeVariables #-}---- | The G and L transforms for Repa arrays--module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.GL-( fL, fLInv, fGPow, fGDec, fGInvPow, fGInvDec-) where--import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon as RT-import Crypto.Lol.LatticePrelude                        as LP-import Data.Coerce--fL, fLInv, fGPow, fGDec :: (Fact m, Additive r, Unbox r, Elt r)-  => Arr m r -> Arr m r--fGInvPow, fGInvDec ::- (Fact m, IntegralDomain r, ZeroTestable r, Unbox r, Elt r)-  => Arr m r -> Maybe (Arr m r)--- | Arbitrary-index L transform to convert a dec-basis Repa array to its powerful-basis representation-fL = eval $ fTensor $ ppTensor pL--- | Arbitrary-index L^{ -1 } transform to convert a powerful-basis Repa array to its dec-basis representation-fLInv = eval $ fTensor $ ppTensor pLInv--- | Arbitrary-index multiplication by the ring element g in the powerful basis-fGPow = eval $ fTensor $ ppTensor pGPow--- | Arbitrary-index multiplication by the ring element g in the dec basis-fGDec = eval $ fTensor $ ppTensor pGDec--- | Arbitrary-index division by the ring element g in the powerful basis. May fail if the input is not a multiple of g.-fGInvPow = wrapGInv' pGInvPow'--- | Arbitrary-index multiplication by the ring element g in the dec basis. May fail if the input is not a multiple of g.-fGInvDec = wrapGInv' pGInvDec'--wrapGInv' :: forall m r .-  (Fact m, IntegralDomain r, ZeroTestable r, Unbox r, Elt r)-  => (forall p . (NatC p) => Tagged p (Trans r))-  -> Arr m r -> Maybe (Arr m r)-wrapGInv' ginv =-  let fGInv = eval $ fTensor $ ppTensor ginv-      oddrad = fromIntegral $ proxy oddRadicalFact (Proxy::Proxy m)-  in (`divCheck` oddrad) . fGInv---- | This is not a constant-time algorithm!  Depending on its usage,--- it might provide a timing side-channel.-divCheck :: (IntegralDomain r, ZeroTestable r, Unbox r)-            => Arr m r -> r -> Maybe (Arr m r)-divCheck = coerce $  \ !arr den ->-  let qrs = force $ RT.map (`divMod` den) arr-      pass = foldAllS (&&) True $ RT.map (isZero . snd) qrs-      out = force $ RT.map fst qrs-  in if pass then Just out else Nothing--pWrap :: forall p r . (NatC p)-         => (forall rep . Source rep r => Int -> Array rep DIM2 r -> Array D DIM2 r)-         -> Tagged p (Trans r)-pWrap f = let pval = proxy valueNatC (Proxy::Proxy p)-              -- special case: return identity function for p=2-          in return $ if pval > 2-                      then trans  (pval-1) $ f pval-                      else Id 1---pL, pLInv, pGPow, pGDec :: (NatC p, Additive r, Unbox r, Elt r)-  => Tagged p (Trans r)--pGInvPow', pGInvDec' :: (NatC p, Ring r, Unbox r, Elt r)-  => Tagged p (Trans r)--pL = pWrap (\_ !arr ->-             fromFunction (extent arr) $-             \ (i':.i) -> sumAllS $ extract (Z:.0) (Z:.(i+1)) $ slice arr (i':.All))--pLInv = pWrap (\_ !arr ->-                let f (i' :. 0) = arr! (i' :. 0)-                    f (i' :. i) = arr! (i' :. i) - arr! (i' :. i-1)-                in fromFunction (extent arr) f)----- multiplicaton by g_p=1-zeta_p in power basis.--- this is "wrong" for p=2 but we never use that case thanks to pWrap.-pGPow = pWrap (\p !arr ->-                let f (i':.0) = arr! (i':.p-2) + arr! (i':.0)-                    f (i':.i) = arr! (i':.p-2) + arr! (i':.i) - arr! (i':.i-1)-                in fromFunction (extent arr) f)---- multiplication by g_p=1-zeta_p in decoding basis-pGDec = pWrap (\_ !arr ->-                let f (i':.0) = arr! (i':.0) + sumAllS (slice arr (i':.All))-                    f (i':.i) = arr! (i':.i) - arr! (i':.i-1)-                in fromFunction (extent arr) f)---- CJP: profiling suggests that this does two read passes through the--- array; see if we can rewrite to make it one---- doesn't do division by (odd) p-pGInvPow' =-  pWrap (\p !arr ->-          let f (i':.i) =-                let col = slice arr (i':.All)-                in fromIntegral (p-i-1) * sumAllS (extract (Z:.0) (Z:.i+1) col) +-                   fromIntegral (-i-1) * sumAllS (extract (Z:.i+1) (Z:.p-i-2) col)-          in fromFunction (extent arr) f)---- doesn't do division by (odd) p-pGInvDec' =-  pWrap (\p !arr ->-          let f (i':.i) =-                let col = slice arr (i':.All)-                    nats = fromFunction (Z:.p-1) (\(Z:.j) -> fromIntegral j+1)-                in (sumAllS $ RT.zipWith (*) col nats) --                   fromIntegral p * sumAllS (extract (Z:.i+1) (Z:.p-i-2) col)-          in fromFunction (extent arr) f)
− src/Crypto/Lol/Cyclotomic/Tensor/RepaTensor/Gauss.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE ConstraintKinds, FlexibleContexts, NoImplicitPrelude,-             RebindableSyntax, ScopedTypeVariables #-}---- | (Continuous) Gaussian sampling for Repa arrays--module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Gauss-( tGaussianDec' ) where--import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon-import Crypto.Lol.GaussRandom-import Crypto.Lol.LatticePrelude--import Control.Monad.Random---- | A function tagged by the cyclotomic index which,--- given a (scaled) variance, outputs a Gaussian-distributed--- vector in the decoding basis-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 $ fD arr---- | The fully tensored D transformation-fD :: (Fact m, Transcendental r, Unbox r, Elt r) => Arr m r -> Arr m r-fD = eval $ fTensor $ ppTensor pD---- | The D transformation for a prime-pD :: forall p r . (NatC p, Transcendental r, Unbox r, Elt r)-      => Tagged p (Trans r)-pD = let pval = proxy valueNatC (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) ->-                              -- mtx is 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)
− src/Crypto/Lol/Cyclotomic/Tensor/RepaTensor/RTCommon.hs
@@ -1,233 +0,0 @@-{-# LANGUAGE BangPatterns, ConstraintKinds, DataKinds, FlexibleContexts,-             FlexibleInstances, GADTs, GeneralizedNewtypeDeriving,-             KindSignatures, MultiParamTypeClasses, NoImplicitPrelude,-             RankNTypes, RebindableSyntax, RoleAnnotations,-             ScopedTypeVariables, TypeOperators #-}---- | A simple DSL for tensoring Repa arrays and other common functionality--- on Repa arrays--module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon-( module R-, module Data.Array.Repa.Eval-, module Data.Array.Repa.Repr.Unboxed-, Arr(..), repl, replM, eval, evalM, fTensor, ppTensor-, Trans(Id), trans, dim, (.*), (@*), force-, mulMat, mulDiag-, scalarPow'-, sumS, sumAllS-) where--import Crypto.Lol.LatticePrelude as LP hiding ((!!))--import Control.DeepSeq              (NFData (..))-import Control.Monad.Identity-import Control.Monad.Random-import Data.Array.Repa              as R hiding (sumAllP, sumAllS, sumP,-                                          sumS, (*^), (+^), (-^), (/^))-import Data.Array.Repa.Eval         hiding (one, zero)-import Data.Array.Repa.Repr.Unboxed-import Data.Coerce-import Data.Singletons-import Data.Singletons.Prelude      hiding ((:.))-import Data.Type.Natural            hiding (Z)-import Data.Typeable-import qualified Data.Vector.Unboxed as U-import Test.QuickCheck---- always unboxed (manifest); intermediate calculations can use--- delayed arrays---- | Indexed newtype for 1-dimensional Unbox repa arrays-newtype Arr (m :: Factored) r = Arr (Array U DIM1 r)-                              deriving (Eq, Show, Typeable, NFData)---- the first argument, though phantom, affects representation--- CJP: why must the second arg be nominal?--- EAC: From https://ghc.haskell.org/trac/ghc/wiki/Roles#Thesolution:---   "The exception to the above algorithm is for classes: all parameters for a class default to a nominal role."--- Arr is a synonym for Array, which is an associated data type to the class Source. The parameter `r` above--- corresponds to the parameter `e` in the definition of class Source, so it's role must be nominal.-type role Arr nominal nominal---- | An 'Arr' filled with the argument.-repl :: forall m r . (Fact m, Unbox r) => r -> Arr m r-repl = let n = proxy totientFact (Proxy::Proxy m)-       in Arr . fromUnboxed (Z:.n) . U.replicate n---- | Monadic version of 'repl'.-replM :: forall m r mon . (Fact m, Unbox r, Monad mon)-         => mon r -> mon (Arr m r)-replM = let n = proxy totientFact (Proxy::Proxy m)-        in liftM (Arr . fromUnboxed (Z:.n)) . U.replicateM n--instance (Unbox r) => NFData (Array U DIM1 r) where-  -- EAC: Repa doesn't define any NFData instances,-  -- I'm hoping deepSeqArray is a reasonable approx-  rnf x = deepSeqArray x ()--instance (Unbox r, Random r, Fact m) => Random (Arr m r) where-  random = runRand $ replM (liftRand random)--  randomR = error "randomR nonsensical for Arr"--instance (Arbitrary r, Unbox r, Fact m) => Arbitrary (Arr m r) where-    arbitrary = replM arbitrary-    shrink = shrinkNothing---- | For a factored index, tensors up any function defined for (and--- tagged by) any prime power-fTensor :: forall m r mon . (Fact m, Monad mon, Unbox r)-  => (forall pp . (PPow pp) => TaggedT pp mon (Trans r))-  -> TaggedT m mon (Trans r)--fTensor func = tagT $ go $ sUnF (sing :: SFactored m)-  where-    go :: Sing (pplist :: [PrimePower]) -> mon (Trans r)-    go spps = case spps of-          SNil -> return $ Id 1-          (SCons spp rest) -> do-            rest' <- go rest-            func' <- withWitnessT func spp-            return $ rest' @* func'---- | For a prime power pp > 1, tensors up any function f defined for--- (and tagged by) a prime to (I_(pp/p) \otimes f)-ppTensor :: forall pp r mon . (PPow pp, Monad mon)-            => (forall p . (NatC p) => TaggedT p mon (Trans r))-            -> TaggedT pp mon (Trans r)--ppTensor func = tagT $ case (sing :: SPrimePower pp) of-  -- intentionally no match for zero exponents, because that is-  -- ill-formed and indicates an internal error-  (SPP (STuple2 sp (SS se1))) -> do-    func' <- withWitnessT func sp-    let lts = withWitness valuePPow (SPP (STuple2 sp se1))-    return $ Id lts @* func'----- deeply embedded DSL for transformations and their various--- compositions---- (dim(f), f) where f operates on innermost dimension of array-data Tensorable r = Tensorable-  Int (forall rep . Source rep r => Array rep DIM2 r -> Array D DIM2 r)---- transform component: a Tensorable with particular I_l, I_r-type TransC r = (Tensorable r, Int, Int)---- full transform: sequence of zero or more components--- | a DSL for tensor transforms on Repa arrays-data Trans r = Id Int           -- ^| identity sentinel-             | TSnoc (Trans r) (TransC r) -- ^| (function) composition of transforms--dimC :: TransC r -> Int-dimC (Tensorable d _, l, r) = l*d*r---- | Returns the (linear) dimension of a transform-dim :: Trans r -> Int-dim (Id n) = n-dim (TSnoc _ f) = dimC f        -- just use dimension of head---- | smart constructor from a Tensorable-trans :: Int -> (forall rep . Source rep r => Array rep DIM2 r -> Array D DIM2 r) -> Trans r-trans d f = TSnoc (Id d) (Tensorable d f, 1, 1)---- | compose transforms-(.*) :: Trans r -> Trans r -> Trans r-f .* g | dim f == dim g = f ..* g-       | otherwise = error $ "(.*): transform dimensions don't match "-                     LP.++ show (dim f) LP.++ ", " LP.++ show (dim g)-  where-    f' ..* (Id _) = f'          -- drop sentinel-    f' ..* (TSnoc rest g') = TSnoc (f' ..* rest) g'---- | tensor/Kronecker product (otimes)-(@*) :: Trans r -> Trans r -> Trans r--- merge identity transforms-(Id n) @* (Id m) = Id (n*m)--- Id on left or right-i@(Id n) @* (TSnoc g' (g, l, r)) = TSnoc (i @* g') (g, n*l, r)-(TSnoc f' (f, l, r)) @* i@(Id n) = TSnoc (f' @* i) (f, l, r*n)--- no Ids: compose-f @* g = (f @* Id (dim g)) .* (Id (dim f) @* g)--evalC :: (Unbox r) => TransC r -> Array U DIM1 r -> Array U DIM1 r-evalC (Tensorable d f, _, r) arr =-  arr `deepSeqArray` force $ unexpose r $ f $ expose d r arr---- | Creates an evaluatable Haskell function from a tensored transform-eval :: (Unbox r) => Tagged m (Trans r) -> Arr m r -> Arr m r-eval x = coerce $ eval' $ untag x-  where eval' (Id _) = id-        eval' (TSnoc rest f) = eval' rest . evalC f---- | Monadic version of 'eval'-evalM :: (Unbox r, Monad mon) => TaggedT m mon (Trans r) -> mon (Arr m r -> Arr m r)-evalM = liftM (eval . return) . untagT----- | maps the innermost dimension to a 2-dim array with innermost dim d,--- for performing a I_l \otimes f_d \otimes I_r transformation-expose !d !r !arr =-  let (sh :. sz) = extent arr-      f (s :. i :. j) = let imodr = i `mod` r-                            idx = (i-imodr)*d + j*r + imodr-                        in arr ! (s :. idx)-  in fromFunction (sh :. sz `div` d :. d) f---- | inverse of expose-unexpose !r !arr =-  let (sh:.sz:.d) = extent arr-      f (s :. i) = let (idivr,imodr) = i `divMod` r-                       (idivrd,j) = idivr `divMod` d-                   in arr ! (s :. r*idivrd + imodr :. j)-  in fromFunction (sh :. sz*d) f---- | general matrix multiplication along innermost dim of v-mulMat :: (Source r1 r, Source r2 r, Ring r, Unbox r, Elt r)-          => Array r1 DIM2 r -> Array r2 DIM2 r -> Array D DIM2 r-mulMat !m !v-  = let (Z :. mrows :. mcols) = extent m-        (sh :. vrows) = extent v-        f (sh' :. i) = sumAllS $ R.zipWith (*) (slice m (Z:.i:.All)) $ slice v (sh':.All)-    in if mcols == vrows then fromFunction (sh :. mrows) f-       else error "mulMatVec: mcols != vdim"---- | multiplication by a diagonal matrix along innermost dim-mulDiag :: (Source r1 r, Source r2 r, Ring r, Unbox r, Elt r)-           => Array r1 DIM1 r -> Array r2 DIM2 r -> Array D DIM2 r-mulDiag !diag !arr = fromFunction (extent arr) f-  where f idx@(_ :. i) = arr! idx * diag! (Z:.i)---- misc Tensor functions---- | Embeds a scalar into a powerful-basis representation of a Repa array,--- tagged by the cyclotomic index-scalarPow' :: forall m r . (Fact m, Additive r, Unbox r) => r -> Arr m r-scalarPow' = coerce . (go $ proxy totientFact (Proxy::Proxy m))-  where go n !r = let fct (Z:.0) = r-                      fct _ = LP.zero-                  in force $ fromFunction (Z:.n) fct---- | Forces a delayed array to a manifest array.-force :: (Shape sh, Unbox r) => Array D sh r -> Array U sh r--- CJP: computeS just until we figure out how to avoid nested parallel--- computation!---force = computeS-force = runIdentity . computeP---- copied implementations of functions we need that normally require--- Num---- | Sum the inner-most dimension of an array sequentially-sumS :: (Source r a, Elt a, Unbox a, Additive a, Shape sh)-  => Array r (sh :. Int) a-  -> Array U sh a-sumS = foldS (+) LP.zero---- | Sum all array indices to a scalar sequentially-sumAllS :: (Shape sh, Source r a, Elt a, Unbox a, Additive a)-  => Array r sh a-  -> a-sumAllS = foldAllS (+) LP.zero
− src/Crypto/Lol/Cyclotomic/UCyc.hs
@@ -1,700 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, DeriveDataTypeable,-             FlexibleContexts, FlexibleInstances, GADTs, InstanceSigs,-             MultiParamTypeClasses, NoImplicitPrelude, PolyKinds,-             RankNTypes, RebindableSyntax, ScopedTypeVariables,-             TypeFamilies, TypeOperators, UndecidableInstances #-}---- | An implementation of cyclotomic rings.  WARNING: this module--- provides an experts-only, "unsafe" interface that may result in--- runtime errors if not used correctly!--- 'Crypto.Lol.Cyclotomic.Cyc.Cyc' provides a safe interface, and--- should be used in applications whenever possible.------ 'UCyc' transparently handles all necessary conversions between--- internal representations to support fast ring operations, and--- efficiently stores and operates upon elements that are known to--- reside in subrings.------ The 'Functor', 'Applicative', 'Foldable', and 'Traversable'--- instances of 'UCyc', as well as the 'fmapC' and 'fmapCM' functions,--- work over the element's /current/ @r@-basis representation (or--- 'pure' scalar representation as a special case, to satisfy the--- 'Applicative' laws), and the output remains in that representation.--- If the input's representation is not one of these, the behavior is--- a runtime error.  To ensure a valid representation when using the--- methods from these classes, first call 'forceBasis' or one of its--- specializations ('forcePow', 'forceDec', 'forceAny').--module Crypto.Lol.Cyclotomic.UCyc-(--- * Data type-  UCyc, CElt, RElt--- * Basic operations-, mulG, divG-, scalarCyc, liftCyc-, adviseCRT--- * Error sampling-, tGaussian, errorRounded, errorCoset--- * Sub/extension rings-, embed, twace, coeffsCyc, powBasis, crtSet--- * Representations-, forceBasis, forcePow, forceDec, forceAny--- * Specialized maps-, fmapC, fmapCM-, U.Basis(..), U.RescaleCyc-) where--import           Crypto.Lol.CRTrans-import           Crypto.Lol.Cyclotomic.Tensor  as T-import qualified Crypto.Lol.Cyclotomic.Utility as U-import           Crypto.Lol.Gadget-import           Crypto.Lol.LatticePrelude     as LP hiding ((*>))-import           Crypto.Lol.Types.FiniteField-import           Crypto.Lol.Types.ZPP--import Algebra.Additive     as Additive (C)-import Algebra.Ring         as Ring (C)-import Algebra.ZeroTestable as ZeroTestable (C)--import Control.Applicative-import Control.DeepSeq-import Control.Monad.Identity-import Control.Monad.Random-import Data.Coerce-import Data.Foldable          as F-import Data.Maybe-import Data.Traversable-import Data.Typeable-import Test.QuickCheck----import qualified Debug.Trace as DT---- | A data type for representing cyclotomic rings such as @Z[zeta]@,--- @Zq[zeta]@, and @Q(zeta)@: @t@ is the 'Tensor' type for storing--- coefficients; @m@ is the cyclotomic index; @r@ is the base ring of--- the coefficients (e.g., @Z@, @Zq@).-data UCyc t (m :: Factored) r where-  Pow  :: !(t m r) -> UCyc t m r -- representation wrt powerful basis-  Dec  :: !(t m r) -> UCyc t m r -- decoding basis--  -- Invariant: use CRTr iff crtFuncs exists for (t m r);-  -- otherwise use CRTe (because crtFuncs is guaranteed to exist for-  -- (t m (CRTExt r))-  CRTr :: !(t m r) -> UCyc t m r -- wrt CRT basis over r, if it exists-  CRTe :: !(t m (CRTExt r)) -> UCyc t m r -- wrt CRT basis over r-extension--  -- super-optimized storage of scalars-  Scalar :: !r -> UCyc t m r--  -- optimized storage of subring elements-  Sub  :: (l `Divides` m) => !(UCyc t l r) -> UCyc t m r---  --EAC: Consider this representation for product rings, but beware of combinatorial explosion of cases.-  --Product :: !(UCyc t m a) -> !(UCyc t m b) -> UCyc t m (a,b)-  deriving (Typeable)---- | Shorthand for frequently reused constraints that are needed for---  change of basis.-type UCCtx t r = (Tensor t, RElt t r, RElt t (CRTExt r), CRTEmbed r)---- | Collection of constraints need to work on most functions over a--- particular base ring @r@.-type RElt t r = (TElt t r, CRTrans r, IntegralDomain r, ZeroTestable r, NFData r)---- | Shorthand for frequently reused constraints that are needed for--- most functions involving 'UCyc' and--- 'Crypto.Lol.Cyclotomic.Cyc.Cyc'.-type CElt t r = (Tensor t, RElt t r, RElt t (CRTExt r),-                 CRTEmbed r, Eq r, Random r)---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.scalarCyc', but for 'UCyc'.-scalarCyc :: (Fact m, CElt t a) => a -> UCyc t m a-scalarCyc = Scalar---- Eq instance-instance (UCCtx t r, Fact m, Eq r) => Eq (UCyc t m r) where-  -- handle same bases when fidelity allows (i.e., *not* CRTe basis)-  (Scalar v1) == (Scalar v2) = v1 == v2-  (Pow v1) == (Pow v2) = v1 == v2 \\ witness entailEqT v1-  (Dec v1) == (Dec v2) = v1 == v2 \\ witness entailEqT v1-  (CRTr v1) == (CRTr v2) = v1 == v2 \\ witness entailEqT v1--  -- compare in compositum-  (Sub (c1 :: UCyc t l1 r)) == (Sub (c2 :: UCyc t l2 r)) =-    (embed' c1 :: UCyc t (FLCM l1 l2) r) == embed' c2-    \\ lcmDivides (Proxy::Proxy l1) (Proxy::Proxy l2)--  -- otherwise compare in power basis for fidelity, which involves-  -- the most efficient transforms in all cases-  p1 == p2 = toPow' p1 == toPow' p2------------ Numeric Prelude instances -------------- ZeroTestable instance-instance (UCCtx t r, Fact m) => ZeroTestable.C (UCyc t m r) where-  isZero (Scalar v) = isZero v-  isZero (Pow v) = isZero v \\ witness entailZTT v-  isZero (Dec v) = isZero v \\ witness entailZTT v-  isZero (CRTr v) = isZero v \\ witness entailZTT v-  isZero x@(CRTe _) = isZero $ toPow' x-  isZero (Sub c) = isZero c---- Additive instance-instance (UCCtx t r, Fact m) => Additive.C (UCyc t m r) where--  zero = Scalar zero--  -- optimized addition of zero-  (Scalar c1) + v2 | isZero c1 = v2-  v1 + (Scalar c2) | isZero c2 = v1--  -- SAME CONSTRUCTORS-  (Scalar c1) + (Scalar c2) = Scalar (c1+c2)-  (Pow v1) + (Pow v2) = Pow $ v1 + v2 \\ witness entailRingT v1-  (Dec v1) + (Dec v2) = Dec $ v1 + v2 \\ witness entailRingT v1-  (CRTr v1) + (CRTr v2) = CRTr $ v1 + v2 \\ witness entailRingT v1-  (CRTe v1) + (CRTe v2) = CRTe $ v1 + v2 \\ witness entailRingT v1-  -- Sub plus Sub: work in compositum-  (Sub (c1 :: UCyc t m1 r)) + (Sub (c2 :: UCyc t m2 r)) =-    (Sub $ (embed' c1 :: UCyc t (FLCM m1 m2) r) + embed' c2)-    \\ lcm2Divides (Proxy::Proxy m1) (Proxy::Proxy m2) (Proxy::Proxy m)--  -- SCALAR PLUS SOMETHING ELSE--  p1@(Scalar _) + p2@(Pow _) = toPow' p1 + p2-  p1@(Scalar _) + p2@(Dec _) = toDec' p1 + p2-  p1@(Scalar _) + p2@(CRTr _) = toCRT' p1 + p2-  p1@(Scalar _) + p2@(CRTe _) = toCRT' p1 + p2-  (Scalar c1) + (Sub c2) = Sub $ Scalar c1 + c2 -- must re-wrap Scalar!--  p1@(Pow _) + p2@(Scalar _) = p1 + toPow' p2-  p1@(Dec _) + p2@(Scalar _) = p1 + toDec' p2-  p1@(CRTr _) + p2@(Scalar _) = p1 + toCRT' p2-  p1@(CRTe _) + p2@(Scalar _) = p1 + toCRT' p2-  (Sub c1) + (Scalar c2) = Sub $ c1 + Scalar c2--  -- SUB PLUS NON-SUB, NON-SCALAR: work in full ring-  (Sub c1) + c2 = embed' c1 + c2-  c1 + (Sub c2) = c1 + embed' c2--  -- mixed Dec and Pow: use linear time conversions-  p1@(Dec _) + p2@(Pow _) = toPow' p1 + p2-  p1@(Pow _) + p2@(Dec _) = p1 + toPow' p2--  -- one CRTr: convert other to CRTr-  p1@(CRTr _) + p2 = p1 + toCRT' p2-  p1 + p2@(CRTr _) = toCRT' p1 + p2--  -- else, one is CRTe: convert both to Pow for fidelity and best-  -- efficiency-  p1 + p2 = toPow' p1 + toPow' p2--  negate (Scalar c) = Scalar (negate c)-  negate (Pow v) = Pow $ fmapT negate v-  negate (Dec v) = Dec $ fmapT negate v-  negate (CRTr v) = CRTr $ fmapT negate v-  negate (CRTe v) = CRTe $ fmapT negate v-  negate (Sub c) = Sub $ negate c---- Ring instance-instance (UCCtx t r, Fact m) => Ring.C (UCyc t m r) where--  one = Scalar one--  -- optimized mul-by-zero-  v1@(Scalar c1) * _ | isZero c1 = v1-  _ * v2@(Scalar c2) | isZero c2 = v2--  -- BOTH IN A CRT BASIS-  (CRTr v1) * (CRTr v2) = CRTr $ v1 * v2 \\ witness entailRingT v1-  (CRTe v1) * (CRTe v2) = toPow' $ CRTe $ v1 * v2 \\ witness entailRingT v1--  -- CRTr/CRTe mixture-  (CRTr _) * (CRTe _) = error "UCyc.(*): mixed CRTr/CRTe"-  (CRTe _) * (CRTr _) = error "UCyc.(*): mixed CRTr/CRTe"--  -- AT LEAST ONE SCALAR-  (Scalar c1) * (Scalar c2) = Scalar $ c1 * c2--  (Scalar c) * (Pow v) = Pow $ fmapT (*c) v-  (Scalar c) * (Dec v) = Dec $ fmapT (*c) v-  (Scalar c) * (CRTr v) = CRTr $ fmapT (*c) v-  (Scalar c) * (CRTe v) = CRTe $ fmapT (* toExt c) v-  (Scalar c1) * (Sub c2) = Sub $ Scalar c1 * c2--  (Pow v) * (Scalar c) = Pow $ fmapT (*c) v-  (Dec v) * (Scalar c) = Dec $ fmapT (*c) v-  (CRTr v) * (Scalar c) = CRTr $ fmapT (*c) v-  (CRTe v) * (Scalar c) = CRTe $ fmapT (* toExt c) v-  (Sub c1) * (Scalar c2) = Sub $ c1 * Scalar c2--  -- TWO SUBS: work in a CRT rep for compositum-  (Sub (c1 :: UCyc t m1 r)) * (Sub (c2 :: UCyc t m2 r)) =-    -- re-wrap c1, c2 as Subs of the composition, and force them to CRT-    (Sub $ (toCRT' $ Sub c1 :: UCyc t (FLCM m1 m2) r) * toCRT' (Sub c2))-    \\ lcm2Divides (Proxy::Proxy m1) (Proxy::Proxy m2) (Proxy::Proxy m)--  -- ELSE: work in appropriate CRT rep-  p1 * p2 = toCRT' p1 * toCRT' p2--  fromInteger = Scalar . fromInteger---- reduces in any basis-instance (Reduce a b, Fact m, CElt t a, CElt t b)-  => Reduce (UCyc t m a) (UCyc t m b) where--  -- optimized for subring constructors-  reduce (Scalar c) = Scalar $ reduce c-  reduce (Sub (c :: UCyc t l a)) = Sub (reduce c :: UCyc t l b)-  reduce x = fmapC reduce $ forceAny x---- promote Gadget from base ring-instance (Gadget gad zq, Fact m, CElt t zq) => Gadget gad (UCyc t m zq) where-  gadget = (scalarCyc <$>) <$> gadget-  -- specialization of 'encode', done efficiently (via 'adviseCRT').-  encode s = ((* adviseCRT s) <$>) <$> gadget---- promote Decompose, using the powerful basis-instance (Decompose gad zq, Fact m,-         -- these imply (superclass) Reduce on UCyc; needed for Sub case-          CElt t zq, CElt t (DecompOf zq), Reduce (DecompOf zq) zq)-  => Decompose gad (UCyc t m zq) where--  type DecompOf (UCyc t m zq) = UCyc t m (DecompOf zq)--  -- faster implementations: decompose directly in subring, which is-  -- correct because we decompose in powerful basis-  decompose (Scalar c) = pasteT $ Scalar <$> peelT (decompose c)-  decompose (Sub c) = pasteT $ Sub <$> peelT (decompose c)--  -- traverse: Traversable (c m) and Applicative (Tagged gad ZL)-  decompose x = fromZL $ traverse (toZL . decompose) $ forcePow x-    where toZL :: Tagged s [a] -> TaggedT s ZipList a-          toZL = coerce-          fromZL :: TaggedT s ZipList a -> Tagged s [a]-          fromZL = coerce---- promote Correct, using the decoding basis-instance (Correct gad zq, Fact m, CElt t zq)-         => Correct gad (UCyc t m zq) where-  -- sequenceA: Applicative (c m) and Traversable (TaggedT [])-  correct bs = (correct . pasteT) <$> sequenceA (forceDec <$> peelT bs)---- generic RescaleCyc instance--instance {-# OVERLAPS #-} (Rescale a b, CElt t a, CElt t b)-         => U.RescaleCyc (UCyc t) a b where--  -- Optimized for subring constructors, for powerful basis.-  -- Analogs for decoding basis are not quite correct, because (* -1)-  -- doesn't commute with 'rescale' due to tiebreakers!-  rescaleCyc U.Pow (Scalar c) = Scalar $ rescale c-  rescaleCyc U.Pow (Sub (c :: UCyc t l a)) =-    Sub (U.rescaleCyc U.Pow c :: UCyc t l b)--  rescaleCyc b x = fmapC rescale $ forceBasis (Just b) x---- specialized instance for product rings: ~2x faster algorithm-instance (Mod a, Field b, Lift a (ModRep a), Reduce (LiftOf a) b,-          CElt t a, CElt t b, CElt t (a,b), CElt t (LiftOf a))-         => U.RescaleCyc (UCyc t) (a,b) b where--  -- optimized for subrings and powerful basis (see comments in other-  -- instance for why this doesn't work for decoding basis)-  rescaleCyc U.Pow (Scalar c) = Scalar $ rescale c-  rescaleCyc U.Pow (Sub (c :: UCyc t l (a,b))) =-    Sub (U.rescaleCyc U.Pow c :: UCyc t l b)--  rescaleCyc bas x =-    let aval = proxy modulus (Proxy::Proxy a)-  -- CJP: could use unzipC here to get (a,b) in one pass, but it-  -- requires adding that method, and unzipT to Tensor and all its-  -- instances. Probably not worth it.-        y = forceAny x-        a = fmapC fst y-        b = fmapC snd y-        z = liftCyc bas a-    in Scalar (recip (reduce aval)) * (b - reduce z)---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.liftCyc', but for 'UCyc'.-liftCyc :: (Lift b a, Fact m, CElt t a, CElt t b)-           => U.Basis -> UCyc t m b -> UCyc t m a--- optimized for subrings and powerful basis (see comments in--- RescaleCyc instances for why this doesn't work for decoding)-liftCyc U.Pow (Scalar c) = Scalar $ lift c-liftCyc U.Pow (Sub c) = Sub $ liftCyc U.Pow c--liftCyc U.Pow x = fmapC lift $ forceBasis (Just U.Pow) x-liftCyc U.Dec x = fmapC lift $ forceBasis (Just U.Dec) x---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.adviseCRT', but for 'UCyc'.-adviseCRT :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r-adviseCRT x@(Scalar _) = x-adviseCRT (Sub c) = Sub $ adviseCRT c-adviseCRT x = toCRT' x---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.mulG', but for 'UCyc'.-mulG :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r-mulG (Scalar c) = Pow $ mulGPow $ scalarPow c -- must go to full ring-mulG (Sub c) = mulG $ embed' c                -- must go to full ring-mulG (Pow v) = Pow $ mulGPow v-mulG (Dec v) = Dec $ mulGDec v--- fromMaybe is safe here because we're already in CRTr-mulG (CRTr v) = CRTr $ fromJust' "UCyc.mulG CRTr" mulGCRT v-mulG (CRTe v) = CRTe $ fromJust' "UCyc.mulG CRTe" mulGCRT v---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.divG', but for 'UCyc'.-divG :: (Fact m, CElt t r) => UCyc t m r -> Maybe (UCyc t m r)-divG (Scalar c) = liftM Pow (divGPow $ scalarPow c) -- full ring-divG (Sub c) = divG $ embed' c                      -- full ring-divG (Pow v) = Pow <$> divGPow v-divG (Dec v) = Dec <$> divGDec v--- fromMaybe is safe here because we're already in CRTr-divG (CRTr v) = Just $ CRTr $ fromJust' "UCyc.divG CRTr" divGCRT v-divG (CRTe v) = Just $ CRTe $ fromJust' "UCyc.divG CRTe" divGCRT v---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.tGaussian', but for 'UCyc'.-tGaussian :: (Fact m, OrdFloat q, Random q, CElt t q,-              ToRational v, MonadRandom rnd)-             => v -> rnd (UCyc t m q)-tGaussian = liftM Dec . tGaussianDec---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.errorRounded', but for 'UCyc'.-errorRounded :: forall v rnd t m z .-                (ToInteger z, Fact m, CElt t z, ToRational v, MonadRandom rnd)-                => v -> rnd (UCyc t m z)-errorRounded svar =-  fmapC (roundMult one) <$> (tGaussian svar :: rnd (UCyc t m Double))---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.errorCoset', but for 'UCyc'.-errorCoset :: forall t m zp z v rnd .-  (Mod zp, z ~ ModRep zp, Lift zp z, Fact m,-   CElt t zp, CElt t z, ToRational v, MonadRandom rnd)-  => v -> UCyc t m zp -> rnd (UCyc t m z)-errorCoset =-  let pval = fromIntegral $ proxy modulus (Proxy::Proxy zp)-  -- we don't force* here because tGaussian is always in Dec-  in \ svar c ->-    roundCosetDec c <$> (tGaussian (svar * pval * pval) :: rnd (UCyc t m Double))---- | Deterministically round to the given coset @c+pR@, using the--- decoding basis.-roundCosetDec ::-    (Mod zp, z ~ ModRep zp, Lift zp z, RealField q,-     Fact m, CElt t q, CElt t zp, CElt t z)-    => UCyc t m zp -> UCyc t m q -> UCyc t m z-roundCosetDec c x = roundCoset <$> forceDec c <*> forceDec x---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.embed', but for 'UCyc'.-embed :: forall t r m m' . (m `Divides` m') => UCyc t m r -> UCyc t m' r-embed (Scalar c) = Scalar c-embed (Sub (c :: UCyc t l r)) = Sub c-  \\ transDivides (Proxy::Proxy l) (Proxy::Proxy m) (Proxy::Proxy m')-embed c = Sub c---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.twace', but for 'UCyc'.-twace :: forall t r m m' . (UCCtx t r, m `Divides` m')-         => UCyc t m' r -> UCyc t m r-twace (Scalar c) = Scalar c--- twace on Sub goes to the largest common subring of O_l and O_m-twace (Sub (c :: UCyc t l r)) =-  Sub (twace c :: UCyc t (FGCD l m) r)-  \\ gcdDivides (Proxy::Proxy l) (Proxy::Proxy m)-twace (Pow v) = Pow $ twacePowDec v-twace (Dec v) = Dec $ twacePowDec v--- stay in CRTr only iff it's valid for target, else go to Pow-twace x@(CRTr v) =-  fromMaybe (twace $ toPow' x) (CRTr <$> (twaceCRT <*> pure v))--- stay in CRTe iff CRTr is invalid for target, else go to Pow-twace x@(CRTe v) =-  fromMaybe (CRTe $ fromJust' "UCyc.twace CRTe" twaceCRT v)-            (proxy (pasteT hasCRTFuncs) (Proxy::Proxy (t m r)) *>-             pure (twace $ toPow' x))---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.coeffsCyc', but for 'UCyc'.-coeffsCyc :: (m `Divides` m', CElt t r)-             => U.Basis -> UCyc t m' r -> [UCyc t m r]-coeffsCyc U.Pow (Pow v) = LP.map Pow $ coeffs v-coeffsCyc U.Dec (Dec v) = LP.map Dec $ coeffs v-coeffsCyc U.Pow x = coeffsCyc U.Pow $ toPow' x-coeffsCyc U.Dec x = coeffsCyc U.Dec $ toDec' x---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.powBasis', but for 'UCyc'.-powBasis :: (m `Divides` m', CElt t r) => Tagged m [UCyc t m' r]-powBasis = map Pow <$> powBasisPow---- | Same as 'Crypto.Lol.Cyclotomic.Cyc.crtSet', but for 'UCyc'.-crtSet :: forall t m m' r p mbar m'bar .-           (m `Divides` m', ZPP r, p ~ CharOf (ZPOf r),-            mbar ~ PFree p m, m'bar ~ PFree p m',-            CElt t r, CElt t (ZPOf r))-           => Tagged m [UCyc t m' r]-crtSet =-  -- CJP: consider using traceEvent or traceMarker-  --DT.trace ("UCyc.fcCrtSet: m = " ++-  --          show (proxy valueFact (Proxy::Proxy m)) ++ ", m'= " ++-  --          show (proxy valueFact (Proxy::Proxy m'))) $-  let (p,e) = proxy modulusZPP (Proxy::Proxy r)-      pp = Proxy::Proxy p-      pm = Proxy::Proxy m-      pm' = Proxy::Proxy m'-  in retag (fmap (embed . (^(p^(e-1))) . Dec . fmapT liftZp) <$>-            (crtSetDec :: Tagged mbar [t m'bar (ZPOf r)]))-     \\ pFreeDivides pp pm pm'-     \\ pSplitTheorems pp pm \\ pSplitTheorems pp pm'------- "Unsafe" functions that expose or rely upon internal representation---- | Yield an equivalent element whose internal representation /must/--- be in the indicated basis: powerful or decoding (for 'Just' 'Pow'--- and 'Just' 'Dec' arguments, respectively), or any @r@-basis of the--- implementation's choice (for 'Nothing' argument).  (See also the--- convenient specializations 'forcePow', 'forceDec', 'forceAny'.)-forceBasis :: (Fact m, CElt t r) => Maybe U.Basis -> UCyc t m r -> UCyc t m r-forceBasis (Just U.Pow) x = toPow' x-forceBasis (Just U.Dec) x = toDec' x-forceBasis Nothing x@(Scalar _) = toPow' x--- force as outermost op to ensure we get an r-basis-forceBasis Nothing (Sub c) = forceBasis Nothing $ embed' c-forceBasis Nothing x@(CRTe _) = toPow' x-forceBasis Nothing x = x--forcePow, forceDec, forceAny :: (Fact m, CElt t r) => UCyc t m r -> UCyc t m r--- | Force a cyclotomic element into the powerful basis.-forcePow = forceBasis (Just U.Pow)--- | Force a cyclotomic element into the decoding basis.-forceDec = forceBasis (Just U.Dec)--- | Force a cyclotomic into any @r@-basis of the implementation's--- choice.-forceAny = forceBasis Nothing---- | A more specialized version of 'fmap': apply a function--- coordinate-wise in the current representation.  The caller must--- ensure that the current representation is an @r@-basis (one of--- powerful, decoding, or CRT, if it exists), usually by using--- 'forceBasis' or its specializations ('forcePow', 'forceDec',--- 'forceAny').  Otherwise, behavior is undefined.-fmapC :: (Fact m, CElt t a, CElt t b) => (a -> b) -> UCyc t m a -> UCyc t m b---- must be in an r-basis for correct semantics, e.g., f 0 = 1-fmapC _ (Scalar _) = error "can't fmapC on Scalar.  Must forceBasis first!"-fmapC _ (Sub _) = error "can't fmapC on Sub.  Must forceBasis first!"-fmapC _ (CRTe _) = error "can't fmapC on CRTe.  Must forceBasis first!"--fmapC f (Pow v) = Pow $ fmapT f v-fmapC f (Dec v) = Dec $ fmapT f v-fmapC f (CRTr v) = CRTr $ fmapT f v---- | Monadic version of 'fmapC'.-fmapCM :: (Fact m, CElt t a, CElt t b, Monad mon)-  => (a -> mon b) -> UCyc t m a -> mon (UCyc t m b)---- must embed into full ring-fmapCM _ (Scalar _) = error "can't fmapCM on Scalar. Must forceBasis first!"-fmapCM _ (Sub _) = error "can't fmapCM on Sub. Must forceBasis first!"-fmapCM _ (CRTe _) =  error "can't fmapCM on CRTe.  Must forceBasis first!"--fmapCM f (Pow v) = liftM Pow $ fmapTM f v-fmapCM f (Dec v) = liftM Dec $ fmapTM f v-fmapCM f (CRTr v) = liftM CRTr $ fmapTM f v--------------- HELPER FUNCTIONS (NOT FOR EXPORT) -------------- | Force embed, to a non-'Sub' constructor.  Preserves Scalar, Pow,--- Dec constructors, and CRTr/CRTe constructor if valid in both source--- and target ring (we rely on this in toCRT').-embed' :: forall t r l m .-          (UCCtx t r, l `Divides` m) => UCyc t l r -> UCyc t m r-embed' (Scalar x) = Scalar x    -- must re-wrap!-embed' (Pow v) = Pow $ embedPow v-embed' (Dec v) = Dec $ embedDec v--- stay in CRTr only if it's possible, otherwise go to Pow-embed' x@(CRTr v) =-    fromMaybe (embed' $ toPow' x) (CRTr <$> (embedCRT <*> pure v))-embed' x@(CRTe v) = -- go to CRTe iff CRTr is invalid for target index-    fromMaybe (CRTe $ fromJust' "UCyc.embed' CRTe" embedCRT v)-              (proxy (pasteT hasCRTFuncs) (Proxy::Proxy (t m r)) *>-               pure (embed' $ toPow' x))-embed' (Sub (c :: UCyc t k r)) = embed' c-  \\ transDivides (Proxy::Proxy k) (Proxy::Proxy l) (Proxy::Proxy m)------------ Basis conversion methods --------------------toPow', toDec' :: (UCCtx t r, Fact m) => UCyc t m r -> UCyc t m r--- forces the argument into the powerful basis-toPow' (Scalar c) = Pow $ scalarPow c-toPow' (Sub c) = embed' $ toPow' c -- OK: embed' preserves Pow-toPow' x@(Pow _) = x-toPow' (Dec v) = Pow $ l v-toPow' (CRTr v) = Pow $ fromJust' "UCyc.toPow'" crtInv v-toPow' (CRTe v) =-    Pow $ fmapT fromExt $ fromJust' "UCyc.toPow' CRTe" crtInv v---- | Force the argument into the decoding basis.-toDec' x@(Scalar _) = toDec' $ toPow' x -- TODO: use scalarDec instead-toDec' (Sub c) = embed' $ toDec' c      -- OK: embed' preserves Dec-toDec' (Pow v) = Dec $ lInv v-toDec' x@(Dec _) = x-toDec' x@(CRTr _) = toDec' $ toPow' x-toDec' x@(CRTe _) = toDec' $ toPow' x---- | Force the argument into the "valid" CRT basis for our invariant.-toCRT' :: forall t m r . (UCCtx t r, Fact m) => UCyc t m r -> UCyc t m r-toCRT' x@(CRTr _) = x-toCRT' x@(CRTe _) = x-toCRT' (Sub (c :: UCyc t l r)) =-    case (proxyT hasCRTFuncs (Proxy::Proxy (t l r)),-          proxyT hasCRTFuncs (Proxy::Proxy (t m r))) of-      (Just _, Just _) -> embed' $ toCRT' c -- fastest; embed' preserves CRTr-      (_, Nothing) -> embed' $ toCRTe c -- faster; temp violate CRTr/e invariant-      _ -> toCRT' $ embed' c            -- fallback-toCRT' x = fromMaybe (toCRTe x) (toCRTr <*> pure x)--toCRTr :: forall t m r . (UCCtx t r, Fact m) => Maybe (UCyc t m r -> UCyc t m r)-toCRTr = do -- Maybe monad-  crt' <- crt-  scalarCRT' <- scalarCRT-  return $ \x -> case x of-                   (Scalar c) -> CRTr $ scalarCRT' c-                   (Pow v) -> CRTr $ crt' v-                   (Dec v) -> CRTr $ crt' $ l v-                   c@(CRTr _) -> c-                   c@(CRTe _) -> fromJust' "UCyc.toCRTr CRTe" toCRTr $ toPow' c-                   (Sub _) -> error "UCyc.toCRTr: Sub"--toCRTe :: forall t m r . (UCCtx t r, Fact m) => UCyc t m r -> UCyc t m r-toCRTe = let m = proxy valueFact (Proxy::Proxy m)-             crt' = fromJust' ("UCyc.toCRTe: no crt': " ++ show m) crt-                  :: t m (CRTExt r) -> t m (CRTExt r) -- must exist-             scalarCRT' = fromJust' "UCyc.toCRTe: no scalarCRT" scalarCRT-                        :: CRTExt r -> t m (CRTExt r)-         in \x -> case x of-                    (Scalar c) -> CRTe $ scalarCRT' $ toExt c-                    (Pow v) -> CRTe $ crt' $ fmapT toExt v-                    (Dec v) -> CRTe $ crt' $ fmapT toExt $ l v-                    c@(CRTr _) -> toCRTe $ toPow' c-                    c@(CRTe _) -> c-                    (Sub _) -> error "UCyc.toCRTe: Sub"------------ "Container" instances ------------instance (Tensor t, Fact m) => Functor (UCyc t m) where-  -- Functor instance is implied by Applicative laws-  fmap f x = pure f <*> x--errApp :: String -> a-errApp name = error $ "UCyc.Applicative: can't/won't handle " ++ name ++-              "; call forcePow|Dec|Any first"--instance (Tensor t, Fact m) => Applicative (UCyc t m) where--  -- This implementation is restricted to the Scalar, Pow, Dec, or-  -- CRTr constructors, in order to force the client to choose a-  -- concrete @r@-basis and avoid unanticipated non-failure behavior.-  -- Encountering a CRTe, or Sub constructor almost certainly means-  -- that the client expressed something it did not intend (since it-  -- cannot force such constructors to be used), so we want to raise-  -- an exception early instead of doing unintended work.--  -- This implementation has one corner case that may-  -- yield unexpected non-failure behavior: consider-  --   fmap f (pure a) = (pure f) <*> (pure a) = (pure $ f a)-  -- which is required by the Applicative homomorphism law.--  -- If the (pure a) is intended as an element of the base ring (which-  -- is the custom), then its Pow coeffs are *not* all a's, so the-  -- (likely intended) expression-  --   fmap f $ forcePow (pure a)-  -- may be a different result.  If the client forgets the force, we-  -- can't recognize it here and throw an error.  (This is certainly the-  -- client's fault; if it's not specifying a basis before fmap'ing-  -- then it shouldn't expect the results to make sense.  We just-  -- can't catch the error here.)--  -- A solution is to introduce an explicit Pure constructor that's-  -- only ever applied in 'pure', and throw an error if we encounter a-  -- Scalar here.  Arithmetically we'd treat Pures as Scalars, but in-  -- a one-way fashion (outputs of arith ops are never Pure).--  pure = Scalar--  -- homomorphism (of pure)-  (Scalar f) <*> (Scalar a) = Scalar $ f a--  -- constructors must match-  (Pow v1) <*> (Pow v2) = Pow $ v1 <*> v2 \\ witness entailIndexT v1-  (Dec v1) <*> (Dec v2) = Dec $ v1 <*> v2 \\ witness entailIndexT v1-  (CRTr v1) <*> (CRTr v2) = CRTr $ v1 <*> v2 \\ witness entailIndexT v1--  -- ... but we can also match Scalar with (almost) anything-  (Scalar f) <*> (Pow v) = Pow $ pure f <*> v \\ witness entailIndexT v-  (Scalar f) <*> (Dec v) = Dec $ pure f <*> v \\ witness entailIndexT v-  (Scalar f) <*> (CRTr v) = CRTr $ pure f <*> v \\ witness entailIndexT v--  (Pow v) <*> (Scalar a) = Pow $ v <*> pure a \\ witness entailIndexT v-  (Dec v) <*> (Scalar a) = Dec $ v <*> pure a \\ witness entailIndexT v-  (CRTr v) <*> (Scalar a) = CRTr $ v <*> pure a \\ witness entailIndexT v--  -- cases we can't/won't handle-  (Sub _) <*> _  = errApp "Sub"-  _ <*> (Sub _)  = errApp "Sub"-  (CRTe _) <*> _ = errApp "CRTe"-  _ <*> (CRTe _) = errApp "CRTe"-  _ <*> _ = errApp "mismatched Pow/Dec/CRTr bases"--instance (Tensor t, Fact m) => Foldable (UCyc t m) where-  foldr f b (Scalar r) = f r b-  foldr f b (Sub c) = F.foldr f b c-  foldr f b (Pow v) = F.foldr f b v \\ witness entailIndexT v-  foldr f b (Dec v) = F.foldr f b v \\ witness entailIndexT v-  foldr f b (CRTr v) = F.foldr f b v \\ witness entailIndexT v-  foldr _ _ (CRTe _) = error "UCyc.Foldable: can't handle CRTe"--instance (Tensor t, Fact m) => Traversable (UCyc t m) where-  traverse f (Scalar r) = Scalar <$> f r-  traverse f (Sub c) = Sub <$> traverse f c-  traverse f (Pow v) = Pow <$> traverse f v \\ witness entailIndexT v-  traverse f (Dec v) = Dec <$> traverse f v \\ witness entailIndexT v-  traverse f (CRTr v) = CRTr <$> traverse f v \\ witness entailIndexT v-  traverse _ (CRTe _) = error "UCyc.Traversable: can't handle CRTe"------------ Utility instances ------------instance (Tensor t, Fact m, TElt t r, CRTrans r, Random r, ZeroTestable r, IntegralDomain r) => Random (UCyc t m r) where--  -- create in CRTr basis if legal, otherwise in powerful-  random = let cons = fromMaybe Pow-                      (proxyT hasCRTFuncs (Proxy::Proxy (t m r)) >> Just CRTr)-           in \g -> let (v,g') = random g-                                 \\ proxy entailRandomT (Proxy::Proxy (t m r))-                    in (cons v, g')--  randomR _ = error "randomR non-sensical for cyclotomic rings"--instance (Show r, Show (t m r), Show (t m (CRTExt r)))-  => Show (UCyc t m r) where--  show (Scalar c) = "scalar " ++ show c-  show (Sub _) = "subring (not showing due to missing constraints)"-  show (Pow v) = "powerful basis coeffs " ++ show v-  show (Dec v) = "decoding basis coeffs " ++ show v-  show (CRTr v) = "CRTr basis coeffs " ++ show v-  show (CRTe v) = "CRTe basis coeffs " ++ show v--instance (Arbitrary (t m r)) => Arbitrary (UCyc t m r) where-  arbitrary = liftM Pow arbitrary-  shrink = shrinkNothing--instance (Tensor t, Fact m, TElt t r, TElt t (CRTExt r), NFData r, NFData (CRTExt r))-         => NFData (UCyc t m r) where-  rnf (Pow x)    = rnf x \\ witness entailNFDataT x-  rnf (Dec x)    = rnf x \\ witness entailNFDataT x-  rnf (CRTr x)   = rnf x \\ witness entailNFDataT x-  rnf (CRTe x)   = rnf x \\ witness entailNFDataT x-  rnf (Scalar x) = rnf x-  rnf (Sub x)    = rnf x
− src/Crypto/Lol/Cyclotomic/Utility.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}--module Crypto.Lol.Cyclotomic.Utility where--import Crypto.Lol.Factored--import Control.DeepSeq---- | Represents the powerful or decoding basis.-data Basis = Pow | Dec--instance NFData Basis where-  rnf Pow = ()-  rnf Dec = ()---- | Represents cyclotomic rings that are rescalable over their base--- rings.  (This is a class because it allows for more efficient--- specialized implementations.)--class RescaleCyc c a b where-  -- | Rescale in the given basis.-  rescaleCyc :: Fact m => Basis -> c m a -> c m b
− src/Crypto/Lol/Factored.hs
@@ -1,481 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds,-             GADTs, KindSignatures, PolyKinds,-             ScopedTypeVariables, TemplateHaskell, TypeFamilies,-             TypeOperators, UndecidableInstances #-}---- | This file defines types and operations for type-level--- representation and manipulation of factored integers. It relies on--- TH, so the documentation will be difficult to read. See comments--- for better documentation.--module Crypto.Lol.Factored-(--- * Factored natural numbers-  Factored(..), SFactored, Fact--- * Prime powers-, PrimePower(..), SPrimePower, PPow, Sing (SPP)--- * Naturals-, Nat, NatC, PrimeNat, Prime--- * Constructors-, toPP, sToPP, ToPP, ppToF, sPpToF, PpToF, PToF--- * Unwrappers-, unF, sUnF, UnF, unPP, sUnPP, UnPP, primePP, PrimePP, exponentPP, ExponentPP--- * Arithmetic operations-, fPPMul, FPPMul, fMul, FMul, type (*)-, fDivides, FDivides, Divides, fDiv, FDiv, type (/)-, fGCD, FGCD, fLCM, FLCM, Coprime-, fOddRadical, FOddRadical-, pFree, PFree--- * Reflections-, ppsFact, valueFact, totientFact, valueHatFact, radicalFact, oddRadicalFact-, ppPPow, primePPow, exponentPPow, valuePPow, totientPPow-, valueNatC--- * Number-theoretic laws-, transDivides, gcdDivides, lcmDivides, lcm2Divides-, pSplitTheorems, pFreeDivides-, (\\) -- re-export from Data.Constraint for convenience--- * Utility operations (on prime powers)-, valueHat-, PP, ppToPP, valuePP, totientPP, radicalPP, oddRadicalPP-, valuePPs, totientPPs, radicalPPs, oddRadicalPPs--- * Type synonyms (not type families)-, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10-, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20-, F21, F22, F24, F25, F26, F27, F28, F30-, F32, F33, F34, F35, F36, F38, F39-, F40, F42, F44, F45, F48, F49-, F50, F51, F52, F54, F55, F56, F57-, F60, F63, F64, F65, F66, F68-, F70, F72, F75, F76, F77, F78, F80, F81, F84, F85, F88-, F90, F91, F95, F96, F98, F99-, F128, F256, F512, F1024, F2048-) where--import Data.Constraint hiding ((***))-import Data.Functor.Trans.Tagged-import Data.Singletons.Prelude hiding (sMin, sMax, MinSym0, MaxSym0, (:-))-import Data.Singletons.TH-import Data.Type.Natural         as N hiding ((:-))-import Data.Typeable--import Control.Arrow ((***))-import Unsafe.Coerce---- | Copied from Data.Type.Natural because the data-level version--- is not exported there.-(<<=) :: Nat -> Nat -> Bool-Z   <<= _   = True-S _ <<= Z   = False-S n <<= S m = n <<= m--singletons [d|--            -- Invariant: first component is prime, second component-            -- (the exponent) is positive (nonzero)-            newtype PrimePower = PP (Nat,Nat) deriving (Eq,Show,Typeable)--            -- List invariant: primes appear in strictly increasing-            -- order (no duplicates)-            newtype Factored = F [PrimePower] deriving (Eq,Show,Typeable)--            -- unwrap 'Factored'-            unF :: Factored -> [PrimePower]-            unF (F pps) = pps--            -- unwrap 'PrimePower'-            unPP :: PrimePower -> (Nat,Nat)-            unPP (PP pp) = pp--            -- grab individual components of a 'PrimePower'-            primePP, exponentPP :: PrimePower -> Nat-            primePP = fst . unPP-            exponentPP = snd . unPP--            |]---- SMART CONSTRUCTORS-singletons [d|--            fPPMul :: PrimePower -> Factored -> Factored-            fMul :: Factored -> Factored -> Factored--            -- constructor implementations-            -- multiply a new 'PrimePower' into a 'Factored' number-            fPPMul (PP(_,Z)) y = y -- throw away trivial prime power-            fPPMul pp@(PP(_,S _)) (F pps) = F (ppMul pp pps)--            -- multiply two 'Factored' numbers-            fMul (F pps1) (F pps2) = F (ppsMul pps1 pps2)--            -- helper functions (not for export)--            -- keeps primes in sorted order; merges duplicates--            -- EAC: Singletons(?) doesn't play well with pattern synonyms (e.g. x@(PP(p,e)))-            -- when compiling with -O2-            -- reported as #10924-            -- singletons-2.0 doesn't work well with guards: https://github.com/goldfirere/singletons/issues/131-            ppMul :: PrimePower -> [PrimePower] -> [PrimePower]-            ppMul x [] = [x]-            ppMul (PP(p,e)) (PP (p',e'):pps') =-              if p == p' then PP(p,e + e'):pps'-              else if p <<= p' then (PP(p,e)):(PP (p',e'):pps')-              else (PP(p',e')):ppMul (PP(p,e)) pps'--            ppsMul :: [PrimePower] -> [PrimePower] -> [PrimePower]-            ppsMul [] ys = ys-            ppsMul (pp:pps) ys = ppsMul pps (ppMul pp ys)--            |]---- ARITHMETIC OPERATIONS-singletons [d|-            -- Smart constructor that checks that the first arg is-            -- prime (< 20) and the second arg is positive-            toPP :: Nat -> Nat -> PrimePower-            toPP p e | primeNat p && (n1 <<= e) = PP (p,e)--            -- EAC: isn't there a singletons promotion for 'F'-            -- that could replace this function?-            ppToF :: PrimePower -> Factored-            ppToF pp = F [pp]--            primeToF :: Nat -> Factored-            primeToF p | primeNat p = ppToF $ PP (p, n1)-            -            fGCD, fLCM :: Factored -> Factored -> Factored-            fDivides :: Factored -> Factored -> Bool-            fDiv :: Factored -> Factored -> Factored-            fOddRadical :: Factored -> Factored-            -            -- can't pattern-match on n*, but can test equality-            primeNat n-              | n==n2 = True-              | n==n3 = True-              | n==n5 = True-              | n==n7 = True-              | n==n11 = True-              | n==n13 = True-              | n==n17 = True-              | n==n19 = True-            fGCD (F pps1) (F pps2) = F (ppsGCD pps1 pps2)-            fLCM (F pps1) (F pps2) = F (ppsLCM pps1 pps2)--            fDivides (F pps1) (F pps2) = ppsDivides pps1 pps2-            fDiv (F pps1) (F pps2) = F (ppsDiv pps1 pps2)-            fOddRadical (F pps) = F (ppsOddRad pps)--            -- Helper functions (not for export) on PrimePowers and-            -- lists.  Can assume that input lists obey the invariant-            -- of Factored lists, and need to ensure that output lists-            -- also obey the invariant.-            ppsGCD :: [PrimePower] -> [PrimePower] -> [PrimePower]-            ppsGCD [] [] = []-            ppsGCD [] (_:_) = []-            ppsGCD (_:_) [] = []-            ppsGCD (PP (p,e) : xs') (PP (p',e') : ys') =-              if p == p' then PP (p,N.min e e') : ppsGCD xs' ys'-              else if p <<= p' then ppsGCD xs' (PP (p',e') : ys')-              else ppsGCD (PP (p,e) : xs') ys'--            ppsLCM :: [PrimePower] -> [PrimePower] -> [PrimePower]-            ppsLCM [] [] = []-            ppsLCM [] ys@(_:_) = ys-            ppsLCM xs@(_:_) [] = xs-            ppsLCM ((PP (p,e)) : xs') ((PP (p',e')) : ys') =-              if p == p' then PP (p,N.max e e') : ppsLCM xs' ys'-              else if p <<= p' then (PP (p,e)) : ppsLCM xs' ((PP (p',e')) : ys')-              else (PP (p',e')) : ppsLCM ((PP (p,e)) : xs') ys'--            ppsDivides :: [PrimePower] -> [PrimePower] -> Bool-            ppsDivides [] _ = True-            ppsDivides (_:_) [] = False-            ppsDivides (PP (p,e) : xs') (PP (p',e') : ys') =-              if p == p' then (e <<= e') && ppsDivides xs' ys'-              else not (p <<= p') && ppsDivides (PP (p,e) : xs') ys'--            ppsDiv :: [PrimePower] -> [PrimePower] -> [PrimePower]-            ppsDiv xs [] = xs-            ppsDiv ((PP (p,e)) : xs') (PP (p',e') : ys') =-              if p == p' && e' == e then ppsDiv xs' ys'-              else if p == p' && e' <<= e then PP (p,e-e') : ppsDiv xs' ys'-              else if p <<= p' then (PP (p,e)) : ppsDiv xs' (PP (p',e') : ys')-              else error "type error in ppsDiv"                -- if p' <<= p then it's an error--            ppsOddRad :: [PrimePower] -> [PrimePower]-            ppsOddRad [] = []-            ppsOddRad (PP ((S (S Z)),_) : xs') = ppsOddRad xs'-            -- need to expand to avoid overlapping with previous case-            ppsOddRad (PP (p@(S (S (S _))),_) : xs') = PP (p,n1) : ppsOddRad xs'--            |]--singletons [d|-            -- removes all @p@-factors from a 'Factored'-            pFree :: Nat -> Factored -> Factored-            pFree n (F pps) = F (go pps)-              where go [] = []-                    go (pp@(PP (p,_)) : ps) =-                      if n == p then ps-                      else pp : (go ps)-            |]--singletons [d|--            f1 = F []-            f2 = primeToF n2-            f3 = primeToF n3-            f4 = f2 `fMul` f2-            f5 = primeToF n5-            f6 = f2 `fMul` f3-            f7 = primeToF n7-            f8 = f2 `fMul` f4-            f9 = f3 `fMul` f3-            f10 = f2 `fMul` f5-            f11 = primeToF n11-            f12 = f4 `fMul` f3-            f13 = primeToF n13-            f14 = f2 `fMul` f7-            f15 = f3 `fMul` f5-            f16 = f2 `fMul` f8-            f17 = primeToF n17-            f18 = f2 `fMul` f9-            f19 = primeToF n19-            f20 = f2 `fMul` f10-            f21 = f3 `fMul` f7-            f22 = f2 `fMul` f11-            f24 = f2 `fMul` f12-            f25 = f5 `fMul` f5-            f26 = f2 `fMul` f13-            f27 = f3 `fMul` f9-            f28 = f2 `fMul` f14-            f30 = f2 `fMul` f15-            f32 = f2 `fMul` f16-            f33 = f3 `fMul` f11-            f34 = f2 `fMul` f17-            f35 = f5 `fMul` f7-            f36 = f2 `fMul` f18-            f38 = f2 `fMul` f19-            f39 = f3 `fMul` f13-            f40 = f2 `fMul` f20-            f42 = f2 `fMul` f21-            f44 = f2 `fMul` f22-            f45 = f3 `fMul` f15-            f48 = f2 `fMul` f24-            f49 = f7 `fMul` f7-            f50 = f2 `fMul` f25-            f51 = f3 `fMul` f17-            f52 = f2 `fMul` f26-            f54 = f2 `fMul` f27-            f55 = f5 `fMul` f11-            f56 = f2 `fMul` f28-            f57 = f3 `fMul` f19-            f60 = f2 `fMul` f30-            f63 = f3 `fMul` f21-            f64 = f2 `fMul` f32-            f65 = f5 `fMul` f13-            f66 = f2 `fMul` f33-            f68 = f2 `fMul` f34-            f70 = f2 `fMul` f35-            f72 = f2 `fMul` f36-            f75 = f3 `fMul` f25-            f76 = f2 `fMul` f38-            f77 = f7 `fMul` f11-            f78 = f2 `fMul` f39-            f80 = f2 `fMul` f40-            f81 = f3 `fMul` f27-            f84 = f2 `fMul` f42-            f85 = f5 `fMul` f17-            f88 = f2 `fMul` f44-            f90 = f2 `fMul` f45-            f91 = f7 `fMul` f13-            f95 = f5 `fMul` f19-            f96 = f2 `fMul` f48-            f98 = f2 `fMul` f49-            f99 = f9 `fMul` f11-            f128 = f2 `fMul` f64-            f256 = f2 `fMul` f128-            f512 = f2 `fMul` f256-            f1024 = f2 `fMul` f512-            f2048 = f2 `fMul` f1024-            |]---- | Type (family) synonym for division of 'Factored' types-type a / b = FDiv a b---- | Type (family) synonym for multiplication of 'Factored' types-type a * b = FMul a b---- | Type (family) synonym to create a Factored from a prime Nat-type PToF p = PpToF (ToPP p N1)---- convenience aliases: enforce kind, hide SingI---- | Kind-restricted synonym for 'SingI'. Use this in constraints --- for types requiring a 'Factored' type.-type Fact (m :: Factored) = SingI m---- | Kind-restricted synonym for 'SingI'. Use this in constraints --- for types requiring a 'PrimePower' type.-type PPow (pp :: PrimePower) = SingI pp---- | Kind-restricted synonym for 'SingI'. Use this in constraints --- for types requiring a 'Nat' type.-type NatC (p :: Nat) = SingI p--type Prime p = (NatC p, PrimeNat p ~ 'True)---- | Constraint synonym for divisibility of 'Factored' types-type Divides m m' = (Fact m, Fact m', FDivides m m' ~ 'True)---- | Constraint synonym for coprimality of 'Factored' types-type Coprime m m' = (FGCD m m' ~ F1)---- coercions: using proxy arguments here due to compiler bugs in usage---- coerce any divisibility relationship we want-coerceFDivs :: p m -> p' m' -> (() :- (FDivides m m' ~ True))-coerceFDivs _ _ = Sub $ unsafeCoerce (Dict :: Dict ())---- coerce any GCD we want-coerceGCD :: p a -> p' a' -> p'' a'' -> (() :- (FGCD a a' ~ a''))-coerceGCD _ _ _ = Sub $ unsafeCoerce (Dict :: Dict ())---- | Entails constraint for transitivity of division, i.e.--- if @k|l@ and @l|m@, then @k|m@.-transDivides :: forall k l m . Proxy k -> Proxy l -> Proxy m ->-                ((k `Divides` l, l `Divides` m) :- (k `Divides` m))-transDivides k _ m = Sub Dict \\ coerceFDivs k m---- | Entails constraint for divisibility by GCD, i.e.--- if @g=GCD(m1,m2)@, then @g|m1@ and @g|m2@.-gcdDivides :: forall m1 m2 g . Proxy m1 -> Proxy m2 ->-              ((Fact m1, Fact m2, g ~ FGCD m1 m2) :--               (g `Divides` m1, g `Divides` m2))-gcdDivides m1 m2 =-  Sub $ withSingI (sFGCD (sing :: SFactored m1) (sing :: SFactored m2))-  Dict \\ coerceFDivs (Proxy::Proxy g) m1-       \\ coerceFDivs (Proxy::Proxy g) m2---- | Entails constraint for LCM divisibility, i.e.--- if @l=LCM(m1,m2)@, then @m1|l@ and @m2|l@.-lcmDivides :: forall m1 m2 l . Proxy m1 -> Proxy m2 ->-              ((Fact m1, Fact m2, l ~ FLCM m1 m2) :--               (m1 `Divides` l, m2 `Divides` l))-lcmDivides m1 m2 = -  Sub $ withSingI (sFLCM (sing :: SFactored m1) (sing :: SFactored m2))-  Dict \\ coerceFDivs m1 (Proxy::Proxy l)-       \\ coerceFDivs m2 (Proxy::Proxy l)---- | Entails constraint for LCM divisibility, i.e.--- the LCM of two divisors of @m@ also divides @m@.-lcm2Divides :: forall m1 m2 l m . Proxy m1 -> Proxy m2 -> Proxy m ->-               ((m1 `Divides` m, m2 `Divides` m, l ~ FLCM m1 m2) :--                (m1 `Divides` l, m2 `Divides` l, (FLCM m1 m2) `Divides` m))-lcm2Divides m1 m2 m = -  Sub $ withSingI (sFLCM (sing :: SFactored m1) (sing :: SFactored m2))-  Dict \\ coerceFDivs (Proxy::Proxy (FLCM m1 m2)) m \\ lcmDivides m1 m2---- | Entails basic facts for @p@-free division, i.e.--- if @f@ is @m@ after removing all @p@-factors, then @f|m@ and--- @gcd(f,p)=1@-pSplitTheorems :: forall p m f . Proxy p -> Proxy m ->-                  ((NatC p, Fact m, f ~ PFree p m) :--                   (f `Divides` m, Coprime (PToF p) f))-pSplitTheorems _ m =-  Sub $ withSingI (sPFree (sing :: SNat p) (sing :: SFactored m))-  Dict \\ coerceFDivs (Proxy::Proxy f) m -  \\ coerceGCD (Proxy::Proxy (PToF p)) (Proxy::Proxy f) (Proxy::Proxy F1)---- | Entails basic facts for @p@-free division, i.e.,--- if @m|m'@, then @p-free(m) | p-free(m')@-pFreeDivides :: forall p m m' . Proxy p -> Proxy m -> Proxy m' ->-                ((NatC p, m `Divides` m') :--                 ((PFree p m) `Divides` (PFree p m')))-pFreeDivides _ _ _ =-  Sub $ withSingI (sPFree (sing :: SNat p) (sing :: SFactored m)) $-        withSingI (sPFree (sing :: SNat p) (sing :: SFactored m')) $-        Dict \\ coerceFDivs (Proxy::Proxy (PFree p m)) (Proxy::Proxy (PFree p m'))---- | Type synonym for @(prime :: Int, exponent :: Int)@ pair-type PP = (Int, Int)---- | Value-level prime-power factorization tagged by a 'Factored' type.-ppsFact :: forall m . (Fact m) => Tagged m [PP]-ppsFact = tag $ map ppToPP $ unF $ fromSing (sing :: SFactored m)--valueFact, totientFact, valueHatFact, radicalFact, oddRadicalFact ::-  (Fact m) => Tagged m Int---- | @Int@ representing the value of a 'Factored' type-valueFact = valuePPs <$> ppsFact---- | @Int@ representing the totient of a 'Factored' type's value-totientFact = totientPPs <$> ppsFact---- | @Int@ representing the "hat" of a 'Factored' type's value @m@:--- @m@, if @m@ is odd, or @m/2@ otherwise.-valueHatFact = valueHat <$> valueFact---- | @Int@ representing the radical (product of prime divisors)--- of a 'Factored' type-radicalFact = radicalPPs <$> ppsFact---- | @Int@ representing the odd radical (product of odd prime divisors)--- of a 'Factored' type-oddRadicalFact = oddRadicalPPs <$> ppsFact---- | Reflects a 'PrimePower' type to a 'PP' value-ppPPow :: forall pp . (PPow pp) => Tagged pp PP-ppPPow = tag $ ppToPP $ fromSing (sing :: SPrimePower pp)--primePPow, exponentPPow, valuePPow, totientPPow :: (PPow pp) => Tagged pp Int--- | Reflects the prime component of a 'PrimePower' type-primePPow = fst <$> ppPPow--- | Reflects the exponent component of a 'PrimePower' type-exponentPPow = snd <$> ppPPow--- | @Int@ representing the value of a 'PrimePower' type-valuePPow = valuePP <$> ppPPow--- | @Int@ representing the totient of a 'PrimePower' type's value-totientPPow = totientPP <$> ppPPow---- | @Int@ representing the value of a 'Nat'-valueNatC :: forall p . (NatC p) => Tagged p Int-valueNatC = tag $ sNatToInt (sing :: SNat p)---- | Returns @m@, if @m@ is odd, or @m/2@ otherwise-valueHat :: (Integral i) => i -> i-valueHat m = if m `mod` 2 == 0 then m `div` 2 else m---- | Converts a 'Nat' prime-power pair to an @Int@ prime-power pair-ppToPP :: PrimePower -> PP-ppToPP = (natToInt *** natToInt) . unPP--valuePP, totientPP, radicalPP, oddRadicalPP :: PP -> Int--- | Evaluates a prime-power pair @(p,e)@ to @p^e@-valuePP (p,e) = p^e---- | Euler's totient function of a prime-power pair-totientPP (_,0) = 1-totientPP (p,e) = (p-1)*(p^(e-1))---- | The prime component of a prime-power pair-radicalPP (_,0) = 1-radicalPP (p,_) = p---- | The odd radical of a prime-power pair (p,_):--- p if p is odd,--- 1 if p==2-oddRadicalPP (_,0) = 1-oddRadicalPP (2,_) = 1-oddRadicalPP (p,_) = p--valuePPs, totientPPs, radicalPPs, oddRadicalPPs :: [PP] -> Int--- | Product of values of individual 'PP's-valuePPs = product . map valuePP--- | Product of totients of individual 'PP's-totientPPs = product . map totientPP--- | Product of radicals of individual 'PP's-radicalPPs = product . map radicalPP--- | Product of odd radicals of individual 'PP's-oddRadicalPPs = product . map oddRadicalPP
− src/Crypto/Lol/Gadget.hs
@@ -1,93 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, DeriveDataTypeable,-             FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,-             NoImplicitPrelude, PolyKinds, ScopedTypeVariables,-             TupleSections, TypeFamilies, UndecidableInstances #-}---- | Interfaces for "gadgets," decomposition, and error correction.--module Crypto.Lol.Gadget-( Gadget(..), Decompose(..), Correct(..)-, TrivGad, BaseBGad-) where--import Crypto.Lol.LatticePrelude--import Control.Applicative-import Data.Typeable---- | Dummy type representing the gadget @[1]@.-data TrivGad deriving (Typeable)--- | Dummy type representing the gadget @[1,b,b^2,...]@.-data BaseBGad b deriving (Typeable)---- | "Gadget" vectors, parameterized by an index type.--class Ring u => Gadget gad u where-  -- | The gadget vector over @u@.-  gadget :: Tagged gad [u]--  -- | Yield an error-tolerant encoding of an element with respect to-  -- the gadget.  (Mathematically, this should just be the product of-  -- the input with the gadget, but it is a class method to allow for-  -- optimized implementations.)-  encode :: u -> Tagged gad [u]-  encode s = ((* s) <$>) <$> gadget---- | Decomposition relative to a gadget.--class (Gadget gad u, Reduce (DecompOf u) u) => Decompose gad u where-  -- | The ring that @u@ decomposes over.-  type DecompOf u--  -- | Yield a short vector @x@ such that @\<g, x\> = u@.-  decompose :: u -> Tagged gad [DecompOf u]---- | Error correction relative to a gadget.--class Gadget gad u => Correct gad u where--  -- | Correct a "noisy" encoding of an element (see 'encode').-  correct :: Tagged gad [u] -> u------ instances for products--instance (Gadget gad a, Gadget gad b) => Gadget gad (a,b) where--  gadget = (++) <$> (map (,zero) <$> gadget) <*> (map (zero,) <$> gadget)--instance (Decompose gad a, Decompose gad b, DecompOf a ~ DecompOf b)-         => Decompose gad (a,b) where--  type DecompOf (a,b) = DecompOf a--  decompose (a,b) = (++) <$> decompose a <*> decompose b----- TODO: need some extra constraints on a,b, like Mod and maybe Rescale.--- instance (Correct gad a, Correct gad b) => Correct gad (a,b) where----{- CJP: strawman class for the more general view of LWE secrets as-"module characters," i.e., module homomorphisms into a particular-range.  This is probably wrong, though.--class Character u where       -- Module superclass(es)?-  type CharRange u-  data Char u                   -- need data for injectivity--  evalChar :: Char u -> u -> CharRange u--class (Gadget gad u, Character u) => Correct gad u where--  -- | Correct a "noisy" encoding of an LWE secret (i.e., a-  -- 'ModuleHomom' on 'u').-  correct :: Tagged gad [CharRange u] -> Char u--encode :: (Correct gad u) => Char u -> Tagged gad [CharRange u]-encode s = pasteT $ evalMH s <$> peelT gadget---}-
− src/Crypto/Lol/GaussRandom.hs
@@ -1,90 +0,0 @@-{-# LANGUAGE NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables #-}---- | Functions for sampling from a continuous Gaussian distribution--module Crypto.Lol.GaussRandom-( realGaussian, realGaussians ) where--import Crypto.Lol.LatticePrelude--import qualified Data.Vector.Generic as V--import Control.Monad-import Control.Monad.Random---- | Using polar form of Box-Muller transform, returns a pair of--- centered, Gaussian-distributed real numbers with scaled variance--- @svar = true variance * (2*pi)@. See--- <http://www.alpheratz.net/murison/Maple/GaussianDistribution/GaussianDistribution.pdf--- this link> for details.--realGaussian :: forall v q m .-                (ToRational v, OrdFloat q, Random q, MonadRandom m)-                => v -> m (q,q)-realGaussian svar =-    let var = realToField svar / pi :: q -- twice true variance-    in do (u,v) <- iterateWhile uvGuard getUV-          let t = u*u+v*v-              com = sqrt (-var * log t / t)-          -- we can either sample u,v from [-1,1]-          -- or generate sign bits for the outputs-          s1 <- getRandom-          s2 <- getRandom-          let u' = if s1 then u else -u-              v' = if s2 then v else -v-          return (u'*com,v'*com)-    where getUV = do u <- getRandomR (zero,one)-                     v <- getRandomR (zero,one)-                     return (u,v)-          uvGuard (u,v) = (u*u+v*v >= one) || (u*u+v*v == zero)---- | Generate @n@ real, independent gaussians of scaled variance @svar--- = true variance * (2*pi)@.-realGaussians ::-    (ToRational svar, OrdFloat i, Random i, V.Vector v i, MonadRandom m)-    => svar -> Int -> m (v i)-realGaussians var n-    | odd n = liftM V.tail (realGaussians var (n+1)) -- O(1) tail-    | otherwise = liftM (V.fromList . uncurry (++) . unzip) $-                  replicateM (n `div` 2) (realGaussian var)--------- Taken from monad-loops-0.4.3---- | Execute an action repeatedly until its result fails to satisfy a predicate,--- and return that result (discarding all others).-iterateWhile :: (Monad m) => (a -> Bool) -> m a -> m a-iterateWhile p x = x >>= iterateUntilM (not . p) (const x)---- | Analogue of @('Prelude.until')@--- Yields the result of applying f until p holds.-iterateUntilM :: (Monad m) => (a -> Bool) -> (a -> m a) -> a -> m a-iterateUntilM p f v -    | p v       = return v-    | otherwise = f v >>= iterateUntilM p f--{---- | Returns a Gaussian-distributed sample over 'pZ' with given--- (scaled) variance parameter @v=var/(2*pi)@ and center, using--- rejection sampling--gaussRound :: (RealTranscendental v, Random v,-               RealRing c, ToRational c,-               Ring i, ToInteger i, Random i, MonadRandom m)-               => v -> c -> m i-gaussRound svar c =-    let dev = ceiling $ 6 * sqrt svar -- 6 gives stat dist < 2^-163-        lower = floor c - dev-        upper = ceiling c + dev-        sampler = do-           z <- getRandomR (lower, upper)-           u <- getRandomR (zero, one)-           let dist = fromIntegral z - realToField c-           let prob = exp (-pi * (dist*dist / svar))-           if u <= prob then return z else sampler-    in sampler--}
− src/Crypto/Lol/LatticePrelude.hs
@@ -1,248 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,-             FlexibleInstances, FunctionalDependencies,-             GeneralizedNewtypeDeriving, MultiParamTypeClasses,-             NoImplicitPrelude, PolyKinds, RankNTypes, RebindableSyntax,-             ScopedTypeVariables, StandaloneDeriving, TemplateHaskell,-             TypeFamilies, TypeOperators, UndecidableInstances #-}---- | A substitute for the Prelude that is more suitable for Lol.  This--- module exports most of the Numeric Prelude and other frequently--- used modules, plus some low-level classes, missing instances, and--- assorted utility functions.--module Crypto.Lol.LatticePrelude-( --- * Classes-  Enumerable(..)-, Mod(..)-, Reduce(..), Lift, Lift'(..), Rescale(..), Encode(..), msdToLSD--- * Numeric-, module Crypto.Lol.Types.Numeric--- * Complex-, module Crypto.Lol.Types.Complex--- * Factored-, module Crypto.Lol.Factored--- * Miscellaneous-, rescaleMod, roundCoset-, fromJust', pureT, peelT, pasteT, withWitness, withWitnessT-, module Data.Functor.Trans.Tagged-, module Data.Proxy-) where--import Crypto.Lol.Factored-import Crypto.Lol.Types.Complex-import Crypto.Lol.Types.Numeric--import Algebra.Field          as Field (C)-import Algebra.IntegralDomain as IntegralDomain (C)-import Algebra.Ring           as Ring (C)--import Control.Applicative-import Control.Arrow-import Control.DeepSeq-import Control.Monad.Identity-import Control.Monad.Random-import Data.Coerce-import Data.Default-import Data.Functor.Trans.Tagged-import Data.Maybe-import Data.Proxy-import Data.Singletons---- for Unbox instance of Maybe a-import qualified Data.Vector.Unboxed          as U-import           Data.Vector.Unboxed.Deriving--instance NFData (Proxy (a :: k)) where rnf Proxy = ()--deriving instance NFData (m a) => NFData (TaggedT s m a)-deriving instance (MonadRandom m) => MonadRandom (TaggedT (tag :: k) m)--derivingUnbox "Maybe"-  [t| forall a . (Default a, U.Unbox a) => Maybe a -> (Bool, a) |]-  [| maybe (False, def) (\ x -> (True, x)) |]-  [| \ (b, x) -> if b then Just x else Nothing |]--instance Default Bool where def = False---- | Poor man's 'Enum'.-class Enumerable a where-  values :: [a]---- | Represents a quotient group modulo some integer.-class (ToInteger (ModRep a), Additive a) => Mod a where-  type ModRep a-  modulus :: Tagged a (ModRep a)---- | Represents that @b@ is a quotient group of @a@.-class (Additive a, Additive b) => Reduce a b where-  reduce :: a -> b---- | Represents that @b@ can be lifted to a "short" @a@ congruent to @b@.-type Lift b a = (Lift' b, LiftOf b ~ a)---- | Fun-dep version of Lift.-class (Reduce (LiftOf b) b) => Lift' b where-  type LiftOf b-  lift :: b -> LiftOf b---- | Represents that @a@ can be rescaled to @b@, as an "approximate"--- additive homomorphism.-class (Additive a, Additive b) => Rescale a b where-  rescale :: a -> b---- | Represents that the target ring can "noisily encode" values from--- the source ring, in either "most significant digit" (MSD) or "least--- significant digit" (LSD) encodings, and provides conversion factors--- between the two types of encodings.--class (Field src, Field tgt) => Encode src tgt where-    -- | The factor that converts an element from LSD to MSD encoding-    -- in the target field, with associated scale factor to apply to-    -- correct the resulting encoded value.-    lsdToMSD :: (src, tgt)---- | Inverted entries of 'lsdToMSD'.-msdToLSD :: (Encode src tgt) => (src, tgt)-msdToLSD = (recip *** recip) lsdToMSD---- | A default implementation of rescaling for 'Mod' types.-rescaleMod :: forall a b .-              (Mod a, Mod b, (ModRep a) ~ (ModRep b),-               Lift a (ModRep b), Ring b)-              => a -> b-rescaleMod =-    let qval = proxy modulus (Proxy :: Proxy a)-        q'val = proxy modulus (Proxy :: Proxy b)-    in \x -> let (quot',_) = divModCent (q'val * lift x) qval-             in fromIntegral quot'---- | Deterministically round to a nearby value in the desired coset-roundCoset :: forall zp z r .-              (Mod zp, z ~ ModRep zp, Lift zp z, RealField r) => zp -> r -> z-roundCoset = let pval = proxy modulus (Proxy::Proxy zp)-             in \ zp x -> let rep = lift zp-                          in rep + roundMult pval (x - fromIntegral rep)------------ Instances for product groups/rings ------------instance (Mod a, Mod b, Lift' a, Lift' b, Reduce Integer (a,b),-          ToInteger (LiftOf a), ToInteger (LiftOf b))-         => Lift' (a,b) where--  type LiftOf (a,b) = Integer--  lift (a,b) =-    let moda = toInteger $ proxy modulus (Proxy::Proxy a)-        modb = toInteger $ proxy modulus (Proxy::Proxy b)-        q = moda * modb-        ainv = fromMaybe (error "Lift' (a,b): moduli not coprime") $ moda `modinv` modb-        lifta = toInteger $ lift a-        liftb = toInteger $ lift b-        -- put in [-q/2, q/2)-        (_,r) = (moda * (liftb - lifta) * ainv + lifta) `divModCent` q-    in r----- NP should define Ring and Field instances for pairs, but doesn't.--- So we do it here.-instance (Ring r1, Ring r2) => Ring.C (r1, r2) where--  (x1, x2) * (y1, y2) = (x1*y1, x2*y2)-  one = (one,one)-  fromInteger x = (fromInteger x, fromInteger x)--instance (Field f1, Field f2) => Field.C (f1, f2) where-  (x1, x2) / (y1, y2) = (x1 / y1, x2 / y2)-  recip = recip *** recip--instance (IntegralDomain a, IntegralDomain b) => IntegralDomain.C (a,b) where-  (a1,b1) `divMod` (a2,b2) =-    let (da,ra) = (a1 `divMod` a2)-        (db,rb) = (b1 `divMod` b2)-    in ((da,db), (ra,rb))--instance (Mod a, Mod b) => Mod (a,b) where-  type ModRep (a,b) = Integer--  modulus = tag $ fromIntegral (proxy modulus (Proxy::Proxy a)) *-            fromIntegral (proxy modulus (Proxy::Proxy b))--instance (Reduce a b1, Reduce a b2) => Reduce a (b1, b2) where-  reduce x = (reduce x, reduce x)---- instances of Rescale for a product-instance (Mod a, Field b, Lift a (ModRep a), Reduce (LiftOf a) b)-         => Rescale (a,b) b where-  rescale = let q1val = proxy modulus (Proxy::Proxy a)-                q1inv = recip $ reduce q1val-            in \(x1,x2) -> q1inv * (x2 - reduce (lift x1))--instance (Mod b, Field a, Lift b (ModRep b), Reduce (LiftOf b) a)-         => Rescale (a,b) a where-  rescale = let q2val = proxy modulus (Proxy::Proxy b)-                q2inv = recip $ reduce q2val-            in \(x1,x2) -> q2inv * (x1 - reduce (lift x2))---- some multi-step scaledowns; could do this forever-instance (Rescale (a,(b,c)) (b,c), Rescale (b,c) c)-         => Rescale (a,(b,c)) c where-  rescale = (rescale :: (b,c) -> c) . rescale--instance (Rescale ((a,b),c) (a,b), Rescale (a,b) a)-         => Rescale ((a,b),c) a where-  rescale = (rescale :: (a,b) -> a) . rescale---- scaling up to a product-instance (Ring a, Mod b, Reduce (ModRep b) a) => Rescale a (a,b) where-  -- multiply by q2-  rescale = let q2val = reduce $ proxy modulus (Proxy::Proxy b)-            in \x -> (q2val * x, zero)--instance (Ring b, Mod a, Reduce (ModRep a) b) => Rescale b (a,b) where-  -- multiply by q1-  rescale = let q1val = reduce $ proxy modulus (Proxy::Proxy a)-            in \x -> (zero, q1val * x)---- Instance of 'Encode' for product ring.-instance (Encode s t1, Encode s t2, Field (t1, t2)) => Encode s (t1, t2) where--  lsdToMSD = let (s1, t1conv) = lsdToMSD-                 (s2, t2conv) = lsdToMSD-             in (negate s1 * s2, (t1conv,t2conv))---- Random could have defined this instance, but didn't, so we do it--- here.-instance (Random a, Random b) => Random (a,b) where-  random g = let (a,g') = random g-                 (b, g'') = random g'-             in ((a,b), g'')--  randomR ((loa,lob), (hia,hib)) g = let (a,g') = randomR (loa,hia) g-                                         (b,g'') = randomR (lob,hib) g'-                                     in ((a,b),g'')---- | Version of 'fromJust' with an error message.-fromJust' :: String -> Maybe a -> a-fromJust' str = fromMaybe (error str)---- | Apply any applicative to a Tagged value.-pureT :: Applicative f => TaggedT t Identity a -> TaggedT t f a-pureT = mapTaggedT (pure . runIdentity)---- | Expose the monad of a tagged value.-peelT :: Tagged t (f a) -> TaggedT t f a-peelT = coerce---- | Hide the monad of a tagged value.-pasteT :: TaggedT t f a -> Tagged t (f a)-pasteT = coerce---- | Use a singleton as a witness to extract a value from a tagged value.-withWitness :: forall n r . (SingI n => Tagged n r) -> Sing n -> r-withWitness t wit = withSingI wit $ proxy t (Proxy::Proxy n)---- | Monadic version of 'withWitness'.-withWitnessT :: forall n mon r . (Monad mon) =>-                (SingI n => TaggedT n mon r) -> Sing n -> mon r-withWitnessT t wit = withSingI wit $ proxyT t (Proxy::Proxy n)
− src/Crypto/Lol/Reflects.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances,-             KindSignatures, MultiParamTypeClasses, PolyKinds,-             ScopedTypeVariables, UndecidableInstances #-}---- | Generic interface for reflecting types to values.--module Crypto.Lol.Reflects-( Reflects(..)-) where--import Crypto.Lol.Factored--import Data.Functor.Trans.Tagged-import Data.Proxy-import Data.Reflection-import GHC.TypeLits              as TL---- | Reflection without fundep, and with tagged value. Intended only--- for low-level code; build specialized wrappers around it for--- specific functionality.--class Reflects a i where-  -- | Reflect the value assiated with the type @a@.-  value :: Tagged a i--instance (KnownNat a, Integral i) => Reflects (a :: TL.Nat) i where-  value = return $ fromIntegral $ natVal (Proxy::Proxy a)--instance (NatC a, Integral i) => Reflects a i where-  value = fmap fromIntegral valueNatC--instance (PPow pp, Integral i) => Reflects pp i where-  value = fmap fromIntegral valuePPow--instance (Fact m, Integral i) => Reflects m i where-  value = fmap fromIntegral valueFact--instance {-# OVERLAPS #-} (Reifies rei a) => Reflects (rei :: *) a where-  value = tag $ reflect (Proxy::Proxy rei)
− src/Crypto/Lol/Types/Complex.hs
@@ -1,89 +0,0 @@-{-# LANGUAGE DataKinds, DeriveDataTypeable, FlexibleContexts,-             FlexibleInstances, GeneralizedNewtypeDeriving,-             MultiParamTypeClasses, NoImplicitPrelude, RebindableSyntax,-             ScopedTypeVariables, StandaloneDeriving, TemplateHaskell,-             TypeFamilies, UndecidableInstances #-}---- | Data type, functions, and instances for complex numbers.--module Crypto.Lol.Types.Complex (-  Complex-, roundComplex-, cis, real, imag, fromReal-) where--import           Algebra.Additive       as Additive (C)-import           Algebra.Field          as Field (C)-import           Algebra.IntegralDomain as IntegralDomain-import           Algebra.Ring           as Ring (C)-import           Algebra.ZeroTestable   as ZeroTestable (C)-import qualified Number.Complex         as C hiding (exp, signum)--import Crypto.Lol.Types.Numeric as LP--import Control.DeepSeq-import Data.Array.Repa.Eval         as R-import Data.Vector.Storable         (Storable)-import Data.Vector.Unboxed          (Unbox)-import Data.Vector.Unboxed.Deriving-import System.Random-import Test.QuickCheck---- | Newtype wrapper (with slightly different instances) for--- <https://hackage.haskell.org/package/numeric-prelude-0.4.2/docs/Number-Complex.html numeric-prelude Complex>.-newtype Complex a = Complex (C.T a) deriving (Additive.C, Ring.C, ZeroTestable.C, Field.C, Storable, Eq, Show, Arbitrary)--derivingUnbox "Complex"-  [t| forall a . (Unbox a) => Complex a -> (a, a) |]-  [| \ (Complex x) -> (C.real x, C.imag x) |]-  [| \ (r, i) -> Complex $ r C.+: i |]---- a custom IntegralDomain instance, replacing the one provided by NP.--- it always returns 0 as the remainder of a division.  If we were to--- use the NP instance, sometimes precision issues yield nonzero--- remainders, which makes, e.g., 'divGPow' think that division has--- failed, when it has not.  This in turn causes 'divGCRT' to yield--- Nothing, among other problems.-instance (Field a) => IntegralDomain.C (Complex a) where-  (Complex a) `divMod` (Complex b) = (Complex $ a / b, LP.zero)---- we can't use Generics for NFData because NP doesn't export the--- (deep) constructor for Complex.T-instance (NFData a) => NFData (Complex a) where-  rnf (Complex x) = let r = C.real x-                        i = C.imag x-                    in rnf r `seq` rnf i `seq` ()--instance (Random a) => Random (Complex a) where-    random g = let (a,g') = random g-                   (b,g'') = random g'-               in (Complex $ a C.+: b, g'')--    randomR = error "randomR not defined for (Complex t)"--instance (R.Elt a) => R.Elt (Complex a) where-    touch (Complex c) = do-        touch $ C.real c-        touch $ C.imag c-    zero = Complex $ R.zero C.+: R.zero-    one = Complex $ R.one C.+: R.zero---- | Rounds the real and imaginary components to the nearest integer.-roundComplex :: (RealRing a, ToInteger b) => Complex a -> (b,b)-roundComplex (Complex x) = (round $ C.real x, round $ C.imag x)---- | 'cis' @t@ is a complex value with magnitude 1 and phase t (modulo @2*Pi@).-cis :: Transcendental a => a -> Complex a-cis = Complex . C.cis---- | Real component of a complex number.-real :: Complex a -> a-real (Complex a) = C.real a---- | Imaginary component of a complex number.-imag :: Complex a -> a-imag (Complex a) = C.imag a---- | Embeds a scalar as the real component of a complex number.-fromReal :: Additive a => a -> Complex a-fromReal = Complex . C.fromReal
− src/Crypto/Lol/Types/FiniteField.hs
@@ -1,122 +0,0 @@-{-# LANGUAGE ConstraintKinds, FlexibleContexts,-             GeneralizedNewtypeDeriving, -             NoImplicitPrelude, PolyKinds,-             RebindableSyntax, RoleAnnotations, ScopedTypeVariables #-}---- CJP: need PolyKinds to allow deg to have non-* kind---- | Basic (unoptimized) finite field arithmetic.--module Crypto.Lol.Types.FiniteField-( PrimeField, CharOf, GF   -- export type but not constructor-, trace-, size-) where--import           Crypto.Lol.CRTrans-import           Crypto.Lol.Factored-import           Crypto.Lol.LatticePrelude-import           Crypto.Lol.Reflects-import           Crypto.Lol.Types.PrimeField hiding ((^))-import qualified Crypto.Lol.Types.PrimeField as PF--import Algebra.Additive     as Additive (C)-import Algebra.Field        as Field (C)-import Algebra.Ring         as Ring (C)-import Algebra.ZeroTestable as ZeroTestable (C)-import MathObj.Polynomial--import Math.NumberTheory.Primes.Factorisation--import           Control.Applicative-import           Control.DeepSeq-import           Control.Monad-import qualified Data.Vector              as V----import qualified Debug.Trace as DT---- | A finite field of given degree over @F_p@.-newtype GF fp deg = GF (Polynomial fp)-                  deriving (Eq, Show, Additive.C, ZeroTestable.C, NFData)---- the second argument, though phantom, affects representation-type role GF representational representational--type GFCtx fp deg = (PrimeField fp, Reflects deg Int)--instance (GFCtx fp deg) => Enumerable (GF fp deg) where-  values = GF <$> fromCoeffs <$>-           -- d-fold cartesian product of Fp values-           replicateM (proxy value (Proxy::Proxy deg)) values--instance (GFCtx fp deg) => Ring.C (GF fp deg) where--  one = GF one--  (*) = let poly = proxy irreduciblePoly (Proxy :: Proxy deg)-        in \(GF f) (GF g) -> GF $ (f*g) `mod` poly--  fromInteger = GF . fromInteger--instance (GFCtx fp deg) => Field.C (GF fp deg) where--  recip = let g = proxy irreduciblePoly (Proxy :: Proxy deg)-          in \(GF f) -> let (_,(a,_)) = extendedGCD f g-                           in GF a--instance (GFCtx fp deg) => CRTrans (GF fp deg) where--  crtInfo m = (,) <$> omegaPow <*> scalarInv-    where-      omegaPow =-        let size' = proxy size (Proxy :: Proxy (GF fp deg))-            (q,r) = (size'-1) `quotRem` m-            gen = head $ filter isPrimitive values-            omega = gen^q-            omegaPows = V.iterateN m (*omega) one-        in if r == 0-           then Just $ (omegaPows V.!) . (`mod` m)-           else Nothing-      scalarInv = Just $ recip $ fromIntegral $ valueHat m--sizePP :: forall fp deg . (GFCtx fp deg) => Tagged (GF fp deg) PP-sizePP = tag (proxy value (Proxy::Proxy (CharOf fp)),-              proxy value (Proxy::Proxy deg))---- | The order of the field: @size (GF fp deg) = p^deg@-size :: (GFCtx fp deg) => Tagged (GF fp deg) Int-size = uncurry (^) <$> sizePP--isPrimitive :: forall fp deg . (GFCtx fp deg) => GF fp deg -> Bool-isPrimitive = let q = proxy size (Proxy :: Proxy (GF fp deg))-                  ps = map (fromIntegral . fst) $ factorise $-                       fromIntegral $ q-1-                  exps = map ((q-1) `div`) ps-              in \g -> not (isZero g) && all (\e -> g^e /= 1) exps--dotp :: (Ring a) => [a] -> [a] -> a-dotp a b = sum $ zipWith (*) a b---- | Trace into the prime subfield.-trace :: forall fp deg . (GFCtx fp deg) => GF fp deg -> fp-trace = let ts = proxy powTraces (Proxy::Proxy (GF fp deg))-        in \(GF f) -> dotp ts (coeffs f)---- | Traces of the power basis elements 1, x, x^2, ..., x^(deg-1).-powTraces :: forall fp deg . (GFCtx fp deg) => Tagged (GF fp deg) [fp]-powTraces = -  --DT.trace ("FiniteField.powTraces: p = " ++ -  --          show (proxy value (Proxy::Proxy (CharOf fp)) :: Int) ++-  --          ", d = " ++ show (proxy value (Proxy::Proxy deg) :: Int)) $-  let d = proxy value (Proxy :: Proxy deg)-  in tag $ map trace' $ take d $-     iterate (* (GF (X PF.^ 1))) (one :: GF fp deg)---- helper that computes trace via brute force: sum frobenius--- automorphisms-trace' :: (GFCtx fp deg) => GF fp deg -> fp-trace' e = let (p,d) = witness sizePP e-               (GF t) = sum $ take d $ iterate (^p) e-               -- t is a constant polynomial-           in head $ coeffs t-
− src/Crypto/Lol/Types/IZipVector.hs
@@ -1,58 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, DeriveDataTypeable,-             DeriveTraversable, FlexibleContexts,-             GeneralizedNewtypeDeriving, KindSignatures,-             MultiParamTypeClasses, RoleAnnotations, ScopedTypeVariables,-             TypeFamilies, UndecidableInstances #-}---- | Provides applicative-like functions for indexed vectors--module Crypto.Lol.Types.IZipVector-( IZipVector, iZipVector, unIZipVector-) where--import Crypto.Lol.Factored--import Algebra.ZeroTestable as ZeroTestable--import Control.DeepSeq-import Data.Data-import Data.Functor.Trans.Tagged-import Data.Vector               as V---- | Indexed Zip Vector: a wrapper around a (boxed) 'Vector' that has--- zip-py 'Applicative' behavior, analogous to--- 'Control.Applicative.ZipList' for lists.  The index @m@ enforces--- proper lengths (and is necessary to implement 'pure').--newtype IZipVector (m :: Factored) a =-  IZipVector { -- | Deconstructor for IZipVector-               unIZipVector :: Vector a}-  -- not deriving Read, Monoid, Alternative, Monad[Plus], IsList-  -- because of different semantics and/or length restriction-  deriving (Show, Eq, Data, NFData, Typeable, Functor,-            Foldable, Traversable, ZeroTestable.C)---- the first argument, though phantom, affects representation-type role IZipVector representational representational---- | Smart constructor that checks whether length of input is right--- (should be totient of @m@).-iZipVector :: forall m a . (Fact m) => Vector a -> Maybe (IZipVector m a)-iZipVector = let n = proxy totientFact (Proxy::Proxy m)-            in \vec -> if n == V.length vec-                       then Just $ IZipVector vec-                       else Nothing---- don't export-repl :: forall m a . (Fact m) => a -> IZipVector m a-repl = let n = proxy totientFact (Proxy::Proxy m)-       in IZipVector . V.replicate n---- Zip-py 'Applicative' instance.-instance (Fact m) => Applicative (IZipVector m) where-  pure = repl-  (IZipVector f) <*> (IZipVector a) = IZipVector $ V.zipWith ($) f a---- no ZeroTestable instance for Vectors, so define here-instance (ZeroTestable.C a) => ZeroTestable.C (Vector a) where-  isZero = V.all isZero
− src/Crypto/Lol/Types/IrreducibleChar2.hs
@@ -1,60 +0,0 @@-{-# LANGUAGE NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables,-             FlexibleInstances, TypeFamilies, UndecidableInstances, PolyKinds #-}---- | (Orphan) instance of 'IrreduciblePoly' for characteristic 2 fields.--module Crypto.Lol.Types.IrreducibleChar2 () where--import Crypto.Lol.LatticePrelude hiding ((^))-import Crypto.Lol.Reflects-import Crypto.Lol.Types.PrimeField--import Data.Type.Natural (N2)---- conway---generate in Python (or choose any irreducible polynomial)--- to generate with Sage, start sage and type:---      conway_polynomial(p,e)--- then copy and paste-instance (CharOf a ~ N2, Ring a) => IrreduciblePoly a where-  irreduciblePoly = do-    pn <- taggedProxy-    let n = proxy value pn :: Int-    return $ case n of-      1 -> X^1 + 1-      2 -> X^2 + X^1 + 1-      3 -> X^3 + X^1 + 1-      4 -> X^4 + X^1 + 1-      5 -> X^5 + X^2 + 1-      6 -> X^6 + X^4 + X^3 + X^1 + 1-      7 -> X^7 + X^1 + 1-      8 -> X^8 + X^4 + X^3 + X^2 + 1-      9 -> X^9 + X^4 + 1-      10 -> X^10 + X^6 + X^5 + X^3 + X^2 + X^1 + 1-      11 -> X^11 + X^2 + 1-      12 -> X^12 + X^7 + X^6 + X^5 + X^3 + X^1 + 1-      13 -> X^13 + X^4 + X^3 + X^1 + 1-      14 -> X^14 + X^7 + X^5 + X^3 + 1-      15 -> X^15 + X^5 + X^4 + X^2 + 1-      16 -> X^16 + X^5 + X^3 + X^2 + 1-      17 -> X^17 + X^3 + 1-      18 -> X^18 + X^12 + X^10 + X^1 + 1-      19 -> X^19 + X^5 + X^2 + X^1 + 1-      20 -> X^20 + X^10 + X^9 + X^7 + X^6 + X^5 + X^4 + X^1 + 1-      21 -> X^21 + X^6 + X^5 + X^2 + 1-      22 -> X^22 + X^12 + X^11 + X^10 + X^9 + X^8 + X^6 + X^5 + 1-      23 -> X^23 + X^5 + 1-      24 -> X^24 + X^16 + X^15 + X^14 + X^13 + X^10 + X^9 + X^7 + X^5 + X^3 + 1-      25 -> X^25 + X^8 + X^6 + X^2 + 1-      26 -> X^26 + X^14 + X^10 + X^8 + X^7 + X^6 + X^4 + X^1 + 1-      27 -> X^27 + X^12 + X^10 + X^9 + X^7 + X^5 + X^3 + X^2 + 1-      28 -> X^28 + X^13 + X^7 + X^6 + X^5 + X^2 + 1-      29 -> X^29 + X^2 + 1-      30 -> X^30 + X^17 + X^16 + X^13 + X^11 + X^7 + X^5 + X^3 + X^2 + X^1 + 1-      31 -> X^31 + X^3 + 1-      32 -> X^32 + X^15 + X^9 + X^7 + X^4 + X^3 + 1 -      otherwise -> -        error $ "The ConwayPoly instance for N2 included with the library (and exported by Crypto.Lol) only contains " ++-                "irreducible polynomials for characteristic-2 fields up to GF(2^32). You need a polynomial " ++ -                "for GF(2^" ++ (show n) ++ "). Define your own instance of ConwayPoly and do " ++-                "not import Crypto.Lol."
− src/Crypto/Lol/Types/Numeric.hs
@@ -1,213 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleInstances, GADTs,-             MultiParamTypeClasses, NoImplicitPrelude, RebindableSyntax,-             ScopedTypeVariables, TypeOperators #-}---- we have some orphan instances here for instances of--- package classes with Prelude data types-{-# OPTIONS_GHC -fno-warn-orphans #-}---- | This module imports NumericPrelude and defines constraint--- synonyms for NumericPrelude classes to help with code readability,--- and defines saner versions of some NumericPrelude functions--module Crypto.Lol.Types.Numeric-( module Crypto.Lol.Types.Numeric -- everything we define here-, module NumericPrelude         -- re-export-, Int64                         -- commonly used-) where--import Control.DeepSeq-import Control.Monad.Random--import           Algebra.IntegralDomain (divUp)--- NumericPrelude has silly types for these functions-import           NumericPrelude         hiding (abs, max, min, (^))-import qualified NumericPrelude.Numeric (abs)-import qualified Prelude                (max, min)--import qualified Algebra.Absolute             (C)-import qualified Algebra.Additive             (C)-import qualified Algebra.Algebraic            (C)-import qualified Algebra.Field                (C)-import qualified Algebra.IntegralDomain       (C)-import qualified Algebra.Module               (C)-import qualified Algebra.PrincipalIdealDomain (C)-import qualified Algebra.RealField            (C)-import qualified Algebra.RealIntegral         (C)-import qualified Algebra.RealRing             (C)-import qualified Algebra.RealTranscendental   (C)-import qualified Algebra.Ring                 (C)-import qualified Algebra.ToInteger            (C)-import qualified Algebra.ToRational           (C, realToField)-import qualified Algebra.Transcendental       (C)-import qualified Algebra.ZeroTestable         (C)-import           MathObj.Polynomial--import Data.Int (Int64)---- | The Prelude definition of 'max'.-max :: Ord a => a -> a -> a-max = Prelude.max---- | The Prelude definition of 'min'.-min :: Ord a => a -> a -> a-min = Prelude.min---- | The sane definition of 'abs' from--- 'NumericPrelude.Numeric'--- rather than the default from 'NumericPrelude'.-abs :: Absolute a => a -> a-abs = NumericPrelude.Numeric.abs---- | The hidden NP function from 'Algebra.ToRational'.-realToField :: (Field b, ToRational a) => a -> b-realToField = Algebra.ToRational.realToField---- use this if you need:-{- isZero -}--- | Sane synonym for 'Algebra.ZeroTestable.C'.-type ZeroTestable a = (Algebra.ZeroTestable.C a)--{- - + negate -}--- | Sane synonym for 'Algebra.Additive.C'.-type Additive a = (Algebra.Additive.C a)--{- Additive, plus: * fromIntegral -}--- | Sane synonym for 'Algebra.Ring.C'.-type Ring a = (Algebra.Ring.C a)--{- Ring and Additive, plus: *> -}--- | Sane synonym for 'Algebra.Module.C'.-type Module a v = (Algebra.Module.C a v)--{- Ring, plus: div, mod, divmod -}--- | Sane synonym for 'Algebra.IntegralDomain.C'.-type IntegralDomain a = (Algebra.IntegralDomain.C a)--{- Ring, plus: abs signum toRational' -}--- | Sane synonym for 'Algebra.ToRational.C'.-type ToRational a = (Algebra.ToRational.C a)--{- Ring, plus: / recip fromRational -}--- | Sane synonym for 'Algebra.Field.C'.-type Field a = (Algebra.Field.C a)--{- Ring, plus: abs and rounding functions -}--- | Sane synonym for 'Algebra.RealRing.C'.-type RealRing a = (Algebra.RealRing.C a)--{- Field, plus: abs signum round floor ceiling -}--- | Sane synonym for 'Algebra.RealField.C'.-type RealField a = (Algebra.RealField.C a)--{- Field, plus: sqrt root ^/ -}--- | Sane synonym for 'Algebra.Algebraic.C'.-type Algebraic a = (Algebra.Algebraic.C a)--{- Algebraic, plus: pi exp log sin atan -}--- | Sane synonym for 'Algebra.Transcendental.C'.-type Transcendental a = (Algebra.Transcendental.C a)--{- Transcendental and RealField, plus atan2 -}--- | Sane synonym for 'Algebra.RealTranscendental.C'.-type RealTranscendental a = (Algebra.RealTranscendental.C a)--{- Transcendental, plus: == <= >= < > -}--- | Convenient synonym for @(Ord a, Transcendental a)@-type OrdFloat a = (Ord a, Transcendental a)--{- ToRational and Ring, plus: toInteger div mod divmod quot rem quotrem -}--- | Sane synonym for 'Algebra.ToInteger.C'.-type ToInteger a = (Algebra.ToInteger.C a)---- | Sane synonym for 'Algebra.Absolute.C'.-type Absolute a = (Algebra.Absolute.C a)---- | Sane synonym for 'Algebra.RealIntegral.C'.-type RealIntegral a = (Algebra.RealIntegral.C a)---- | Sane synonym for 'Algebra.PrincipalIdealDomain.C'.-type PID a = (Algebra.PrincipalIdealDomain.C a)---- | Sane synonym for 'MathObj.Polynomial.T'.-type Polynomial a = MathObj.Polynomial.T a---- | IntegralDomain instance for Double-instance Algebra.IntegralDomain.C Double where-    _ `div` 0 = error "cannot divide Double by 0\n"-    a `div` b = a / b-    _ `mod` _ = 0---- NFData instance for Polynomial, missing from NP-instance (NFData r) => NFData (Polynomial r) where-  rnf = rnf . coeffs---- | Our custom exponentiation, overriding NP's version that--- requires 'Integer' exponent.--- Copied from http://hackage.haskell.org/package/base-4.7.0.0/docs/src/GHC-Real.html#%5E-{-# SPECIALISE [1] (^) ::-        Integer -> Integer -> Integer,-        Integer -> Int -> Integer,-        Int -> Int -> Int,-        Int64 -> Int64 -> Int64-  #-}-(^) :: forall a i . (Ring a, ToInteger i) => a -> i -> a-x0 ^ y0 | y0 < 0    = error "Negative exponent"-        | y0 == 0   = 1-        | otherwise = f x0 y0-    where -- f : x0 ^ y0 = x ^ y-          f :: a -> i -> a -- a polymorphic local binding needs a sig-          f x y | even y    = f (x * x) (y `quot` 2)-                | y == 1    = x-                | otherwise = g (x * x) ((y - 1) `quot` 2) x-          -- g : x0 ^ y0 = (x ^ y) * z-          g :: a -> i -> a -> a-          g x y z | even y = g (x * x) (y `quot` 2) z-                  | y == 1 = x * z-                  | otherwise = g (x * x) ((y - 1) `quot` 2) (x * z)---- | Inverse of @a@ modulo @q@, in range @0..q-1@.  (Argument order is--- infix-friendly.)-modinv :: (PID i, Eq i) => i -> i -> Maybe i-modinv a q = let (d, (_, inv)) = extendedGCD q a-             in if d == one-                then Just $ inv `mod` q-                else Nothing---- | Decompose an element into a list of "centered" digits with respect--- to relative radices.-decomp :: (IntegralDomain z, Ord z) => [z] -> z -> [z]-decomp [] v = [v]-decomp (b:bs) v = let (q,r) = v `divModCent` b-                  in r : decomp bs q---- | Yield @ceil (log_b(x))@.-logCeil :: (ToInteger i) => i -> i -> Int-logCeil _ 1 = 0-logCeil b x = 1 + logCeil b (x `divUp` b)---- | Deterministically round to the nearest multiple of @i@.-roundMult :: (RealField r, ToInteger i) => i -> r -> i-roundMult 1 r  = round r-roundMult i r = let r' = r / fromIntegral i in i * round r'---- | Randomly round to the nearest larger or smaller multiple of @i@,--- where the round-off term has expectation zero.-roundScalarCentered :: (RealField r, Random r, ToInteger i,-                        MonadRandom mon)-                      => i -> r -> mon i-roundScalarCentered p x =-  let x' = x / fromIntegral p-      mod1 = x' - floor x'-  in do prob <- getRandomR (zero, one)-        return $ p * if prob < mod1-                     then ceiling x'-                     else floor x'---- | Variant of 'Algebra.IntegralDomain.divMod' in which the remainder--- is in the range @[-b\/2,b\/2)@.-divModCent :: (IntegralDomain i, Ord i) => i -> i -> (i,i)-divModCent a b = let (q,r) = a `divMod` b-                 in if 2*r < b -- divMod returns non-neg remainder-                    then (q,r)-                    else (q+1,r-b)
− src/Crypto/Lol/Types/PrimeField.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE NoImplicitPrelude, RebindableSyntax, PolyKinds, TypeFamilies, -             DataKinds, FlexibleContexts, ConstraintKinds #-}---- | Prime-order fields.--module Crypto.Lol.Types.PrimeField where--import Crypto.Lol.LatticePrelude as LP-import Crypto.Lol.Reflects--import MathObj.Polynomial---- | Constraint synonym for prime-order fields.-type PrimeField fp = (Enumerable fp, Eq fp, ZeroTestable fp, Field fp,-       IrreduciblePoly fp)---- | The characteristic of a field, represented as a type.-type family CharOf (fp :: k) :: Nat---- | Represents prime-order fields over which we can get irreducible--- polynomials of desired degree.  (An instance of this class is--- defined in 'Crypto.Lol.Types.IrreducibleChar2' and exported from--- 'Crypto.Lol'.)-class (Ring fp, Prime (CharOf fp)) => IrreduciblePoly fp where-  irreduciblePoly :: (Reflects deg Int) => Tagged deg (Polynomial fp)---- | Convenience function for writing 'IrreduciblePoly' instances.-taggedProxy :: Tagged s (Proxy s)-taggedProxy = tag Proxy---- | Convenience data type for writing 'IrreduciblePoly' instances.-data X = X---- | Convenience function for writing 'IrreduciblePoly' instances.-(^) :: (Ring a) => X -> Int -> Polynomial a-X ^ i | i >= 0 = fromCoeffs $ (replicate i 0) ++ [1]
− src/Crypto/Lol/Types/ZPP.hs
@@ -1,23 +0,0 @@-{-# LANGUAGE FlexibleContexts, TypeFamilies #-}---- | A class for integers mod a prime power.--module Crypto.Lol.Types.ZPP-( ZPP(..)-) where--import Crypto.Lol.LatticePrelude-import Crypto.Lol.Types.FiniteField---- | Represents integers modulo a prime power.-class (PrimeField (ZPOf zq), Ring zq, Ring (ZPOf zq)) => ZPP zq where--  -- | An implementation of the integers modulo the prime base.-  type ZPOf zq--  -- | The prime and exponent of the modulus.-  modulusZPP :: Tagged zq PP--  -- | Lift from @Z_p@ to a representative.-  liftZp :: ZPOf zq -> zq-
− src/Crypto/Lol/Types/ZmStar.hs
@@ -1,69 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,-             NoImplicitPrelude, PolyKinds, RebindableSyntax,-             ScopedTypeVariables, TypeFamilies, TypeOperators, -             UndecidableInstances #-}---- | A collection of helper functions for working with @Z_m^*@--module Crypto.Lol.Types.ZmStar-( order, partitionCosets-) where--import Crypto.Lol.Factored-import Crypto.Lol.LatticePrelude as LP hiding (null)-import Crypto.Lol.Reflects-import Crypto.Lol.Types.ZqBasic--import Data.List as L (foldl', transpose)-import Data.Map  (Map, elems, empty, insertWith')-import Data.Set  as S (Set, difference, findMin, fromList, map, null)----- | The multiplicative order of @p@ (the argument) modulo @m@.--- Requires @gcd(p,m)=1@.-order :: forall m . (Reflects m Int) => Int -> Tagged m Int-order p = tag $-  let mval = proxy value (Proxy::Proxy m)-  in if gcd p mval /= 1-     then error "p and m not coprime"-     else 1 + (length $ takeWhile (/= one) $-               tail $ iterate (* (fromIntegral p)) (one :: ZqBasic m Int))---- given p, returns the cosets of Z_m^* / <p>-cosets :: forall zm . (Mod zm, ModRep zm ~ Int, Ord zm, Ring zm)-  => Int -> [Set zm]-cosets p =-  let mval = proxy modulus (Proxy::Proxy zm)-  in if gcd p mval /= 1-     then error "p and m not coprime"-     else let zmstar = fromList $ LP.map fromIntegral $ filter ((==) 1 . gcd mval) [1..mval]-              zp = fromIntegral p-              -- generates the coset containing x-              coset x = fromList $ x : takeWhile (/=x) (iterate (*zp) $ zp*x)-              -- repeatedly removes a (new) coset from the remaining elements-              genCosets s | null s = []-              genCosets s = let c = coset (findMin s)-                            in c : genCosets (difference s c)-          in genCosets zmstar---- CJP: could tag this by '(p,m,m') for safety/memoization.---- | Given @p@, returns a partition of the cosets of @Z_{m\'}^* \/ \<p>@--- (specified by representatives), where the cosets in each component--- are in bijective correspondence with the cosets of @Z_m^* \/ \<p>@ under--- the natural (@mod m@) homomorphism.-partitionCosets :: forall m m' . (m `Divides` m')-  => Int -> Tagged '(m, m') [[Int]]-partitionCosets p =-  let m'cosets = cosets p-      -- a map from cosets of Z_m^* / <p> to their preimages under the-      -- natural homomorphism-      partition =-        L.foldl' (\cmap x -> insertWith' (++) (S.map (reduce . lift) x) [x] cmap)-          (empty :: Map (Set (ZqBasic m Int)) [Set (ZqBasic m' Int)])-          m'cosets-      -- transpose the map to get a list of list of sets, where for each-      -- inner list, there is exactly one m'-(co)set lying above each m-coset-      part' = transpose $ elems partition-     -- concat the inner sets to get a list of "CRT cosets" (indexed in Z_m'^*)-  in return $ LP.map (LP.map (lift . findMin)) part'
− src/Crypto/Lol/Types/ZqBasic.hs
@@ -1,256 +0,0 @@-{-# LANGUAGE ConstraintKinds, DataKinds, DeriveDataTypeable,
-             FlexibleContexts, FlexibleInstances,
-             GeneralizedNewtypeDeriving, MultiParamTypeClasses,
-             NoImplicitPrelude, PolyKinds, RebindableSyntax,
-             RoleAnnotations, ScopedTypeVariables, 
-             StandaloneDeriving, TypeFamilies, UndecidableInstances #-}
-
--- | An implementation of modular arithmetic, i.e., the ring Zq.
-
-module Crypto.Lol.Types.ZqBasic
-( ZqBasic -- export the type, but not the constructor (for safety)
-) where
-
-import Crypto.Lol.LatticePrelude as LP
-import Crypto.Lol.Reflects
-import Crypto.Lol.CRTrans
-import Crypto.Lol.Types.FiniteField
-import Crypto.Lol.Types.ZPP
-import Crypto.Lol.Gadget
-
-import Control.Applicative
-import Control.DeepSeq        (NFData)
-import Control.Monad          (liftM)
-import Data.Coerce
-import Data.Maybe
-import Data.Typeable
-import NumericPrelude.Numeric as NP (round)
-import System.Random
-import Test.QuickCheck
-
--- for the Unbox instances
-import qualified Data.Vector.Generic         as V
-import qualified Data.Vector.Generic.Mutable as M
-import qualified Data.Vector.Unboxed         as U
-
-import Foreign.Storable
-
--- for the Elt instance
-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)
-
--- | The ring @Z_q@ of integers modulo 'q', using underlying integer
--- type 'z'.
-newtype ZqBasic q z = ZqB z
-                    deriving (Eq, Ord, ZeroTestable.C, E.Elt, Show, NFData, Storable)
-
--- the q argument, though phantom, matters for safety
-type role ZqBasic nominal representational
-
---deriving instance (U.Unbox i) => V.Vector U.Vector (ZqBasic q i)
---deriving instance (U.Unbox i) => M.MVector U.MVector (ZqBasic q i)
---deriving instance (U.Unbox i) => U.Unbox (ZqBasic q i)
-
--- convenience synonym for many instances
-type ReflectsTI q z = (Reflects q z, ToInteger z)
-
-reduce' :: forall q z . (ReflectsTI q z) => z -> ZqBasic q z
-reduce' = coerce . (`mod` proxy value (Proxy::Proxy q))
-
--- puts value in range [-q/2, q/2)
-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..(qval-1)]
-
-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
-
-instance (ReflectsTI q z) => Lift' (ZqBasic q z) where
-  type LiftOf (ZqBasic q z) = z
-  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)
-
--- instance of CRTrans
-instance (Reflects q z, PID z, r ~ (ZqBasic q z), Mod r, Enumerable r,
-          Show z) -- for DT.trace
-         => CRTrans (ZqBasic q z) where
-
-  crtInfo =
-    --DT.trace ("ZqBasic.crtInfo: q = " ++ 
-    --          show (proxy value (Proxy::Proxy q) :: z)) $
-    let qval :: z = proxy value (Proxy::Proxy q)
-    in \m -> (,) <$> omegaPowMod m <*>
-  -- CJP: using coerce depends on modinv returning in [0..q-1]
-                     (coerce $ fromIntegral (valueHat m) `modinv` qval)
-
--- instance of CRTEmbed
-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 of Additive
-instance (ReflectsTI q z, Additive z) => Additive.C (ZqBasic q z) where
-  -- CJP: "LHS too complicated to desugar"; might be fixed in 7.10:
-  -- https://ghc.haskell.org/trac/ghc/ticket/8848
-  {-# SPECIALIZE instance ReflectsTI q Int => Additive.C (ZqBasic q Int) #-}
-  {-# SPECIALIZE instance ReflectsTI q Int64 => Additive.C (ZqBasic q Int64) #-}
-  
-  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 of Ring
-instance (ReflectsTI q z, Ring z) => Ring.C (ZqBasic q z) where
-    (ZqB x) * (ZqB y) = reduce' $ x * y
-
-    fromInteger x =
-      let qval = toInteger (proxy value (Proxy::Proxy q) :: z)
-    -- this is safe as long as type z can hold the value of q
-      in ZqB $ fromInteger $ x `mod` qval
-
--- instance of Field
-instance (ReflectsTI q z, PID z, Show z) => Field.C (ZqBasic q z) where
-
-  recip = let qval = proxy value (Proxy::Proxy q)
-              -- safe because modinv returns in range 0..qval-1
-          in \(ZqB x) -> ZqB $ 
-               fromMaybe (error $ "ZqB.recip fail: " ++ 
-                         show x ++ "\t" ++ show qval) $ modinv x qval
-
--- (canonical) instance of IntegralDomain, needed for FastCyc
-instance (Field (ZqBasic q z)) => IntegralDomain.C (ZqBasic q z) where
-    divMod a b = (a/b, zero)
-
--- Gadget-related instances
-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
-    _ -> error "Correct TrivGad: wrong length"
-
-instance (ReflectsTI q z, Additive 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)
-               k = logCeil bval qval
-           in tag $ map reduce' (take k (iterate (*bval) one))
-
-instance (ReflectsTI q z, Ring 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 = logCeil bval qval
-                  radices = replicate (k-1) bval
-              in tag . decomp radices . lift
-
--- TODO: implement Correct for BaseBGad b
-
--- instance of Random
-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 of Arbitrary
-instance (ReflectsTI q z, Random z) => Arbitrary (ZqBasic q z) where
-  arbitrary =
-    let qval :: z = proxy value (Proxy::Proxy q)
-    in fromIntegral <$> choose (0, qval-1)
-
-  shrink = shrinkNothing
-
--- CJP: restored manual Unbox instances, until we have a better way
--- (NewtypeDeriving or TH)
-
-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)
-
--- Unbox, when underlying representation is
-instance (U.Unbox z) => U.Unbox (ZqBasic q z)
-
-{- purloined and tweaked from code in `vector` package that defines
-types as unboxed -}
-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 `liftM` M.basicUnsafeNew n
-  basicUnsafeReplicate n (ZqB x) = MV_ZqBasic `liftM` M.basicUnsafeReplicate n x
-  basicUnsafeRead (MV_ZqBasic v) z = ZqB `liftM` 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 `liftM` M.basicUnsafeGrow v n
-
-instance (U.Unbox z) => V.Vector U.Vector (ZqBasic q z) where
-  basicUnsafeFreeze (MV_ZqBasic v) = V_ZqBasic `liftM` V.basicUnsafeFreeze v
-  basicUnsafeThaw (V_ZqBasic v) = MV_ZqBasic `liftM` V.basicUnsafeThaw v
-  basicLength (V_ZqBasic v) = V.basicLength v
-  basicUnsafeSlice z n (V_ZqBasic v) = V_ZqBasic $ V.basicUnsafeSlice z n v
-  basicUnsafeIndexM (V_ZqBasic v) z = ZqB `liftM` V.basicUnsafeIndexM v z
-  basicUnsafeCopy (MV_ZqBasic mv) (V_ZqBasic v) = V.basicUnsafeCopy mv v
-  elemseq _ = seq
− test-suite/CycTests.hs
@@ -1,105 +0,0 @@-{-# LANGUAGE RankNTypes, ScopedTypeVariables, NoImplicitPrelude, RebindableSyntax,-             TypeOperators, FlexibleContexts, ConstraintKinds, TypeFamilies,-             DataKinds #-}-module CycTests (cycTests) where--import TestTypes--import Crypto.Lol.CRTrans-import Crypto.Lol.Cyclotomic.Cyc-import Crypto.Lol.LatticePrelude-import Crypto.Lol.Cyclotomic.Tensor.CTensor-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor-import Crypto.Lol.Types.FiniteField-import Crypto.Lol.Types.IrreducibleChar2-import Crypto.Lol.Types.ZPP--import Control.Monad (join, liftM2)--import Data.Array.Repa.Eval (Elt)-import Data.Type.Natural hiding (zero)-import Data.Vector.Unboxed (Vector, Unbox)-import Data.Vector.Storable (Storable)--import Test.Framework (testGroup, Test, defaultMain)-import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.QuickCheck (Property, property, Arbitrary)--cycTests = [testGroup "coeffsPow" $ groupC $ wrapCmm'rToBool prop_coeffsBasis,-            testGroup "crtSet" $ groupC $ wrapProxyCmm'rToBool prop_crtSet_pairs]------type BasisCtx t m m' r = -  (m `Divides` m', ZPP r, CElt t r, CElt t (ZPOf r))--prop_coeffsBasis :: forall t m m' r . (BasisCtx t m m' r)-  => Proxy m -> Cyc t m' r -> Bool-prop_coeffsBasis _ x = -  let xs = map embed (coeffsCyc Pow x :: [Cyc t m r])-      bs = proxy powBasis (Proxy::Proxy m)-  in (sum $ zipWith (*) xs bs) == x---- verifies that CRT set elements satisfy c_i * c_j = delta_ij * c_i--- necessary (not sufficient?) condition-prop_crtSet_pairs :: forall t m m' r . (BasisCtx t m m' r)-  => Proxy m -> Proxy (Cyc t m' r) -> Bool-prop_crtSet_pairs pm _ = -  let crtset = proxy crtSet pm :: [Cyc t m' r]-      pairs = join (liftM2 (,)) crtset-  in and $ map (\(a,b) -> if a == b then a*b == a else a*b == zero) pairs--type BasisWrapCtx t m m' r =-  (BasisCtx t m m' r, Show (Cyc t m' r), Arbitrary (t m' r))--wrapCmm'rToBool :: (BasisWrapCtx t m m' r)-  => (Proxy m -> Cyc t m' r -> Bool) -     -> Proxy (Cyc t) -> Proxy '(m,m',r) -> Property-wrapCmm'rToBool f _ _ = property $ f Proxy--wrapProxyCmm'rToBool :: (BasisWrapCtx t m m' r)-  => (Proxy m -> Proxy (Cyc t m' r) -> Bool) -     -> Proxy (Cyc t) -> Proxy '(m,m',r) -> Property-wrapProxyCmm'rToBool f _ _ = property $ f Proxy Proxy--groupC ::-  (forall t m m' r . -       (BasisWrapCtx t m m' r) -       => Proxy (Cyc t) -          -> Proxy '(m,m',r) -          -> Property)-  -> [Test]--- since we don't have any Tensor-level tests for coeffs/basis functions,--- we need to test all Tensors here.-groupC f =-  [testGroup "FC CT" $ groupMM'R (f (Proxy::Proxy (Cyc CT))),-   testGroup "FC RT" $ groupMM'R (f (Proxy::Proxy (Cyc RT)))]--type BasisWrapCCtx m m' r =-  (BasisWrapCtx RT m m' r,-   BasisWrapCtx CT m m' r)--groupMM'R :: -  (forall m m' r . (BasisWrapCCtx m m' r) => Proxy '(m, m', r) -> Property) -  -> [Test]-groupMM'R f = [testProperty "F1/F7/PP8" $ f (Proxy::Proxy '(F1, F7, Zq (PP2 N3))), -               testProperty "F1/F7/PP2" $ f (Proxy::Proxy '(F1, F7, Zq (PP2 N1)))] -- add some more test cases------- for crtSet, take all pairwise products --- if elts are equal, id--- if not, zero---- also do a cardinality check---- checks cardinality of the CRT set-{--prop_crtSet_card pm _-  let inferLen = length $ (proxy crtSetDec pm :: [t m' r])-      expectLen = -  in  --}
− test-suite/Main.hs
@@ -1,19 +0,0 @@-----module Tests where--import SHETests-import TensorTests-import CycTests-import ZqTests--import Test.Framework--main :: IO ()-main = do-  flip defaultMainWithArgs ["--threads=1","--maximum-generated-tests=1000"]-    [  testGroup "Tensor Tests" tensorTests-     , testGroup "Cyc Tests" cycTests-     , testGroup "SHE Tests" sheTests-     , testGroup "Zq Tests" zqTests-    ]
− test-suite/SHETests.hs
@@ -1,442 +0,0 @@-{-# LANGUAGE ScopedTypeVariables, NoImplicitPrelude, RebindableSyntax, -             DataKinds, TypeOperators, NoMonomorphismRestriction, NoMonoLocalBinds,-             ConstraintKinds, TypeFamilies, FlexibleContexts, PartialTypeSignatures, -             RankNTypes, MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, -             RebindableSyntax, GADTs, PolyKinds, KindSignatures #-}--module SHETests (sheTests) where--import TestTypes--import Control.Applicative hiding ((<$$>))-import Control.Monad-import Control.Monad.Random--import Crypto.Lol.LatticePrelude hiding (lift)-import Crypto.Lol.Cyclotomic.Cyc-import Crypto.Lol.Applications.SymmSHE-import Crypto.Lol.CRTrans-import Crypto.Lol.Gadget-import Crypto.Lol.Cyclotomic.Linear--import Crypto.Lol.Cyclotomic.Tensor.RepaTensor-import qualified Crypto.Lol.Cyclotomic.Tensor.CTensor as CT-import Crypto.Lol.Cyclotomic.Tensor.CTensor hiding (CT)-import Crypto.Lol.Types.ZqBasic--import Data.Array.Repa.Eval (Elt)-import Data.Type.Natural hiding (zero,one)-import Data.Typeable-import Data.Vector.Unboxed (Unbox)-import Data.Vector.Storable (Storable)--import Test.Framework-import Test.Framework.Providers.QuickCheck2-import Test.QuickCheck hiding (generate,output)-import Test.QuickCheck.Monadic (monadicIO, assert)--v = 1 :: Double--sheTests = -  [testGroup "Tunnel" $ tunnelTests,-   testGroup "Dec . Enc (Unrestricted)" $ groupCEnc $ wrapEnc prop_encDec,-   testGroup "Dec . Enc (MSD)" $ groupCEnc $ wrapEnc prop_encDec_MSD,-   testGroup "AddPub" $ groupCEnc $ wrapEnc prop_addPub,-   testGroup "MulPub" $ groupCEnc $ wrapEnc prop_mulPub,-   testGroup "ScalarPub" $ groupCEnc $ wrapScalar prop_addScalar,-   testGroup "CTAdd" $ groupCEnc $ wrapMath prop_ctadd,-   testGroup "CTMul" $ groupCEnc $ wrapMath prop_ctmul,-   testGroup "CT zero" $ groupCEnc $ wrapConst prop_ctzero,-   testGroup "CT one" $ groupCEnc $ wrapConst prop_ctone,-   testGroup "ModSwPT" modSwPTTests,-   testGroup "KSLin" $ groupCKS $ wrapKSLin prop_ksLin,-   testGroup "KSQuad" $ groupCKS $ wrapKSQuad prop_ksQuad,-   testGroup "Embed" $ groupCTwEm $ wrapEm prop_ctembed,-   testGroup "Twace" $ groupCTwEm $ wrapTw prop_cttwace-  ]--type EncDecCtx c m m' zp zq =-  (GenSKCtx c m (LiftOf zp) Double,-   EncryptCtx c m m' (LiftOf zp) zp zq,-   -- constraints from decryptUnrestricted-   ToSDCtx c m' zp zq, Lift' zq, Reduce (LiftOf zq) zp)--prop_encDec :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq) -  => Proxy '(m', zq) -> Cyc c m zp -> Property-prop_encDec _ x = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk x-  let x' = decryptUnrestricted sk $ y-  assert $ x == x'--prop_encDec_MSD :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq) -  => Proxy '(m', zq) -> Cyc c m zp -> Property-prop_encDec_MSD _ x = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk x-  let x' = decryptUnrestricted sk $ toMSD y-  assert $ x == x'--prop_addPub :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq)-  => Proxy '(m', zq) -> Cyc c m zp -> Property-prop_addPub _ x = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk x-  let y' = addPublic x y-      x' = decryptUnrestricted sk y'-  assert $ x' == (x+x)--prop_mulPub :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq)-  => Proxy '(m', zq) -> Cyc c m zp -> Property-prop_mulPub _ x = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk x-  let y' = mulPublic x y-      x' = decryptUnrestricted sk y'-  assert $ x' == (x*x)--prop_addScalar :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq)-  => Proxy '(m', zq) -> zp -> Cyc c m zp -> Property-prop_addScalar _ s x = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk x-  let y' = addScalar s y-      x' = decryptUnrestricted sk y'-  assert $ x' == ((scalarCyc s)+x)--prop_ctadd :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq) -  => Proxy '(m', zq) -> Cyc c m zp -> Cyc c m zp -> Property-prop_ctadd _ x1 x2 = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y1 :: CT m zp (Cyc c m' zq) <- encrypt sk x1-  y2 :: CT m zp (Cyc c m' zq) <- encrypt sk x2-  let y' = y1+y2-      x' = decryptUnrestricted sk y'-  assert $ x1+x2 == x'--prop_ctmul :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq)-  => Proxy '(m', zq) -> Cyc c m zp -> Cyc c m zp -> Property-prop_ctmul _ x1 x2 = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y1 :: CT m zp (Cyc c m' zq) <- encrypt sk x1-  y2 :: CT m zp (Cyc c m' zq) <- encrypt sk x2-  let y' = y1*y2-      x' = decryptUnrestricted sk y'-  assert $ x1*x2 == x'--prop_ctzero :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq) -  => Proxy '(m', zq) -> Proxy (Cyc c m zp) -> Property-prop_ctzero _ _ = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  let z = decryptUnrestricted sk (zero :: CT m zp (Cyc c m' zq))-  assert $ zero == z--prop_ctone :: forall m zp c m' zq . -  (EncDecCtx c m m' zp zq)-  => Proxy '(m', zq) -> Proxy (Cyc c m zp) -> Property-prop_ctone _ _ = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  let z = decryptUnrestricted sk (one :: CT m zp (Cyc c m' zq))-  assert $ one == z--type EncDecWrapCtx c m m' zp zq =-  (EncDecCtx c m m' zp zq, Show (Cyc c m zp), Arbitrary (c m zp), Show zp, Arbitrary zp)--wrapEnc :: (EncDecWrapCtx c m m' zp zq)-  => (Proxy '(m', zq) -> Cyc c m zp -> Property) -     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property-wrapEnc f _ _ = property $ f Proxy--wrapScalar :: (EncDecWrapCtx c m m' zp zq)-  => (Proxy '(m', zq) -> zp -> Cyc c m zp -> Property)-     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property-wrapScalar f _ _ = property $ f Proxy--wrapMath :: (EncDecWrapCtx c m m' zp zq)-  => (Proxy '(m', zq) -> Cyc c m zp -> Cyc c m zp -> Property) -     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property-wrapMath f _ _ = property $ f Proxy--wrapConst :: (EncDecWrapCtx c m m' zp zq)-  => (Proxy '(m', zq) -> Proxy (Cyc c m zp) -> Property) -     -> Proxy (Cyc c) -> Proxy '(m, m', zp, zq) -> Property-wrapConst f _ _ = property $ f Proxy Proxy--groupCEnc :: -  (forall c m m' zp zq . (EncDecWrapCtx c m m' zp zq)-     => Proxy (Cyc c)-     -> Proxy '(m, m', zp, zq)-     -> Property) -  -> [Test]-groupCEnc f =-  [testGroup "CT" $ groupTypesEnc (f (Proxy::Proxy (Cyc CT.CT))),-   testGroup "RT" $ groupTypesEnc (f (Proxy::Proxy (Cyc RT)))]--type EncDecWrapCCtx m m' zp zq =-  (EncDecWrapCtx RT m m' zp zq,-   EncDecWrapCtx CT.CT m m' zp zq)--groupTypesEnc :: -  (forall m m' zp zq . (EncDecWrapCCtx m m' zp zq)-    => Proxy '(m, m', zp, zq)-    -> Property)-  -> [Test]-groupTypesEnc f = [testProperty "F7/F7 /ZP2/ZQ2" $ f (Proxy::Proxy '(F7, F7,  ZP2, ZQ2)),-                   testProperty "F7/F21/ZP2/ZQ2" $ f (Proxy::Proxy '(F7, F21, ZP2, ZQ2)),-                   testProperty "F2/F8 /ZP2/Q536871001" $ f (Proxy::Proxy '(F2,F8,ZP2,Zq Q536871001)),-                   testProperty "F1/F8 /ZP2/Q536871001" $ f (Proxy::Proxy '(F1,F8,ZP2,Zq Q536871001)),-                   testProperty "F4/F12/ZP2/SmoothZQ1" $ f (Proxy::Proxy '(F4,F12,ZP2,SmoothZQ1)),-                   testProperty "F4/F8/ZP3/SmoothQ1" $ f (Proxy::Proxy '(F4,F8,ZP3, Zq SmoothQ1)),-                   testProperty "F7/F7 /ZP4/ZQ2" $ f (Proxy::Proxy '(F7, F7,  ZP4, ZQ2)),-                   testProperty "F7/F21/ZP4/ZQ2" $ f (Proxy::Proxy '(F7, F21, ZP4, ZQ2)),-                   testProperty "F1/F4/ZP4/ZQ1" $ f (Proxy::Proxy '(F1,F4,ZP4,ZQ1)),-                   testProperty "F4/F4/ZP4/ZQ1" $ f (Proxy::Proxy '(F4,F4,ZP4,ZQ1)),-                   testProperty "F14/F14/ZP4/ZQ1" $ f (Proxy::Proxy '(F14,F14,ZP4,ZQ1)),-                   testProperty "F28/F28/ZP4/ZQ1" $ f (Proxy::Proxy '(F28,F28,ZP4,ZQ1)),-                   testProperty "F28/F28/ZP4/Q80221" $ f (Proxy::Proxy '(F28,F28,ZP4,Zq Q80221)),-                   testProperty "F1/F8 /ZP4/Q536871001" $ f (Proxy::Proxy '(F1,F8,ZP4,Zq Q536871001)),-                   testProperty "F2/F8 /ZP4/Q536871001" $ f (Proxy::Proxy '(F2,F8,ZP4,Zq Q536871001)),-                   testProperty "F4/F12/ZP8/SmoothZQ1" $ f (Proxy::Proxy '(F4,F12,ZP8,SmoothZQ1))-                  ]---- one-off tests, no wrapper--prop_modSwPT :: forall m zp c m' zq z v zp' .-  (EncryptCtx c m m' z zp zq,-   GenSKCtx c m z v,-   DecryptCtx c m m' z zp' zq,-   ModSwitchPTCtx c m' zp zp' zq,-   RescaleCyc (Cyc c) zp zp', Mod zp',-   CElt c Int64, CElt c zq,-   z ~ LiftOf zp', v ~ Double, ModRep zp' ~ ModRep zp) -  => Proxy '(m', zq, zp') -> Cyc c m zp -> Property-prop_modSwPT _ x = monadicIO $ do-  let p = proxy modulus (Proxy::Proxy zp)-      p' = proxy modulus (Proxy::Proxy zp')-      x' = (fromIntegral $ p `div` p') * x-  sk :: SK (Cyc c m' z) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk x'-  let y' = modSwitchPT y :: CT m zp' (Cyc c m' zq)-      x'' = decrypt sk y'-  assert $ x'' == rescaleCyc Dec x'--modSwPTTests = -  [testProperty "RT/F7/F21/ZQ1/ZP4/ZP8" (prop_modSwPT (Proxy::Proxy '(F21, ZQ1, ZP4)) :: Cyc RT F7 ZP8 -> Property),-   testProperty "RT/F7/F42/ZQ1/ZP2/ZP4" (prop_modSwPT (Proxy::Proxy '(F42, ZQ1, ZP2)) :: Cyc RT F7 ZP4 -> Property),-   testProperty "CT/F7/F21/ZQ1/ZP4/ZP8" (prop_modSwPT (Proxy::Proxy '(F21, ZQ1, ZP4)) :: Cyc CT.CT F7 ZP8 -> Property),-   testProperty "CT/F7/F42/ZQ1/ZP2/ZP4" (prop_modSwPT (Proxy::Proxy '(F42, ZQ1, ZP2)) :: Cyc CT.CT F7 ZP4 -> Property)]---tunnelTests = -  [testProperty "RT/F7/F21/ZQ1/ZP4/ZP8" -    (prop_ringTunnel (Proxy::Proxy '(F40,ZQ1,F20,F60,TrivGad,ZQ2)) :: Cyc RT F8 ZP4 -> Property)]--prop_ringTunnel :: forall c e r s e' r' s' z zp zq zq' gad . -  (TunnelCtx c e r s e' r' s' z zp zq zq' gad, -   EncryptCtx c r r' z zp zq,-   GenSKCtx c r' z Double,-   GenSKCtx c s' z Double,-   DecryptCtx c s s' z zp zq,-   Random (Cyc c s zp),-   e ~ FGCD r s, Fact e) -  => Proxy '(r', zq, s, s', gad, zq') -> Cyc c r zp -> Property-prop_ringTunnel _ x = monadicIO $ do-  let totr = proxy totientFact (Proxy::Proxy r)-      tote = proxy totientFact (Proxy::Proxy e)-      basisSize = totr `div` tote-  -- choose a random linear function of the appropriate size-  bs :: [Cyc c s zp] <- replicateM basisSize getRandom-  let f = (linearDec bs) \\ (gcdDivides (Proxy::Proxy r) (Proxy::Proxy s)) :: Linear c zp e r s -      expected = evalLin f x \\ (gcdDivides (Proxy::Proxy r) (Proxy::Proxy s))-  skin :: SK (Cyc c r' (LiftOf zp)) <- genSK v-  skout :: SK (Cyc c s' (LiftOf zp)) <- genSK v-  y :: CT r zp (Cyc c r' zq) <- encrypt skin x-  tunn <- proxyT (tunnelCT f skout skin) (Proxy::Proxy (gad,zq'))-  let y' = tunn y-      actual = decrypt skout y' :: Cyc c s zp-  assert $ expected == actual-------------type KsCtx m zp z c m' zq gad zq' deczq = -  (GenSKCtx c m' z Double,-   z ~ LiftOf zp, -   EncryptCtx c m m' z zp zq,-   KeySwitchCtx gad c m' zp zq zq', -   KSHintCtx gad c m' z zq',-   RescaleCyc (Cyc c) zq deczq,-   DecryptCtx c m m' z zp deczq)--prop_ksLin :: forall m zp z c m' zq gad zq' deczq . (KsCtx m zp z c m' zq gad zq' deczq) -  => Proxy '(m', zq, gad, zq', deczq) -> Cyc c m zp -> Property-prop_ksLin (_ :: Proxy '(m', zq, gad, zq', deczq)) x = monadicIO $ do-  sk1 :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  sk2 :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk1 x-  ks <- proxyT (keySwitchLinear sk2 sk1) (Proxy::Proxy (gad,zq'))-  let y' :: CT m zp (Cyc c m' zq) = ks y-      x' = decrypt sk2 (rescaleLinearCT y' :: CT m zp (Cyc c m' deczq))-  assert $ x == x'--prop_ksQuad :: forall m zp z c m' zq gad zq' deczq . (KsCtx m zp z c m' zq gad zq' deczq) -  => Proxy '(m', zq, gad, zq', deczq) -> Cyc c m zp -> Cyc c m zp -> Property-prop_ksQuad (_ :: Proxy '(m', zq, gad, zq', deczq)) x1 x2 = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y1 :: CT m zp (Cyc c m' zq) <- encrypt sk x1-  y2 :: CT m zp (Cyc c m' zq) <- encrypt sk x2-  ks <- proxyT (keySwitchQuadCirc sk) (Proxy::Proxy (gad,zq'))-  let y' = ks (y1*y2)-      x' = decrypt sk (rescaleLinearCT y' :: CT m zp (Cyc c m' deczq))-  assert $ x1*x2 == x'--type KsWrapCtx m zp z c m' zq gad zq' deczq = -  (KsCtx m zp z c m' zq gad zq' deczq, Show (Cyc c m zp), Arbitrary (c m zp))--wrapKSLin :: forall m zp z c m' zq gad zq' deczq . (KsWrapCtx m zp z c m' zq gad zq' deczq)-  => (Proxy '(m', zq, gad, zq', deczq) -> Cyc c m zp -> Property) -     -> Proxy (Cyc c) -> Proxy gad -> Proxy '(m, m', zp, zq, zq', deczq) -> Property-wrapKSLin f _ _ _ = property $ f Proxy--wrapKSQuad :: forall m zp z c m' zq gad zq' deczq . (KsWrapCtx m zp z c m' zq gad zq' deczq)-  => (Proxy '(m', zq, gad, zq',deczq) -> Cyc c m zp -> Cyc c m zp -> Property) -     -> Proxy (Cyc c) -> Proxy gad -> Proxy '(m, m', zp, zq, zq', deczq) -> Property-wrapKSQuad f _ _ _ = property $ f Proxy--groupCKS :: -  (forall c m m' zp z zq zq' gad deczq . (KsWrapCtx m zp z c m' zq gad zq' deczq)-     => Proxy (Cyc c)-     -> Proxy gad-     -> Proxy '(m, m', zp, zq, zq', deczq)-     -> Property)-  -> [Test]-groupCKS f =-  [testGroup "CT" $ groupGadKS $ f (Proxy::Proxy (Cyc CT.CT)),-   testGroup "RT" $ groupGadKS $ f (Proxy::Proxy (Cyc RT))]--type KsWrapCCtx m zp z m' zq gad zq' deczq = -  (KsWrapCtx m zp z RT m' zq gad zq' deczq,-   KsWrapCtx m zp z CT.CT m' zq gad zq' deczq)--groupGadKS :: -  (forall m m' zp z zq zq' gad deczq . (KsWrapCCtx m zp z m' zq gad zq' deczq)-     => Proxy gad-     -> Proxy '(m, m', zp, zq, zq', deczq)-     -> Property) -  -> [Test]-groupGadKS f =-  [testGroup "TrivGad" $ groupTypesKS (f (Proxy::Proxy TrivGad))]-   --testGroup "Base16" $ groupTypesKS (f (Proxy::Proxy (BaseBGad N16)))]--type KsWrapCGadCtx m zp z m' zq zq' deczq = -  (KsWrapCCtx m zp z m' zq TrivGad zq' deczq)--groupTypesKS :: -  (forall m m' zp z zq zq' deczq . (KsWrapCGadCtx m zp z m' zq zq' deczq)-    => Proxy '(m, m', zp, zq, zq', deczq) -    -> Property) -  -> [Test]-groupTypesKS f = -  [testProperty "F1/F7/ZP2/ZQ1/ZQ2" $ f (Proxy::Proxy '(F1, F7, ZP2, ZQ1, ZQ2, ZQ1)),-   testProperty "F2/F4/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F2, F4, ZP8, SmoothZQ1, SmoothZQ2, SmoothZQ1)),-   testProperty "F4/F12/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F4, F12, ZP2, SmoothZQ1, SmoothZQ2, SmoothZQ1)),-   testProperty "F8/F64/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F8, F64, ZP2, SmoothZQ1, SmoothZQ2, SmoothZQ1)),-   testProperty "F3/F27/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F3, F27, ZP2, SmoothZQ1, SmoothZQ2, SmoothZQ1)),-   testProperty "F2/F4/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F2, F4, ZP8, SmoothZQ2, SmoothZQ3, SmoothZQ1)),-   testProperty "F4/F12/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F4, F12, ZP2, SmoothZQ2, SmoothZQ3, SmoothZQ1)),-   testProperty "F8/F64/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F8, F64, ZP2, SmoothZQ2, SmoothZQ3, SmoothZQ1)),-   testProperty "F3/F27/ZP2/SmoothZQ1/SmoothZQ2" $ f (Proxy::Proxy '(F3, F27, ZP2, SmoothZQ2, SmoothZQ3, SmoothZQ1))]-------------------type TwEmCtx c m m' t t' zp zq =-  (EncryptCtx c m m' (LiftOf zp) zp zq,-   GenSKCtx c m (LiftOf zp) Double, -   DecryptCtx c m m' (LiftOf zp) zp zq, -   t `Divides` t', m `Divides` t, m' `Divides` t', m ~ FGCD m' t)--prop_ctembed :: forall c m m' t t' zp zq . -  (TwEmCtx c m m' t t' zp zq)-  => Proxy '(m', zq, t, t') -> Cyc c m zp -> Property-prop_ctembed _ x = monadicIO $ do-  sk :: SK (Cyc c m' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt sk x-  let y' = embedCT y :: CT t zp (Cyc c t' zq)-      x' = decrypt (embedSK sk) y'-  assert $ (embed x :: Cyc c t zp) == x'--prop_cttwace :: forall c m m' t t' zp zq . -  (TwEmCtx c t t' m m' zp zq)-  => Proxy '(m', zq, t, t') -> Cyc c m zp -> Property-prop_cttwace _ x = monadicIO $ do-  sk :: SK (Cyc c t' (LiftOf zp)) <- genSK v-  y :: CT m zp (Cyc c m' zq) <- encrypt (embedSK sk) x-  let y' = twaceCT y :: CT t zp (Cyc c t' zq)-      x' = decrypt sk y'-  assert $ (twace x :: Cyc c t zp) == x'--type TwEmWrapCtx c m m' t t' zp zq = -  (TwEmCtx c m m' t t' zp zq, Show (Cyc c m zp), Show (Cyc c t zp), Arbitrary (c m zp), Arbitrary (c t zp))--wrapEm :: (TwEmWrapCtx c m m' t t' zp zq)-  => (Proxy '(m', zq, t, t') -> Cyc c m zp -> Property) -     -> Proxy (Cyc c) -> Proxy '(m, m', t, t', zp, zq) -> Property-wrapEm f _ _ = property $ f Proxy--wrapTw :: (TwEmWrapCtx c t t' m m' zp zq)-  => (Proxy '(m', zq, t, t') -> Cyc c m zp -> Property) -     -> Proxy (Cyc c) -> Proxy '(t, t', m, m', zp, zq) -> Property-wrapTw f _ _ = property $ f Proxy--groupCTwEm :: -  (forall c m m' t t' zp zq . (TwEmWrapCtx c m m' t t' zp zq)-     => Proxy (Cyc c)-     -> Proxy '(m, m', t, t', zp, zq)-     -> Property) -  -> [Test]-groupCTwEm f =-  [testGroup "CT" $ groupTypesTwEm (f (Proxy::Proxy (Cyc CT.CT))),-   testGroup "RT" $ groupTypesTwEm (f (Proxy::Proxy (Cyc RT)))]--type TwEmWrapCCtx m m' t t' zp zq =-  (TwEmWrapCtx RT m m' t t' zp zq,-   TwEmWrapCtx CT.CT m m' t t' zp zq)--groupTypesTwEm :: -  (forall m m' t t' zp zq . (TwEmWrapCCtx m m' t t' zp zq)-    => Proxy '(m, m', t, t', zp, zq) -    -> Property) -  -> [Test]-groupTypesTwEm f = -  [testProperty "F1/F7/F3/F21/ZP2/ZQ1" $ f (Proxy::Proxy '(F1, F7, F3, F21, ZP2, ZQ1))]
− test-suite/TensorTests.hs
@@ -1,368 +0,0 @@-{-# LANGUAGE NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables, -             DataKinds, TypeOperators, KindSignatures, RankNTypes, GADTs,-             MultiParamTypeClasses, ConstraintKinds, FlexibleInstances, RebindableSyntax,-             FlexibleContexts, UndecidableInstances, TypeFamilies, DeriveDataTypeable #-}--module TensorTests (tensorTests) where---import TestTypes--import Crypto.Lol.CRTrans-import Crypto.Lol.LatticePrelude as LP hiding (round)-import Crypto.Lol.Cyclotomic.Tensor-import Crypto.Lol.Cyclotomic.Tensor.CTensor-import Crypto.Lol.Cyclotomic.Tensor.RepaTensor--import Control.Applicative-import Control.Monad.Random--import Data.Array.Repa.Eval (Elt)-import Data.Constraint-import Data.Maybe-import Data.Vector.Unboxed as U-import Data.Vector.Storable (Storable)--import Test.Framework-import Test.Framework.Providers.QuickCheck2-import Test.QuickCheck hiding (generate,output)--tensorTests = -  [testGroup "fmap comparison" $ groupTMR $ wrapTmrToBool prop_fmap,-   testGroup "fmap comparison 2" $ groupTMR $ wrapTmrToBool prop_fmap2,-   testGroup "Extension Mult" $ groupExtTests $ wrap2TmrToBool prop_mul_ext,--   -- inverse property-   tremTests, -   gInvGTests,-   testGroup "CRTInv.CRT" $ groupTMR $ wrapTmrToBool prop_crt_inv,-   testGroup "LInv.L" $ groupTMR $ wrapTmrToBool prop_l_inv,--   -- commutative property-   gCommuteTests,-   embedCommuteTests,-   twaceCommuteTests,-   testGroup "Scalar" $ groupTMR $ wrapRToBool prop_scalar_crt,-   twaceInvarTests-   ]---type TMRCtx t m r = (Tensor t, Fact m, m `Divides` m, CRTrans r, TElt t r, CRTEmbed r, -                     TElt t (CRTExt r), Eq r, ZeroTestable r, IntegralDomain r)--prop_fmap :: (TMRCtx t m r) => t m r -> Bool-prop_fmap x = fmapT id x == x \\ witness entailEqT x \\ witness entailIndexT x--prop_fmap2 :: (TMRCtx t m r) => t m r -> Bool-prop_fmap2 x = (fmapT id x) == (fmap id x) \\ witness entailEqT x \\ witness entailIndexT x---- tests that multiplication in the extension ring matches CRT multiplication-prop_mul_ext :: forall t m r . (TMRCtx t m r)-  => t m r -> t m r -> Bool-prop_mul_ext x y = -  let m = proxy valueFact (Proxy::Proxy m)-  in case (crtInfo m :: Maybe (CRTInfo r)) of-       Nothing -> error "mul have a CRT to call prop_mul_ext"-       Just _ -> (let z = x * y-                      z' = fmapT fromExt $ (fmapT toExt x) * (fmapT toExt y)-                  in z == z') \\ witness entailEqT x -                              \\ witness entailRingT x-                              \\ witness entailRingT (fmap toExt x)-                              \\ witness entailIndexT x--gInvGTests = testGroup "GInv.G == id" [-  testGroup "Pow basis" $ groupTMR $ wrapTmrToBool prop_ginv_pow,-  testGroup "Dec basis" $ groupTMR $ wrapTmrToBool prop_ginv_dec,-  testGroup "CRT basis" $ groupTMR $ wrapTmrToBool prop_ginv_crt]---- divG . mulG == id in Pow basis-prop_ginv_pow :: (TMRCtx t m r) => t m r -> Bool-prop_ginv_pow x = (fromMaybe (error "could not divide by G in prop_ginv_pow") $ -  divGPow $ mulGPow x) == x \\ witness entailEqT x---- divG . mulG == id in Dec basis-prop_ginv_dec :: (TMRCtx t m r) => t m r -> Bool-prop_ginv_dec x = (fromMaybe (error "could not divide by G in prop_ginv_dec") $ -  divGDec $ mulGDec x) == x \\ witness entailEqT x---- divG . mulG == id in CRT basis-prop_ginv_crt :: (TMRCtx t m r) => t m r -> Bool-prop_ginv_crt x = fromMaybe (error "no CRT in prop_ginv_crt") $ do-  divGCRT' <- divGCRT-  mulGCRT' <- mulGCRT-  return $ (divGCRT' $ mulGCRT' x) == x \\ witness entailEqT x---- crtInv . crt == id-prop_crt_inv :: (TMRCtx t m r) => t m r -> Bool-prop_crt_inv x = fromMaybe (error "no CRT in prop_crt_inv") $ do-  crt' <- crt-  crtInv' <- crtInv-  return $ (crtInv' $ crt' x) == x \\ witness entailEqT x---- lInv . l == id-prop_l_inv :: (TMRCtx t m r) => t m r -> Bool-prop_l_inv x = (lInv $ l x) == x \\ witness entailEqT x---- scalarCRT = crt . scalarPow-prop_scalar_crt :: forall t m r . (TMRCtx t m r)-                   => Proxy (t m r) -> r -> Bool-prop_scalar_crt _ r = fromMaybe (error "no CRT in prop_scalar_crt") $ do-  scalarCRT' <- scalarCRT-  crt' <- crt-  return $ (scalarCRT' r :: t m r) == (crt' $ scalarPow r)-  \\ proxy entailEqT (Proxy::Proxy (t m r))--gCommuteTests = testGroup "G commutes with L" [-  testGroup "Dec basis" $ groupTMR $ wrapTmrToBool prop_g_dec,-  testGroup "CRT basis" $ groupTMR $ wrapTmrToBool prop_g_crt]---- mulGDec == lInv. mulGPow . l-prop_g_dec :: (TMRCtx t m r) => t m r -> Bool-prop_g_dec x = (mulGDec x) == (lInv $ mulGPow $ l x) \\ witness entailEqT x--prop_g_crt :: (TMRCtx t m r) => t m r -> Bool-prop_g_crt x = fromMaybe (error "no CRT in prop_g_crt") $ do-  mulGCRT' <- mulGCRT-  crt' <- crt-  crtInv' <- crtInv-  return $ (mulGCRT' x) == (crt' $ mulGPow $ crtInv' x) \\ witness entailEqT x--type TMRWrapCtx t m r = (TMRCtx t m r, Show (t m r), Arbitrary (t m r), Show r, Arbitrary r)--wrap2TmrToBool :: (TMRWrapCtx t m r) => (t m r -> t m r -> Bool) -     -> Proxy t -> Proxy '(m,r) -> Property-wrap2TmrToBool f _ _ = property f--wrapTmrToBool :: (TMRWrapCtx t m r) => (t m r -> Bool) -     -> Proxy t -> Proxy '(m,r) -> Property-wrapTmrToBool f _ _ = property f--wrapRToBool :: (TMRWrapCtx t m r) => (Proxy (t m r) -> r -> Bool)-     -> Proxy t -> Proxy '(m,r) -> Property-wrapRToBool f _ _ = property $ f Proxy --groupTMR :: (forall t m r . (TMRWrapCtx t m r)-             => Proxy t-             -> Proxy '(m,r) -             -> Property) -> [Test]-groupTMR f =-  [testGroup "CT" $ groupMR (f (Proxy::Proxy CT)),-   testGroup "RT" $ groupMR (f (Proxy::Proxy RT))]--groupExtTests :: (forall t m r . (TMRWrapCtx t m r)-             => Proxy t-             -> Proxy '(m,r) -             -> Property) -> [Test]-groupExtTests f =-  [testGroup "CT" $ groupMRExt (f (Proxy::Proxy CT)),-   testGroup "RT" $ groupMRExt (f (Proxy::Proxy RT))]--type MRWrapCtx m r = (TMRWrapCtx CT m r, TMRWrapCtx RT m r)--groupMR :: (forall m r . (MRWrapCtx m r) => Proxy '(m, r) -> Property) -            -> [Test]-groupMR f = [testProperty "F7/Q29" $ f (Proxy::Proxy '(F7, Zq Q29)),-             testProperty "F12/SmoothZQ1" $ f (Proxy::Proxy '(F12, SmoothZQ1)),-             testProperty "F1/Q17" $ f (Proxy::Proxy '(F1, Zq Q17)),-             testProperty "F2/Q17" $ f (Proxy::Proxy '(F2, Zq Q17)),-             testProperty "F4/Q17" $ f (Proxy::Proxy '(F4, Zq Q17)),-             testProperty "F8/Q17" $ f (Proxy::Proxy '(F8, Zq Q17)),-             testProperty "F21/Q8191" $ f (Proxy::Proxy '(F21, Zq Q8191)),-             testProperty "F42/Q8191" $ f (Proxy::Proxy '(F42, Zq Q8191)),-             testProperty "F42/ZQ1" $ f (Proxy::Proxy '(F42, ZQ1)),-             testProperty "F42/ZQ2" $ f (Proxy::Proxy '(F42, ZQ2))]---- we can't include a large modulus here because there is not enough--- precision in Doubles to handle the error-groupMRExt :: (forall m r . (MRWrapCtx m r) => Proxy '(m, r) -> Property) -            -> [Test]-groupMRExt f = [testProperty "F7/Q29" $ f (Proxy::Proxy '(F7, Zq Q29)),-             testProperty "F1/Q17" $ f (Proxy::Proxy '(F1, Zq Q17)),-             testProperty "F2/Q17" $ f (Proxy::Proxy '(F2, Zq Q17)),-             testProperty "F4/Q17" $ f (Proxy::Proxy '(F4, Zq Q17)),-             testProperty "F8/Q17" $ f (Proxy::Proxy '(F8, Zq Q17)),-             testProperty "F21/Q8191" $ f (Proxy::Proxy '(F21, Zq Q8191)),-             testProperty "F42/Q8191" $ f (Proxy::Proxy '(F42, Zq Q8191)),-             testProperty "F42/ZQ1" $ f (Proxy::Proxy '(F42, ZQ1)),-             testProperty "F42/ZQ2" $ f (Proxy::Proxy '(F42, ZQ2))]------------type TMM'RCtx t m m' r = (Tensor t, m `Divides` m', TElt t r, Ring r, CRTrans r, Eq r, ZeroTestable r, IntegralDomain r)---- groups related tests-tremTests = testGroup "Tr.Em == id" [-  testGroup "Pow basis" $ groupTMM'R $ wrapTmm'rToBool prop_trem_pow,-  testGroup "Dec basis" $ groupTMM'R $ wrapTmm'rToBool prop_trem_dec,-  testGroup "CRT basis" $ groupTMM'R $ wrapTmm'rToBool prop_trem_crt]---- tests that twace . embed == id in the Pow basis-prop_trem_pow :: forall t m m' r . (TMM'RCtx t m m' r)-  => Proxy m' -> t m r -> Bool-prop_trem_pow _ x = (twacePowDec $ (embedPow x :: t m' r)) == x \\ witness entailEqT x---- tests that twace . embed == id in the Dec basis-prop_trem_dec :: forall t m m' r . (TMM'RCtx t m m' r)-  => Proxy m' -> t m r -> Bool-prop_trem_dec _ x = (twacePowDec $ (embedDec x :: t m' r)) == x \\ witness entailEqT x---- tests that twace . embed == id in the CRT basis-prop_trem_crt :: forall t m m' r . (TMM'RCtx t m m' r)-  => Proxy m' -> t m r -> Bool-prop_trem_crt _ x = fromMaybe (error "no CRT in prop_trem_crt") $-  (x==) <$> (twaceCRT <*> (embedCRT <*> pure x :: Maybe (t m' r))) \\ witness entailEqT x--embedCommuteTests = testGroup "Em commutes with L" [-  testGroup "Dec basis" $ groupTMM'R $ wrapTmm'rToBool prop_embed_dec,-  testGroup "CRT basis" $ groupTMM'R $ wrapTmm'rToBool prop_embed_crt]---- embedDec == lInv . embedPow . l-prop_embed_dec :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m' -> t m r -> Bool-prop_embed_dec _ x = (embedDec x :: t m' r) == (lInv $ embedPow $ l x) -  \\ proxy entailEqT (Proxy::Proxy (t m' r))---- embedCRT = crt . embedPow . crtInv-prop_embed_crt :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m' -> t m r -> Bool-prop_embed_crt _ x = fromMaybe (error "no CRT in prop_embed_crt") $ do-  crt' <- crt-  crtInv' <- crtInv-  embedCRT' <- embedCRT-  return $ (embedCRT' x :: t m' r) == (crt' $ embedPow $ crtInv' x) -    \\ proxy entailEqT (Proxy::Proxy (t m' r))--twaceCommuteTests = testGroup "Tw commutes with L" [-  testGroup "Dec basis" $ groupTMM'R $ wrapTm'mrToBool prop_twace_dec,-  testGroup "CRT basis" $ groupTMM'R $ wrapTm'mrToBool prop_twace_crt]---- twacePowDec = lInv . twacePowDec . l-prop_twace_dec :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m -> t m' r -> Bool-prop_twace_dec _ x = (twacePowDec x :: t m r) == (lInv $ twacePowDec $ l x)-  \\ proxy entailEqT (Proxy::Proxy (t m r))---- twaceCRT = crt . twacePowDec . crtInv-prop_twace_crt :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m -> t m' r -> Bool-prop_twace_crt _ x = fromMaybe (error "no CRT in prop_trace_crt") $ do-  twaceCRT' <- twaceCRT-  crt' <- crt-  crtInv' <- crtInv-  return $ (twaceCRT' x :: t m r) == (crt' $ twacePowDec $ crtInv' x)-    \\ proxy entailEqT (Proxy::Proxy (t m r))--twaceInvarTests = testGroup "Twace invariants" [-  testGroup "Tw and Em ID for equal indices" $ groupTMR $ wrapTmrToBool $ prop_twEmID,-  testGroup "Invar1 Pow basis" $ groupTMM'R $ wrapProxyTmm'rToBool prop_twace_invar1_pow,-  testGroup "Invar1 Dec basis" $ groupTMM'R $ wrapProxyTmm'rToBool prop_twace_invar1_dec,-  testGroup "Invar1 CRT basis" $ groupTMM'R $ wrapProxyTmm'rToBool prop_twace_invar1_crt,-  testGroup "Invar2 Pow/Dec basis" $ groupTMM'R $ wrapProxyTmm'rToBool prop_twace_invar2_powdec,-  testGroup "Invar2 CRT basis" $ groupTMM'R $ wrapProxyTmm'rToBool prop_twace_invar2_crt-  ]--prop_twEmID :: forall t m r . (Tensor t, TElt t r, CRTrans r, Fact m, m `Divides` m, Eq r, ZeroTestable r, IntegralDomain r) => t m r -> Bool-prop_twEmID x = ((twacePowDec x) == x) &&-                  (((fromMaybe (error "twemid_crt") twaceCRT) x) == x) &&-                  ((embedPow x) == x) &&-                  ((embedDec x) == x) &&-                  (((fromMaybe (error "twemid_crt") embedCRT) x) == x) \\ witness entailEqT x---- twace mhat'/g' = mhat*totm'/totm/g (Pow basis)-prop_twace_invar1_pow :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m' -> Proxy (t m r) -> Bool-prop_twace_invar1_pow _ _ = fromMaybe (error "could not divide by G in prop_twace_invar1_pow") $ do-  let mhat = proxy valueHatFact (Proxy::Proxy m)-      mhat' = proxy valueHatFact (Proxy::Proxy m')-      totm = proxy totientFact (Proxy::Proxy m)-      totm' = proxy totientFact (Proxy::Proxy m')-  output :: t m r <- divGPow $ scalarPow $ fromIntegral $ mhat * totm' `div` totm-  input :: t m' r <- divGPow $ scalarPow $ fromIntegral mhat'-  return $ (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))---- twace mhat'/g' = mhat*totm'/totm/g (Dec basis)-prop_twace_invar1_dec :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m' -> Proxy (t m r) -> Bool-prop_twace_invar1_dec _ _ = fromMaybe (error "could not divide by G in prop_twace_invar1_dec") $ do-  let mhat = proxy valueHatFact (Proxy::Proxy m)-      mhat' = proxy valueHatFact (Proxy::Proxy m')-      totm = proxy totientFact (Proxy::Proxy m)-      totm' = proxy totientFact (Proxy::Proxy m')-  output :: t m r <- divGDec $ lInv $ scalarPow $ fromIntegral $ mhat * totm' `div` totm-  input :: t m' r <- divGDec $ lInv $ scalarPow $ fromIntegral mhat'-  return $ (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))---- twace mhat'/g' = mhat*totm'/totm/g (CRT basis)-prop_twace_invar1_crt :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m' -> Proxy (t m r) -> Bool-prop_twace_invar1_crt _ _ = fromMaybe (error "no CRT in prop_twace_invar1_crt") $ do-  let mhat = proxy valueHatFact (Proxy::Proxy m)-      mhat' = proxy valueHatFact (Proxy::Proxy m')-      totm = proxy totientFact (Proxy::Proxy m)-      totm' = proxy totientFact (Proxy::Proxy m')-  scalarCRT1 <- scalarCRT-  scalarCRT2 <- scalarCRT-  divGCRT1 <- divGCRT-  divGCRT2 <- divGCRT-  twaceCRT' <- twaceCRT-  let output :: t m r = divGCRT1 $ scalarCRT1 $ fromIntegral $ mhat * totm' `div` totm-      input :: t m' r = divGCRT2 $ scalarCRT2 $ fromIntegral mhat'-  return $ (twaceCRT' input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))---- twace preserves scalars in Pow/Dec basis-prop_twace_invar2_powdec :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m' -> Proxy (t m r) -> Bool-prop_twace_invar2_powdec _ _ = -  let output = scalarPow $ one :: t m r-      input = scalarPow $ one :: t m' r-  in (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))---- twace preserves scalars in Pow/Dec basis-prop_twace_invar2_crt :: forall t m m' r . (TMM'RCtx t m m' r) => Proxy m' -> Proxy (t m r) -> Bool-prop_twace_invar2_crt _ _ = fromMaybe (error "no CRT in prop_twace_invar2_crt") $ do-  scalarCRT1 <- scalarCRT-  scalarCRT2 <- scalarCRT-  let input = scalarCRT1 one :: t m' r-      output = scalarCRT2 one :: t m r-  return $ (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))--type TMM'RWrapCtx t m m' r = (TMM'RCtx t m m' r, Show (t m' r), Show (t m r), Arbitrary (t m' r), Arbitrary (t m r))--wrapProxyTmm'rToBool :: (TMM'RWrapCtx t m m' r)-                        => (Proxy m' -> Proxy (t m r) -> Bool) -                        -> Proxy t -> Proxy '(m,m',r) -> Property-wrapProxyTmm'rToBool f _ _ = property $ f Proxy Proxy--wrapTmm'rToBool :: (TMM'RWrapCtx t m m' r) => (Proxy m' -> t m r -> Bool) -                   -> Proxy t -> Proxy '(m,m',r) -> Property-wrapTmm'rToBool f _ _ = property $ f Proxy--wrapTm'mrToBool :: (TMM'RWrapCtx t m m' r) => (Proxy m -> t m' r -> Bool) -                   -> Proxy t -> Proxy '(m,m',r) -> Property-wrapTm'mrToBool f _ _ = property $ f Proxy--groupTMM'R :: (forall t m m' r . TMM'RWrapCtx t m m' r-               => Proxy t-               -> Proxy '(m,m',r) -               -> Property) -> [Test]-groupTMM'R f =-  [testGroup "CT" $ groupMM'R (f (Proxy::Proxy CT)),-   testGroup "RT" $ groupMM'R (f (Proxy::Proxy RT))]--type MM'RWrapCtx m m' r = (TMM'RWrapCtx CT m m' r, TMM'RWrapCtx RT m m' r)--groupMM'R :: (forall m m' r . (MM'RWrapCtx m m' r)-              => Proxy '(m, m', r) -> Property) -> [Test]-groupMM'R f = [testProperty "F1/F7/Q29" $ f (Proxy::Proxy '(F1, F7, Zq Q29)),-               testProperty "F4/F12/Q536871001" $ f (Proxy::Proxy '(F4, F12, Zq Q536871001)),-               testProperty "F4/F12/SmoothZQ1" $ f (Proxy::Proxy '(F4, F12, SmoothZQ1)),-               testProperty "F2/F8/Q17" $ f (Proxy::Proxy '(F2, F8, Zq Q17)),-               testProperty "F8/F8/Q17" $ f (Proxy::Proxy '(F8, F8, Zq Q17)),-               testProperty "F12/F12/SmoothZQ1" $ f (Proxy::Proxy '(F2, F8, SmoothZQ1)),-               testProperty "F4/F8/Q17" $ f (Proxy::Proxy '(F4, F8, Zq Q17)),-               testProperty "F3/F21/Q8191" $ f (Proxy::Proxy '(F3, F21, Zq Q8191)),-               testProperty "F7/F21/Q8191" $ f (Proxy::Proxy '(F7, F21, Zq Q8191)),-               testProperty "F3/F42/Q8191" $ f (Proxy::Proxy '(F3, F42, Zq Q8191)),-               testProperty "F3/F21/ZQ1" $ f (Proxy::Proxy '(F3, F21, ZQ1)),-               testProperty "F7/F21/ZQ2" $ f (Proxy::Proxy '(F7, F21, ZQ2)),-               testProperty "F3/F42/ZQ3" $ f (Proxy::Proxy '(F3, F42, ZQ3))]
− test-suite/TestTypes.hs
@@ -1,90 +0,0 @@-{-# LANGUAGE KindSignatures, PolyKinds, DataKinds, FlexibleInstances, RankNTypes,-             TypeOperators, ConstraintKinds, FlexibleContexts, ScopedTypeVariables,-             MultiParamTypeClasses, TypeFamilies, NoImplicitPrelude, RebindableSyntax #-}--module TestTypes (-  ZP2, ZP3, ZP4, ZP8-, PP2-, SmoothZQ1, SmoothZQ2, SmoothZQ3-, SmoothQ1-, Zq, ZQ1, ZQ2, ZQ3-, Q17, Q29, Q8191, Q80221, Q536871001) where--import Control.Monad-import Control.Monad.Random--import Crypto.Lol-import Crypto.Lol.Reflects-import Crypto.Lol.Factored--import Data.Type.Natural--import Test.QuickCheck.Monadic--instance (MonadRandom m) => MonadRandom (PropertyM m) where-  getRandom = run getRandom-  getRandoms = run getRandoms-  getRandomR r = run $ getRandomR r-  getRandomRs r = run $ getRandomRs r---- three 24-bit moduli, enough to handle rounding for p=32 (depth-4 circuit at ~17 bits per mul)-data Q18869761-instance (ToInteger i) => Reflects Q18869761 i where value = return 18869761-type ZQ1 = Zq Q18869761--data Q19393921-instance (ToInteger i) => Reflects Q19393921 i where value = return 19393921-type ZQ2 = (Zq Q19393921, ZQ1)--data Q19918081-instance (ToInteger i) => Reflects Q19918081 i where value = return 19918081-type ZQ3 = (Zq Q19918081, ZQ2)---- a 31-bit modulus, for rounding off after the last four hops-data Q2149056001-instance (ToInteger i) => Reflects Q2149056001 i where value = return 2149056001-type ZQ4 = (Zq Q2149056001, ZQ3)---- for rounding off after the first hop-data Q3144961-instance (ToInteger i) => Reflects Q3144961 i where value = return 3144961-type ZQ5 = (Zq Q3144961, ZQ4)--data Q7338241-instance (ToInteger i) => Reflects Q7338241 i where value = return 7338241-type ZQ6 = (Zq Q7338241, ZQ5)---- concrete types useful for building tests or real applications-data Q17-data Q29-data Q8191  -- 1028th prime, = 1 mod 21-data Q80221  -- good for 28-data Q536871001 --- the next three moduli are "good" for any index dividing 128*27*25*7-data SmoothQ1 -data SmoothQ2 -data SmoothQ3 --instance (ToInteger i) => Reflects Q17 i where value = return 17-instance (ToInteger i) => Reflects Q29 i where value = return 29-instance (ToInteger i) => Reflects Q8191 i where value = return 8191-instance (ToInteger i) => Reflects Q536871001 i where value = return 536871001-instance (ToInteger i) => Reflects Q80221 i where value = return 80221-instance (ToInteger i) => Reflects SmoothQ1 i where value = return 2148249601-instance (ToInteger i) => Reflects SmoothQ2 i where value = return 2148854401-instance (ToInteger i) => Reflects SmoothQ3 i where value = return 2150668801--type Zq (q :: k) = ZqBasic q Z-type Z = Int64--type PP2 e = ToPP N2 e-type PP3 e = ToPP N3 e--type ZP2 = Zq (PP2 N1)-type ZP3 = Zq (PP3 N1)-type ZP4 = Zq (PP2 N2)-type ZP8 = Zq (PP2 N3)--type SmoothZQ1 = Zq SmoothQ1-type SmoothZQ2 = (Zq SmoothQ2, SmoothZQ1)-type SmoothZQ3 = (Zq SmoothQ3, SmoothZQ2)
− test-suite/ZqTests.hs
@@ -1,56 +0,0 @@-{-# LANGUAGE NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables, DataKinds, TypeOperators, PolyKinds, FlexibleContexts, RankNTypes, KindSignatures, MultiParamTypeClasses #-}--module ZqTests (zqTests) where--import Crypto.Lol.Types.ZqBasic-import Crypto.Lol.LatticePrelude hiding (Nat)-import Crypto.Lol.Reflects--import Control.Monad--import GHC.TypeLits--import Test.Framework-import Test.Framework.Providers.QuickCheck2-import Test.QuickCheck---prop_add :: forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Int -> Bool-prop_add _ x y = (fromIntegral $ x + y) == ((fromIntegral x) + (fromIntegral y :: ZqBasic q Int))--prop_mul :: forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Int -> Bool-prop_mul _ x y = (fromIntegral $ x * y) == ((fromIntegral x) * (fromIntegral y :: ZqBasic q Int))--prop_recip :: forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Bool-prop_recip _ x = let qval = proxy value (Proxy::Proxy q)-                     y = fromIntegral x :: ZqBasic q Int-                 in if (x `mod` qval) == 0-                    then True-                    else (fromIntegral (1::Int)) == (y * (recip y))--type ZqModuli = '[7, 13, 17, 11, 13, 29]--class CallZqProp xs where-  callProp :: Proxy xs -> Gen Int -> (forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Int -> Bool) -> [Test]--  callProp2 :: Proxy xs -                -> Gen Int -                -> (forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Bool)-                -> [Test]--instance CallZqProp '[] where-  callProp _ _ _ = []-  callProp2 _ _ _ = []--instance (CallZqProp qs, KnownNat q) => CallZqProp (q ': qs) where-  callProp _ gen f = (testProperty ("q = " ++ (show $ (proxy value (Proxy::Proxy q) :: Int))) $ property $ liftM2 (f (Proxy::Proxy q)) gen gen) : (callProp (Proxy::Proxy qs) gen f)-  callProp2 _ gen f = (testProperty ("q = " ++ (show $ (proxy value (Proxy::Proxy q) :: Int))) $ property $ liftM (f (Proxy::Proxy q)) gen) : (callProp2 (Proxy::Proxy qs) gen f)--zqModuli :: Proxy ZqModuli-zqModuli = Proxy--zqTests :: [Test]-zqTests = -  [testGroup "ZqBasic +" $ callProp zqModuli (choose (-100,100)) prop_add,-   testGroup "ZqBasic *" $ callProp zqModuli (choose (-100,100)) prop_mul,-   testGroup "ZqBasic recip" $ callProp2 zqModuli (choose (-100,100)) prop_recip]
+ tests/CycTests.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE DataKinds, FlexibleContexts, NoImplicitPrelude, PolyKinds,+             ScopedTypeVariables, TypeOperators, TypeFamilies #-}+module CycTests (cycTests) where++import Control.Monad (liftM2,join)++import Crypto.Lol+import Crypto.Lol.Types.ZPP++import Test.Framework (buildTest)++import Utils+import Harness.Cyc+import Tests++cycTests = [+  testGroupM "coeffsPow" $ applyTwoIdx (Proxy::Proxy '[])      $ hideArgs prop_coeffsBasis,+  testGroupM "mulGPow" $ applyBasic (Proxy::Proxy AllParams)   $ hideArgs prop_mulgPow,+  testGroupM "mulGDec" $ applyBasic (Proxy::Proxy AllParams)   $ hideArgs prop_mulgDec,+  testGroupM "mulGCRT" $ applyBasic (Proxy::Proxy AllParams)   $ hideArgs prop_mulgCRT,+  testGroupM "crtSet"  $ applyBasis (Proxy::Proxy BasisParams) $ hideArgs prop_crtSet_pairs+  ]++prop_mulgPow :: (CElt t r, Fact m, Eq r) => Cyc t m r -> Test '(t,m,r)+prop_mulgPow x =+  let y = advisePow x+  in test $ y == (fromJust' "prop_mulgPow failed divisibility!" $ divG $ mulG y)++prop_mulgDec :: (CElt t r, Fact m, Eq r) => Cyc t m r -> Test '(t,m,r)+prop_mulgDec x = +  let y = adviseDec x+  in test $ y == (fromJust' "prop_mulgDec failed divisibility!" $ divG $ mulG y)++prop_mulgCRT :: (CElt t r, Fact m, Eq r) => Cyc t m r -> Test '(t,m,r)+prop_mulgCRT x = +  let y = adviseCRT x+  in test $ y == (fromJust' "prop_mulgCRT failed divisibility!" $ divG $ mulG y)++prop_coeffsBasis :: forall t m m' r . (m `Divides` m', CElt t r, Eq r)+  => Cyc t m' r -> Test '(t,m,m',r)+prop_coeffsBasis x = +  let xs = map embed (coeffsCyc Pow x :: [Cyc t m r])+      bs = proxy powBasis (Proxy::Proxy m)+  in test $ (sum $ zipWith (*) xs bs) == x++-- verifies that CRT set elements satisfy c_i * c_j = delta_ij * c_i+-- necessary (but not sufficient) condition+prop_crtSet_pairs :: forall t m m' r . (m `Divides` m', ZPP r, Eq r, CElt t r, CElt t (ZpOf r))+  => Test '(t,m,m',r)+prop_crtSet_pairs = +  let crtset = proxy crtSet (Proxy::Proxy m) :: [Cyc t m' r]+      pairs = join (liftM2 (,)) crtset+  in test $ and $ map (\(a,b) -> if a == b then a*b == a else a*b == zero) pairs++type Tensors = '[CT,RT]+type MRCombos = +  '[ '(F7, Zq 29),+     '(F7, Zq 32),+     '(F12, Zq 2148249601),+     '(F1, Zq 17),+     '(F2, Zq 17),+     '(F4, Zq 17),+     '(F8, Zq 17),+     '(F21, Zq 8191),+     '(F42, Zq 8191),+     '(F42, Zq 18869761),+     '(F42, Zq 1024),+     '(F42, Zq (18869761 ** 19393921)),+     '(F89, Zq 179)+    ]++type MM'RCombos = '[+  '(F1, F7, Zq PP8),+  '(F1, F7, Zq PP2)+  ]++type AllParams = ( '(,) <$> Tensors) <*> MRCombos+type BasisParams = ( '(,) <$> Tensors) <*> MM'RCombos++-- for crtSet, take all pairwise products +-- if elts are equal, id+-- if not, zero++-- also do a cardinality check++-- checks cardinality of the CRT set+{-+prop_crtSet_card pm _+  let inferLen = length $ (proxy crtSetDec pm :: [t m' r])+      expectLen = +  in  +-}
+ tests/Main.hs view
@@ -0,0 +1,14 @@++import TensorTests+import CycTests+import ZqTests++import Test.Framework++main :: IO ()+main = do+  flip defaultMainWithArgs ["--threads=1","--maximum-generated-tests=100"]+    [ testGroup "Tensor Tests" tensorTests+     ,testGroup "Cyc Tests" cycTests+     ,testGroup "Zq Tests" zqTests+    ]
+ tests/TensorTests.hs view
@@ -0,0 +1,343 @@+{-# LANGUAGE ConstraintKinds, FlexibleContexts, DataKinds, NoImplicitPrelude, +             RebindableSyntax, ScopedTypeVariables, TypeFamilies, TypeOperators,+             UndecidableInstances #-}++module TensorTests (tensorTests) where++import Harness.Cyc+import Tests+import Utils++import TestTypes++import Crypto.Lol+import Crypto.Lol.CRTrans+import Crypto.Lol.Cyclotomic.Tensor++import Control.Applicative+import Control.Monad.Random++import Data.Maybe++import Data.Singletons+import Data.Promotion.Prelude.List+import Data.Promotion.Prelude.Eq+import Data.Singletons.TypeRepStar++tensorTests = +  [testGroupM "fmapT comparison" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_fmapT,+   testGroupM "fmap comparison"  $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_fmap,+   testGroup  "GInv.G == id"       gInvGTests,+   testGroupM "CRTInv.CRT == id" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_crt_inv,+   testGroupM "LInv.L == id"     $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_l_inv,+   testGroupM "Scalar"           $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_scalar_crt,+   testGroup  "G commutes with L"  gCommuteTests,+   testGroupM "Extension Mult"   $ applyBasic (Proxy::Proxy ExtParams) $ hideArgs prop_mul_ext,+   testGroupM "GSqNormDec"       $ applyLift (Proxy::Proxy NormParams) $ hideArgs prop_gsqnorm,+   testGroup  "Tw.Em == id"        tremTests,+   testGroup  "Em commutes with L" embedCommuteTests,+   testGroup "Tw commutes with L"  twaceCommuteTests,+   testGroup  "Twace invariants"   twaceInvarTests+   ]++prop_fmapT :: (Tensor t, TElt t r, Fact m, Eq r) => t m r -> Test '(t,m,r)+prop_fmapT x = test $ fmapT id x == x \\ witness entailEqT x \\ witness entailIndexT x++prop_fmap :: (Tensor t, TElt t r, Fact m, Eq r) => t m r -> Test '(t,m,r)+prop_fmap x = test $ (fmap id x) == x \\ witness entailEqT x \\ witness entailIndexT x++-- divG . mulG == id in Pow basis+prop_ginv_pow :: (Tensor t, TElt t r, Fact m, Eq r, Ring r, ZeroTestable r, IntegralDomain r) +  => t m r -> Test '(t,m,r)+prop_ginv_pow x = test $ (fromMaybe (error "could not divide by G in prop_ginv_pow") $ +  divGPow $ mulGPow x) == x \\ witness entailEqT x++-- divG . mulG == id in Dec basis+prop_ginv_dec :: (Tensor t, TElt t r, Fact m, Eq r, Ring r, ZeroTestable r, IntegralDomain r) +  => t m r -> Test '(t,m,r)+prop_ginv_dec x = test $ (fromMaybe (error "could not divide by G in prop_ginv_dec") $ +  divGDec $ mulGDec x) == x \\ witness entailEqT x++-- divG . mulG == id in CRT basis+prop_ginv_crt :: (Tensor t, TElt t r, Fact m, Eq r, ZeroTestable r, IntegralDomain r, CRTrans r) +  => t m r -> Test '(t,m,r)+prop_ginv_crt x = test $ fromMaybe (error "no CRT in prop_ginv_crt") $ do+  divGCRT' <- divGCRT+  mulGCRT' <- mulGCRT+  return $ (divGCRT' $ mulGCRT' x) == x \\ witness entailEqT x++gInvGTests =  [+  testGroupM "Pow basis" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_ginv_pow,+  testGroupM "Dec basis" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_ginv_dec,+  testGroupM "CRT basis" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_ginv_crt]++-- mulGDec == lInv. mulGPow . l+prop_g_dec :: (Tensor t, Ring r, Fact m, TElt t r, Eq r) => t m r -> Test '(t,m,r)+prop_g_dec x = test $ (mulGDec x) == (lInv $ mulGPow $ l x) \\ witness entailEqT x++prop_g_crt :: (Tensor t, TElt t r, Fact m, Eq r, ZeroTestable r, IntegralDomain r, CRTrans r) +  => t m r -> Test '(t,m,r)+prop_g_crt x = test $ fromMaybe (error "no CRT in prop_g_crt") $ do+  mulGCRT' <- mulGCRT+  crt' <- crt+  crtInv' <- crtInv+  return $ (mulGCRT' x) == (crt' $ mulGPow $ crtInv' x) \\ witness entailEqT x++gCommuteTests =  [+  testGroupM "Dec basis" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_g_dec,+  testGroupM "CRT basis" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_g_crt]++-- crtInv . crt == id+prop_crt_inv :: (Tensor t, TElt t r, Fact m, Eq r, ZeroTestable r, IntegralDomain r, CRTrans r) +  => t m r -> Test '(t,m,r)+prop_crt_inv x = test $ fromMaybe (error "no CRT in prop_crt_inv") $ do+  crt' <- crt+  crtInv' <- crtInv+  return $ (crtInv' $ crt' x) == x \\ witness entailEqT x++-- lInv . l == id+prop_l_inv :: (Tensor t, Ring r, Eq r, Fact m, TElt t r) => t m r -> Test '(t,m,r)+prop_l_inv x = test $ (lInv $ l x) == x \\ witness entailEqT x++-- scalarCRT = crt . scalarPow+prop_scalar_crt :: forall t m r . (Tensor t, TElt t r, Fact m, Eq r, ZeroTestable r, IntegralDomain r, CRTrans r)+                => r -> Test '(t,m,r)+prop_scalar_crt r = test $ fromMaybe (error "no CRT in prop_scalar_crt") $ do+  scalarCRT' <- scalarCRT+  crt' <- crt+  return $ (scalarCRT' r :: t m r) == (crt' $ scalarPow r)+  \\ proxy entailEqT (Proxy::Proxy (t m r))++++-- tests that multiplication in the extension ring matches CRT multiplication+prop_mul_ext :: forall t m r . (Tensor t, Fact m, TElt t r, TElt t (CRTExt r), CRTrans r, CRTEmbed r, Ring r, Eq r)+  => t m r -> t m r -> Test '(t,m,r)+prop_mul_ext x y = test $+  let m = proxy valueFact (Proxy::Proxy m)+  in case (crtInfo m :: Maybe (CRTInfo r)) of+       Nothing -> error "mul have a CRT to call prop_mul_ext"+       Just _ -> (let z = zipWithT (*) x y+                      z' = fmapT fromExt $ zipWithT (*) (fmapT toExt x) (fmapT toExt y)+                  in z == z') \\ witness entailEqT x +                              \\ witness entailIndexT x++type NormCtx t m r = (TElt t r, TElt t (LiftOf r), +  Fact m, Lift' r, CRTrans r, Eq (LiftOf r),+  ZeroTestable r, Ring (LiftOf r), Ring r, IntegralDomain r)++type NormWrapCtx m r = (NormCtx CT m r, NormCtx RT m r)++-- tests that gSqNormDec of two "random-looking" vectors agrees for RT and CT+-- t is a dummy param+prop_gsqnorm :: forall t m r . +  (NormWrapCtx m r, NormCtx t m r) +  => r -> Test '(t,m,r)+prop_gsqnorm x = test $+  let crtCT = fromJust crt+      crtRT = fromJust crt+      -- not mathematically meaningful, we just need some "random" coefficients+      ct = fmapT lift (mulGDec $ lInv $ crtCT $ scalarPow x :: CT m r)+      rt = fmapT lift (mulGDec $ lInv $ crtRT $ scalarPow x :: RT m r)+  in gSqNormDec ct == gSqNormDec rt+++type TMM'RCtx t m m' r = +  (Tensor t, m `Divides` m', TElt t r, Ring r, +   CRTrans r, Eq r, ZeroTestable r, IntegralDomain r)++-- groups related tests+tremTests = [+  testGroupM "Pow basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_trem_pow,+  testGroupM "Dec basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_trem_dec,+  testGroupM "CRT basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_trem_crt]++-- tests that twace . embed == id in the Pow basis+prop_trem_pow :: forall t m m' r . (TMM'RCtx t m m' r)+  => t m r -> Test '(t,m,m',r)+prop_trem_pow x = test $ (twacePowDec $ (embedPow x :: t m' r)) == x \\ witness entailEqT x++-- tests that twace . embed == id in the Dec basis+prop_trem_dec :: forall t m m' r . (TMM'RCtx t m m' r)+  => t m r -> Test '(t,m,m',r)+prop_trem_dec x = test $ (twacePowDec $ (embedDec x :: t m' r)) == x \\ witness entailEqT x++-- tests that twace . embed == id in the CRT basis+prop_trem_crt :: forall t m m' r . (TMM'RCtx t m m' r)+  => t m r -> Test '(t,m,m',r)+prop_trem_crt x = test $ fromMaybe (error "no CRT in prop_trem_crt") $+  (x==) <$> (twaceCRT <*> (embedCRT <*> pure x :: Maybe (t m' r))) \\ witness entailEqT x++++embedCommuteTests = [+  testGroupM "Dec basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_embed_dec,+  testGroupM "CRT basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_embed_crt]++-- embedDec == lInv . embedPow . l+prop_embed_dec :: forall t m m' r . (TMM'RCtx t m m' r) => t m r -> Test '(t,m,m',r)+prop_embed_dec x = test $ (embedDec x :: t m' r) == (lInv $ embedPow $ l x) +  \\ proxy entailEqT (Proxy::Proxy (t m' r))++-- embedCRT = crt . embedPow . crtInv+prop_embed_crt :: forall t m m' r . (TMM'RCtx t m m' r) => t m r -> Test '(t,m,m',r)+prop_embed_crt x = test $ fromMaybe (error "no CRT in prop_embed_crt") $ do+  crt' <- crt+  crtInv' <- crtInv+  embedCRT' <- embedCRT+  return $ (embedCRT' x :: t m' r) == (crt' $ embedPow $ crtInv' x) +    \\ proxy entailEqT (Proxy::Proxy (t m' r))++twaceCommuteTests = [+  testGroupM "Dec basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_twace_dec,+  testGroupM "CRT basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_twace_crt]++-- twacePowDec = lInv . twacePowDec . l+prop_twace_dec :: forall t m m' r . (TMM'RCtx t m m' r) => t m' r -> Test '(t,m,m',r)+prop_twace_dec x = test $ (twacePowDec x :: t m r) == (lInv $ twacePowDec $ l x)+  \\ proxy entailEqT (Proxy::Proxy (t m r))++-- twaceCRT = crt . twacePowDec . crtInv+prop_twace_crt :: forall t m m' r . (TMM'RCtx t m m' r) => t m' r -> Test '(t,m,m',r)+prop_twace_crt x = test $ fromMaybe (error "no CRT in prop_trace_crt") $ do+  twaceCRT' <- twaceCRT+  crt' <- crt+  crtInv' <- crtInv+  return $ (twaceCRT' x :: t m r) == (crt' $ twacePowDec $ crtInv' x)+    \\ proxy entailEqT (Proxy::Proxy (t m r))++twaceInvarTests = [+  testGroupM "Tw and Em ID for equal indices" $ applyBasic (Proxy::Proxy TMRParams) $ hideArgs prop_twEmID,+  testGroupM "Invar1 Pow basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_twace_invar1_pow,+  testGroupM "Invar1 Dec basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_twace_invar1_dec,+  testGroupM "Invar1 CRT basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_twace_invar1_crt,+  testGroupM "Invar2 Pow/Dec basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_twace_invar2_powdec,+  testGroupM "Invar2 CRT basis" $ applyTwoIdx (Proxy::Proxy TrEmParams) $ hideArgs prop_twace_invar2_crt+  ]++prop_twEmID :: forall t m r . (Tensor t, TElt t r, CRTrans r, Fact m, m `Divides` m, Eq r, ZeroTestable r, IntegralDomain r) +  => t m r -> Test '(t,m,r)+prop_twEmID x = test $ +  ((twacePowDec x) == x) &&+   (((fromMaybe (error "twemid_crt") twaceCRT) x) == x) &&+   ((embedPow x) == x) &&+   ((embedDec x) == x) &&+   (((fromMaybe (error "twemid_crt") embedCRT) x) == x) \\ witness entailEqT x++-- twace mhat'/g' = mhat*totm'/totm/g (Pow basis)+prop_twace_invar1_pow :: forall t m m' r . (TMM'RCtx t m m' r) +  => Test '(t,m,m',r)+prop_twace_invar1_pow = test $ fromMaybe (error "could not divide by G in prop_twace_invar1_pow") $ do+  let mhat = proxy valueHatFact (Proxy::Proxy m)+      mhat' = proxy valueHatFact (Proxy::Proxy m')+      totm = proxy totientFact (Proxy::Proxy m)+      totm' = proxy totientFact (Proxy::Proxy m')+  output :: t m r <- divGPow $ scalarPow $ fromIntegral $ mhat * totm' `div` totm+  input :: t m' r <- divGPow $ scalarPow $ fromIntegral mhat'+  return $ (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))++-- twace mhat'/g' = mhat*totm'/totm/g (Dec basis)+prop_twace_invar1_dec :: forall t m m' r . (TMM'RCtx t m m' r) => Test '(t,m,m',r)+prop_twace_invar1_dec = test $ fromMaybe (error "could not divide by G in prop_twace_invar1_dec") $ do+  let mhat = proxy valueHatFact (Proxy::Proxy m)+      mhat' = proxy valueHatFact (Proxy::Proxy m')+      totm = proxy totientFact (Proxy::Proxy m)+      totm' = proxy totientFact (Proxy::Proxy m')+  output :: t m r <- divGDec $ lInv $ scalarPow $ fromIntegral $ mhat * totm' `div` totm+  input :: t m' r <- divGDec $ lInv $ scalarPow $ fromIntegral mhat'+  return $ (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))++-- twace mhat'/g' = mhat*totm'/totm/g (CRT basis)+prop_twace_invar1_crt :: forall t m m' r . (TMM'RCtx t m m' r) => Test '(t,m,m',r)+prop_twace_invar1_crt = test $ fromMaybe (error "no CRT in prop_twace_invar1_crt") $ do+  let mhat = proxy valueHatFact (Proxy::Proxy m)+      mhat' = proxy valueHatFact (Proxy::Proxy m')+      totm = proxy totientFact (Proxy::Proxy m)+      totm' = proxy totientFact (Proxy::Proxy m')+  scalarCRT1 <- scalarCRT+  scalarCRT2 <- scalarCRT+  divGCRT1 <- divGCRT+  divGCRT2 <- divGCRT+  twaceCRT' <- twaceCRT+  let output :: t m r = divGCRT1 $ scalarCRT1 $ fromIntegral $ mhat * totm' `div` totm+      input :: t m' r = divGCRT2 $ scalarCRT2 $ fromIntegral mhat'+  return $ (twaceCRT' input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))++-- twace preserves scalars in Pow/Dec basis+prop_twace_invar2_powdec :: forall t m m' r . (TMM'RCtx t m m' r) => Test '(t,m,m',r)+prop_twace_invar2_powdec = test $+  let output = scalarPow $ one :: t m r+      input = scalarPow $ one :: t m' r+  in (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))++-- twace preserves scalars in Pow/Dec basis+prop_twace_invar2_crt :: forall t m m' r . (TMM'RCtx t m m' r) => Test '(t,m,m',r)+prop_twace_invar2_crt = test $ fromMaybe (error "no CRT in prop_twace_invar2_crt") $ do+  scalarCRT1 <- scalarCRT+  scalarCRT2 <- scalarCRT+  let input = scalarCRT1 one :: t m' r+      output = scalarCRT2 one :: t m r+  return $ (twacePowDec input) == output \\ proxy entailEqT (Proxy::Proxy (t m r))++++++type Tensors = '[CT,RT]+type MRCombos = '[+  '(F7, Zq 29),+  '(F12, SmoothZQ1),+  '(F1, Zq 17),+  '(F2, Zq 17),+  '(F4, Zq 17),+  '(F8, Zq 17),+  '(F21, Zq 8191),+  '(F42, Zq 8191),+  '(F42, ZQ1),+  '(F2, ZQ2),+  '(F3, ZQ2),+  '(F7, ZQ2),+  '(F6, ZQ2),+  '(F42, SmoothZQ3),+  '(F42, ZQ2),+  '(F89, Zq 179)+  ]++-- we can't include a large modulus here because there is not enough+-- precision in Doubles to handle the error+type MRExtCombos = '[+  '(F7, Zq 29),+  '(F1, Zq 17),+  '(F2, Zq 17),+  '(F4, Zq 17),+  '(F8, Zq 17),+  '(F21, Zq 8191),+  '(F42, Zq 8191),+  '(F42, ZQ1),+  '(F42, ZQ2),+  '(F89, Zq 179)+  ]++type MM'RCombos = '[+  '(F1, F7, Zq 29),+  '(F4, F12, Zq 536871001),+  '(F4, F12, SmoothZQ1),+  '(F2, F8, Zq 17),+  '(F8, F8, Zq 17),+  '(F2, F8, SmoothZQ1),+  '(F4, F8, Zq 17),+  '(F3, F21, Zq 8191),+  '(F7, F21, Zq 8191),+  '(F3, F42, Zq 8191),+  '(F3, F21, ZQ1),+  '(F7, F21, ZQ2),+  '(F3, F42, ZQ3)+  ]++type TMRParams = ( '(,) <$> Tensors) <*> MRCombos+type ExtParams = ( '(,) <$> Tensors) <*> MRExtCombos+type TrEmParams = ( '(,) <$> Tensors) <*> MM'RCombos+type NormParams = ( '(,) <$> '[RT]) <*> (Filter Liftable MRCombos)++data Liftable :: TyFun (Factored, *) Bool -> *+type instance Apply Liftable '(m,zq) = Int64 :== (LiftOf zq)
+ tests/ZqTests.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE NoImplicitPrelude, RebindableSyntax, ScopedTypeVariables, DataKinds, TypeOperators, PolyKinds, FlexibleContexts, RankNTypes, KindSignatures, MultiParamTypeClasses #-}++module ZqTests (zqTests) where++import Crypto.Lol.Types.ZqBasic+import Crypto.Lol.LatticePrelude hiding (Nat)+import Crypto.Lol.Reflects++import Control.Monad++import GHC.TypeLits++import Test.Framework+import Test.Framework.Providers.QuickCheck2+import Test.QuickCheck+++prop_add :: forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Int -> Bool+prop_add _ x y = (fromIntegral $ x + y) == ((fromIntegral x) + (fromIntegral y :: ZqBasic q Int))++prop_mul :: forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Int -> Bool+prop_mul _ x y = (fromIntegral $ x * y) == ((fromIntegral x) * (fromIntegral y :: ZqBasic q Int))++prop_recip :: forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Bool+prop_recip _ x = let qval = proxy value (Proxy::Proxy q)+                     y = fromIntegral x :: ZqBasic q Int+                 in if (x `mod` qval) == 0+                    then True+                    else (fromIntegral (1::Int)) == (y * (recip y))++type ZqModuli = '[7, 13, 17, 11, 13, 29]++class CallZqProp xs where+  callProp :: Proxy xs -> Gen Int -> (forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Int -> Bool) -> [Test]++  callProp2 :: Proxy xs +                -> Gen Int +                -> (forall (q :: Nat) . (Reflects q Int, KnownNat q) => Proxy q -> Int -> Bool)+                -> [Test]++instance CallZqProp '[] where+  callProp _ _ _ = []+  callProp2 _ _ _ = []++instance (CallZqProp qs, KnownNat q) => CallZqProp (q ': qs) where+  callProp _ gen f = (testProperty ("q = " ++ (show $ (proxy value (Proxy::Proxy q) :: Int))) $ property $ liftM2 (f (Proxy::Proxy q)) gen gen) : (callProp (Proxy::Proxy qs) gen f)+  callProp2 _ gen f = (testProperty ("q = " ++ (show $ (proxy value (Proxy::Proxy q) :: Int))) $ property $ liftM (f (Proxy::Proxy q)) gen) : (callProp2 (Proxy::Proxy qs) gen f)++zqModuli :: Proxy ZqModuli+zqModuli = Proxy++zqTests :: [Test]+zqTests = +  [testGroup "ZqBasic +" $ callProp zqModuli (choose (-100,100)) prop_add,+   testGroup "ZqBasic *" $ callProp zqModuli (choose (-100,100)) prop_mul,+   testGroup "ZqBasic recip" $ callProp2 zqModuli (choose (-100,100)) prop_recip]
+ utils/Apply.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE DataKinds, FlexibleInstances, MultiParamTypeClasses, PolyKinds, +             TypeFamilies, TypeOperators #-}++-- applies functions to proxy arguments+module Apply where++class (params :: [k]) `Satisfy` (ctx :: *)  where+  data ArgsCtx ctx++  run :: proxy params+            -> (ArgsCtx ctx -> rnd res) +            -> [rnd res]++instance '[] `Satisfy` ctx  where+  -- any implementation of ArgsCtx would conflict with concrete instances,+  -- so skip  +  run _ _ = []
+ utils/Benchmarks.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, +             PolyKinds, RankNTypes, ScopedTypeVariables, TypeFamilies #-}++module Benchmarks +(Benchmarks.bench+,benchIO+,benchGroup+,hideArgs+,Bench(..)+,Benchmark+,NFData) where++import Gen+import Utils++import Control.DeepSeq+import Control.Monad.Random+import Control.Monad.State+import Criterion as C++import Data.Proxy++-- wrapper for Criterion's `nf`+bench :: NFData b => (a -> b) -> a -> Bench params+bench f = Bench . nf f++-- wrapper for Criterion's `nfIO`+benchIO :: NFData b => IO b -> Bench params+benchIO = Bench . nfIO++-- wrapper for Criterion's +benchGroup :: (Monad rnd) => String -> [rnd Benchmark] -> rnd Benchmark+benchGroup str = (bgroup str <$>) . sequence++-- normalizes any function resulting in a Benchmark to +-- one that takes a proxy for its arguments+hideArgs :: (GenArgs rnd bnch, Monad rnd, ShowType a,+             ResultOf bnch ~ Bench a)+  => bnch -> Proxy a -> rnd Benchmark+hideArgs f p = (C.bench (showType p) . unbench) <$> genArgs f++newtype Bench params = Bench {unbench :: Benchmarkable}++instance (Monad rnd) => GenArgs rnd (Bench params) where+  type ResultOf (Bench params) = Bench params+  genArgs = return
+ utils/Gen.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, TypeFamilies #-}++-- generates arguments to functions+module Gen where++import Control.Monad.Random++-- bnch represents a function whose arguments can be generated,+-- resulting in a "NFValue"+class GenArgs rnd bnch where+  type ResultOf bnch+  genArgs :: bnch -> rnd (ResultOf bnch)++instance (Generatable rnd a, GenArgs rnd b, +          Monad rnd, ResultOf b ~ ResultOf (a -> b)) +  => GenArgs rnd (a -> b) where+  type ResultOf (a -> b) = ResultOf b+  genArgs f = do+    x <- genArg+    genArgs $ f x++-- a parameter that can be generated using a particular monad+class Generatable rnd arg where+  genArg :: rnd arg++instance {-# Overlappable #-} (Random a, MonadRandom rnd) => Generatable rnd a where+  genArg = getRandom
+ utils/Harness/Cyc.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts, FlexibleInstances, +             GADTs, MultiParamTypeClasses, NoImplicitPrelude, PolyKinds, RankNTypes, +             ScopedTypeVariables, TypeFamilies, TypeOperators, UndecidableInstances #-}++module Harness.Cyc where++import Control.Applicative+import Control.Monad.Random++import Crypto.Lol+import Crypto.Lol.Cyclotomic.Tensor+import Crypto.Lol.Types.ZPP+import Crypto.Random.DRBG++import Data.Vector.Storable++import Utils+import Gen+import Apply++data BasicCtxD+type BasicCtx t m r = +  (CElt t r, Fact m, Random r, Eq r, NFElt r, ShowType '(t,m,r), Random (t m r), m `Divides` m)+instance (params `Satisfy` BasicCtxD, BasicCtx t m r) +  => ( '(t, '(m,r)) ': params) `Satisfy` BasicCtxD where+  data ArgsCtx BasicCtxD where+    BC :: (BasicCtx t m r) => Proxy '(t,m,r) -> ArgsCtx BasicCtxD+  run _ f = (f $ BC (Proxy::Proxy '(t,m,r))) : (run (Proxy::Proxy params) f)++applyBasic :: (params `Satisfy` BasicCtxD, MonadRandom rnd) =>+  Proxy params +  -> (forall t m r . (BasicCtx t m r, Generatable rnd r, Generatable rnd (t m r)) +       => Proxy '(t,m,r) -> rnd res)+  -> [rnd res]+applyBasic params g = run params $ \(BC p) -> g p++-- r is Liftable+data LiftCtxD+type LiftCtx t m r = +  (BasicCtx t m r, Lift' r, CElt t (LiftOf r), NFElt (LiftOf r), ToInteger (LiftOf r), +   TElt CT r, TElt RT r, TElt CT (LiftOf r), TElt RT (LiftOf r))+instance (params `Satisfy` LiftCtxD, LiftCtx t m r) +  => ( '(t, '(m,r)) ': params) `Satisfy` LiftCtxD  where+  data ArgsCtx LiftCtxD where+    LC :: (LiftCtx t m r) => Proxy '(t,m,r) -> ArgsCtx LiftCtxD+  run _ f = (f $ LC (Proxy::Proxy '(t,m,r))) : (run (Proxy::Proxy params) f)++applyLift :: (params `Satisfy` LiftCtxD, MonadRandom rnd) =>+  Proxy params +  -> (forall t m r . (LiftCtx t m r, Generatable rnd r) => Proxy '(t,m,r) -> rnd res) +  -> [rnd res]+applyLift params g = run params $ \(LC p) -> g p++-- similar to LiftCtxD, but with a `gen` param+data ErrorCtxD+type ErrorCtx t m r gen = (CElt t r, Fact m, ShowType '(t,m,r,gen), +                           CElt t (LiftOf r), NFElt (LiftOf r), Lift' r, +                           ToInteger (LiftOf r), CryptoRandomGen gen)+instance (params `Satisfy` ErrorCtxD, ErrorCtx t m r gen) +  => ( '(gen, '(t, '(m,r))) ': params) `Satisfy` ErrorCtxD  where+  data ArgsCtx ErrorCtxD where+    EC :: (ErrorCtx t m r gen) => Proxy '(t,m,r,gen) -> ArgsCtx ErrorCtxD+  run _ f = (f $ EC (Proxy::Proxy '(t,m,r,gen))) : (run (Proxy::Proxy params) f)++applyError :: (params `Satisfy` ErrorCtxD, Monad rnd) =>+  Proxy params +  -> (forall t m r gen . (ErrorCtx t m r gen) => Proxy '(t,m,r,gen) -> rnd res) +  -> [rnd res]+applyError params g = run params $ \(EC p) -> g p+++data TwoIdxCtxD+type TwoIdxCtx t m m' r = (m `Divides` m', CElt t r, Eq r, Random r, NFElt r, ShowType '(t,m,m',r), Random (t m r), Random (t m' r))++instance (params `Satisfy` TwoIdxCtxD, TwoIdxCtx t m m' r) +  => ( '(t, '(m,m',r)) ': params) `Satisfy` TwoIdxCtxD where+  data ArgsCtx TwoIdxCtxD where+    TI :: (TwoIdxCtx t m m' r) => Proxy '(t,m,m',r) -> ArgsCtx TwoIdxCtxD+  run _ f = (f $ TI (Proxy::Proxy '(t,m,m',r))) : (run (Proxy::Proxy params) f)++applyTwoIdx :: (params `Satisfy` TwoIdxCtxD, MonadRandom rnd) =>+  Proxy params +  -> (forall t m m' r . (TwoIdxCtx t m m' r, Generatable rnd (t m r), Generatable rnd (t m' r)) +        => Proxy '(t,m,m',r) -> rnd res) +  -> [rnd res]+applyTwoIdx params g = run params $ \(TI p) -> g p++-- similar to TwoIdxCtxD, but r must be a prime-power+data BasisCtxD+type BasisCtx t m m' r = (m `Divides` m', Eq r, ZPP r, CElt t r, CElt t (ZpOf r), ShowType '(t,m,m',r))++instance (params `Satisfy` BasisCtxD, BasisCtx t m m' r)+  => ( '(t, '(m,m',r)) ': params) `Satisfy` BasisCtxD where+  data ArgsCtx BasisCtxD where+    BsC :: (BasisCtx t m m' r) => Proxy '(t,m,m',r) -> ArgsCtx BasisCtxD+  run _ f = (f $ BsC (Proxy::Proxy '(t,m,m',r))) : (run (Proxy::Proxy params) f)++applyBasis :: (params `Satisfy` BasisCtxD) =>+  Proxy params+  -> (forall t m m' r . (BasisCtx t m m' r) => Proxy '(t,m,m',r) -> rnd res)+  -> [rnd res]+applyBasis params g = run params $ \(BsC p) -> g p
+ utils/TestTypes.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE ConstraintKinds, DataKinds, FlexibleContexts,+             FlexibleInstances, KindSignatures, MultiParamTypeClasses,+             NoImplicitPrelude, PolyKinds, RankNTypes, RebindableSyntax,+             ScopedTypeVariables, TypeFamilies, TypeOperators #-}++module TestTypes (++SmoothZQ1, SmoothZQ2, SmoothZQ3+, Zq, ZQ1, ZQ2, ZQ3) where++import Control.Monad+import Control.Monad.Random++import Crypto.Lol+import Crypto.Lol.Reflects++import Utils++import Test.QuickCheck.Monadic++instance (MonadRandom m) => MonadRandom (PropertyM m) where+  getRandom = run getRandom+  getRandoms = run getRandoms+  getRandomR r = run $ getRandomR r+  getRandomRs r = run $ getRandomRs r++-- three 24-bit moduli, enough to handle rounding for p=32 (depth-4 circuit at ~17 bits per mul)+type ZQ1 = Zq 18869761+type ZQ2 = Zq (19393921 ** 18869761)+type ZQ3 = Zq (19918081 ** 19393921 ** 18869761)++-- the next three moduli are "good" for any index dividing 128*27*25*7+type SmoothQ1 = 2148249601+type SmoothQ2 = 2148854401+type SmoothQ3 = 2150668801++type SmoothZQ1 = Zq 2148249601+type SmoothZQ2 = Zq (2148854401 ** 2148249601)+type SmoothZQ3 = Zq (2148854401 ** 2148249601 ** 2150668801)
+ utils/Tests.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE FlexibleContexts, FlexibleInstances, GADTs, MultiParamTypeClasses, +             PolyKinds, RankNTypes, ScopedTypeVariables, TypeFamilies #-}+module Tests+(test+,testIO+,TF.testGroup+,testGroupM+,hideArgs+,Test(..)) where++import Gen+import Utils++import Control.Monad.Random+import Control.Monad.State++import Data.Proxy++import qualified Test.Framework as TF+import Test.Framework.Providers.QuickCheck2+import Test.QuickCheck++test :: Bool -> Test params+test = Test++testIO :: (forall m . MonadRandom m => m Bool) -> Test params+testIO = TestM++testGroupM :: String -> [IO TF.Test] -> TF.Test+testGroupM str = TF.buildTest . (TF.testGroup str <$>) . sequence++-- normalizes any function resulting in a Benchmark to +-- one that takes a proxy for its arguments+hideArgs :: (GenArgs rnd bnch, MonadRandom rnd, ShowType a,+             ResultOf bnch ~ Test a)+  => bnch -> Proxy a -> rnd TF.Test+hideArgs f p = do+  res <- genArgs f+  case res of+    Test b -> return $ testProperty (showType p) b+    TestM b -> testProperty (showType p) <$> b++data Test params where+  Test :: Bool -> Test params+  TestM :: (forall m . MonadRandom m => m Bool) -> Test params++instance (MonadRandom rnd) => GenArgs rnd (Test params) where+  type ResultOf (Test params) = Test params+  genArgs = return
+ utils/Utils.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs,+             GeneralizedNewtypeDeriving, MultiParamTypeClasses, +             PolyKinds, RankNTypes, ConstraintKinds, ScopedTypeVariables, +             KindSignatures,+             TypeFamilies, TypeOperators, UndecidableInstances #-}++module Utils +(Zq+,type (**)+,type (<$>)+,type (<*>)++,module Data.Promotion.Prelude.List++,showType+,ShowType) where++import Control.Monad.Random+import Control.Monad (liftM)+import Control.Monad.State++import Control.DeepSeq++import Crypto.Lol (Int64,Fact,Factored,valueFact,Mod(..), Proxy(..), proxy, Cyc, RT, CT, LiftOf, TrivGad, BaseBGad)+import Crypto.Lol.Reflects+import Crypto.Lol.Types.ZqBasic+import Crypto.Random.DRBG++import Data.Promotion.Prelude.List+{-+import Math.NumberTheory.Primes.Testing (isPrime)++-- an infinite list of primes greater than the input and congruent to+-- 1 mod m+goodQs :: (Integral i) => i -> i -> [i]+goodQs m lower = checkVal (lower + ((m-lower) `mod` m) + 1)+  where checkVal v = if (isPrime (fromIntegral v :: Integer))+                     then v : checkVal (v+m)+                    else checkVal (v+m)+-}++infixr 9 **+data a ** b++type family Zq (a :: k) :: * where+  Zq (a ** b) = (Zq a, Zq b)+  Zq q = (ZqBasic q Int64)+++type family (f :: (k1 -> k2)) <$>  (xs :: [k1]) where+  f <$> '[] = '[]+  f <$> (x ': xs) = (f x) ': (f <$> xs)++type family (fs :: [k1 -> k2]) <*> (xs :: [k1]) where+  fs <*> xs = Go fs xs xs++type family Go (fs :: [k1 -> k2]) (xs :: [k1]) (ys :: [k1]) where+  Go '[] xs ys = '[]+  Go (f ': fs) '[] ys = Go fs ys ys+  Go (f ': fs) (x ': xs) ys = (f x) ': (Go (f ': fs) xs ys)++++++++-- a wrapper type for printing test/benchmark names+data ArgType (a :: k) = AT++-- allows automatic printing of test parameters+type ShowType a = Show (ArgType a)++showType :: forall a . (Show (ArgType a)) => Proxy a -> String+showType _ = show (AT :: ArgType a)++instance Show (ArgType HashDRBG) where+  show _ = "HashDRBG"++instance (Fact m) => Show (ArgType m) where+  show _ = "F" ++ (show $ proxy valueFact (Proxy::Proxy m))++instance (Mod (ZqBasic q i), Show i) => Show (ArgType (ZqBasic q i)) where+  show _ = "Q" ++ (show $ proxy modulus (Proxy::Proxy (ZqBasic q i)))++instance Show (ArgType RT) where+  show _ = "RT"++instance Show (ArgType CT) where+  show _ = "CT"++instance Show (ArgType Int64) where+  show _ = "Int64"++instance Show (ArgType TrivGad) where+  show _ = "TrivGad"++instance (Reflects b Integer) => Show (ArgType (BaseBGad (b :: k))) where+  show _ = "Base" ++ (show $ (proxy value (Proxy::Proxy b) :: Integer)) ++ "Gad"++-- for RNS-style moduli+instance (Show (ArgType a), Show (ArgType b)) => Show (ArgType (a,b)) where+  show _ = (show (AT :: ArgType a)) ++ "*" ++ (show (AT :: ArgType b))++-- we use tuples rather than lists because types in a list must have the same kind,+-- but tuples permit different kinds+instance (Show (ArgType a), Show (ArgType b)) +  => Show (ArgType '(a,b)) where+  show _ = (show (AT :: ArgType a)) ++ " " ++ (show (AT :: ArgType b))++instance (Show (ArgType a), Show (ArgType '(b,c))) +  => Show (ArgType '(a,b,c)) where+  show _ = (show (AT :: ArgType a)) ++ " " ++ (show (AT :: ArgType '(b,c)))++instance (Show (ArgType a), Show (ArgType '(b,c,d))) +  => Show (ArgType '(a,b,c,d)) where+  show _ = (show (AT :: ArgType a)) ++ " " ++ (show (AT :: ArgType '(b,c,d)))++instance (Show (ArgType a), Show (ArgType '(b,c,d,e))) +  => Show (ArgType '(a,b,c,d,e)) where+  show _ = (show (AT :: ArgType a)) ++ " " ++ (show (AT :: ArgType '(b,c,d,e)))++instance (Show (ArgType a), Show (ArgType '(b,c,d,e,f))) +  => Show (ArgType '(a,b,c,d,e,f)) where+  show _ = (show (AT :: ArgType a)) ++ " " ++ (show (AT :: ArgType '(b,c,d,e,f)))++instance (Show (ArgType a), Show (ArgType '(b,c,d,e,f,g))) +  => Show (ArgType '(a,b,c,d,e,f,g)) where+  show _ = (show (AT :: ArgType a)) ++ " " ++ (show (AT :: ArgType '(b,c,d,e,f,g)))++instance (Show (ArgType a), Show (ArgType '(b,c,d,e,f,g,h))) +  => Show (ArgType '(a,b,c,d,e,f,g,h)) where+  show _ = (show (AT :: ArgType a)) ++ " " ++ (show (AT :: ArgType '(b,c,d,e,f,g,h)))