module Crypto.Lol.Factored
(
Factored(..), SFactored, Fact
, PrimePower(..), SPrimePower, PPow, Sing (SPP)
, Nat, NatC, PrimeNat, Prime
, toPP, sToPP, ToPP, ppToF, sPpToF, PpToF, PToF
, unF, sUnF, UnF, unPP, sUnPP, UnPP, primePP, PrimePP, exponentPP, ExponentPP
, fPPMul, FPPMul, fMul, FMul, type (*)
, fDivides, FDivides, Divides, fDiv, FDiv, type (/)
, fGCD, FGCD, fLCM, FLCM, Coprime
, fOddRadical, FOddRadical
, pFree, PFree
, ppsFact, valueFact, totientFact, valueHatFact, radicalFact, oddRadicalFact
, ppPPow, primePPow, exponentPPow, valuePPow, totientPPow
, valueNatC
, transDivides, gcdDivides, lcmDivides, lcm2Divides
, pSplitTheorems, pFreeDivides
, (\\)
, valueHat
, PP, ppToPP, valuePP, totientPP, radicalPP, oddRadicalPP
, valuePPs, totientPPs, radicalPPs, oddRadicalPPs
, 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
(<<=) :: Nat -> Nat -> Bool
Z <<= _ = True
S _ <<= Z = False
S n <<= S m = n <<= m
singletons [d|
newtype PrimePower = PP (Nat,Nat) deriving (Eq,Show,Typeable)
newtype Factored = F [PrimePower] deriving (Eq,Show,Typeable)
unF :: Factored -> [PrimePower]
unF (F pps) = pps
unPP :: PrimePower -> (Nat,Nat)
unPP (PP pp) = pp
primePP, exponentPP :: PrimePower -> Nat
primePP = fst . unPP
exponentPP = snd . unPP
|]
singletons [d|
fPPMul :: PrimePower -> Factored -> Factored
fMul :: Factored -> Factored -> Factored
fPPMul (PP(_,Z)) y = y
fPPMul pp@(PP(_,S _)) (F pps) = F (ppMul pp pps)
fMul (F pps1) (F pps2) = F (ppsMul pps1 pps2)
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)
|]
singletons [d|
toPP :: Nat -> Nat -> PrimePower
toPP p e | primeNat p && (n1 <<= e) = PP (p,e)
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
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)
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,ee') : ppsDiv xs' ys'
else if p <<= p' then (PP (p,e)) : ppsDiv xs' (PP (p',e') : ys')
else error "type error in ppsDiv"
ppsOddRad :: [PrimePower] -> [PrimePower]
ppsOddRad [] = []
ppsOddRad (PP ((S (S Z)),_) : xs') = ppsOddRad xs'
ppsOddRad (PP (p@(S (S (S _))),_) : xs') = PP (p,n1) : ppsOddRad xs'
|]
singletons [d|
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 a / b = FDiv a b
type a * b = FMul a b
type PToF p = PpToF (ToPP p N1)
type Fact (m :: Factored) = SingI m
type PPow (pp :: PrimePower) = SingI pp
type NatC (p :: Nat) = SingI p
type Prime p = (NatC p, PrimeNat p ~ 'True)
type Divides m m' = (Fact m, Fact m', FDivides m m' ~ 'True)
type Coprime m m' = (FGCD m m' ~ F1)
coerceFDivs :: p m -> p' m' -> (() :- (FDivides m m' ~ True))
coerceFDivs _ _ = Sub $ unsafeCoerce (Dict :: Dict ())
coerceGCD :: p a -> p' a' -> p'' a'' -> (() :- (FGCD a a' ~ a''))
coerceGCD _ _ _ = Sub $ unsafeCoerce (Dict :: Dict ())
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
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
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)
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
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)
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 PP = (Int, Int)
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
valueFact = valuePPs <$> ppsFact
totientFact = totientPPs <$> ppsFact
valueHatFact = valueHat <$> valueFact
radicalFact = radicalPPs <$> ppsFact
oddRadicalFact = oddRadicalPPs <$> ppsFact
ppPPow :: forall pp . (PPow pp) => Tagged pp PP
ppPPow = tag $ ppToPP $ fromSing (sing :: SPrimePower pp)
primePPow, exponentPPow, valuePPow, totientPPow :: (PPow pp) => Tagged pp Int
primePPow = fst <$> ppPPow
exponentPPow = snd <$> ppPPow
valuePPow = valuePP <$> ppPPow
totientPPow = totientPP <$> ppPPow
valueNatC :: forall p . (NatC p) => Tagged p Int
valueNatC = tag $ sNatToInt (sing :: SNat p)
valueHat :: (Integral i) => i -> i
valueHat m = if m `mod` 2 == 0 then m `div` 2 else m
ppToPP :: PrimePower -> PP
ppToPP = (natToInt *** natToInt) . unPP
valuePP, totientPP, radicalPP, oddRadicalPP :: PP -> Int
valuePP (p,e) = p^e
totientPP (_,0) = 1
totientPP (p,e) = (p1)*(p^(e1))
radicalPP (_,0) = 1
radicalPP (p,_) = p
oddRadicalPP (_,0) = 1
oddRadicalPP (2,_) = 1
oddRadicalPP (p,_) = p
valuePPs, totientPPs, radicalPPs, oddRadicalPPs :: [PP] -> Int
valuePPs = product . map valuePP
totientPPs = product . map totientPP
radicalPPs = product . map radicalPP
oddRadicalPPs = product . map oddRadicalPP