Guest User

Quadratic Sieve

a guest
Dec 7th, 2012
589
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- A record representing the immutable data used during factoring
  2. data FactorData = FD { smoothNum :: Int,
  3.                        segSize :: Integer,
  4.                        factorBase :: [Integer],
  5.                        ceilSqrt :: Integer,
  6.                        quadF :: Integer -> Integer,
  7.                        toSieve :: [(Integer, [Integer])]
  8.                      }
  9.  
  10. -- Constructs the FactorData record given the number to factor
  11. -- TODO: smoothness bound or smoothness number?
  12. mkFactorData :: Integer -> FactorData
  13. mkFactorData n = FD {
  14.   smoothNum = sn,
  15.   segSize = 100000, -- temp
  16.   factorBase = fb,
  17.   ceilSqrt = cs,
  18.   quadF = \x -> (x + cs) * (x + cs) - n,
  19.   toSieve = map (\p -> (p, yRoots p)) fb
  20.   }
  21.   where
  22.     sn = 150 -- temp
  23.     fb = take sn $ filter (\p -> legendre n p == 1) primes
  24.     cs = ceiling $ (sqrt :: Float -> Float) $ fromIntegral n
  25.     yRoots p = map (\r -> (r - cs) `mod` p) (psqrt n p)
  26.  
  27. -- Do the sieving with the given prime and roots
  28. sieve' :: STArray s Integer Integer -> (Integer, [Integer]) -> ST s ()
  29. sieve' _ (_,[]) = error "polynomial should have at least one solution"
  30. sieve' a (p,rs) = mapM_ sieve'' rs
  31.  where
  32.    sieve'' r = do
  33.      (lo, hi) <- getBounds a
  34.      -- Get the first index that equals (r mod p)
  35.      let s = lo + mod (r - lo) p in
  36.        -- Sieve with p
  37.        forM_ [s, s + p .. hi]
  38.        (\i -> do
  39.            n <- readArray a i
  40.            writeArray a i (fst $ powsN n p))
  41.  
  42. -- Sieve the array with each of the (prime,roots) pairs
  43. sieve :: STArray s Integer Integer -> FactorData -> ST s ()
  44. sieve a = mapM_ (sieve' a) . toSieve
  45.  
  46. -- Fill the array with the initial values of the polynomial
  47. fill :: (Integer -> Integer) -> STArray s Integer Integer -> ST s ()
  48. fill f a = do
  49.   (lo, hi) <- getBounds a
  50.   forM_ [lo .. hi] (\i -> writeArray a i (f i))
  51.  
  52. -- Loop fusion may handle this, but explicitly writing it out will help
  53. -- me sleep at night
  54. filterMap :: (a -> Bool) -> (a -> b) -> [a] -> [b]
  55. filterMap _ _ [] = []
  56. filterMap p f (x:xs)
  57.   | p x       = f x : filterMap p f xs
  58.   | otherwise = filterMap p f xs
  59.  
  60. -- Rips the smooth numbers out of the sieved array
  61. rip :: FactorData -> Array Integer Integer -> [(Integer, Integer)]
  62. rip fd = (filterMap ((== 1) . snd) pair) . assocs
  63.   where pair (i,_) = (i + ceilSqrt fd, quadF fd i)
  64.  
  65. -- Creates an infinite list of smooth numbers
  66. doSieve :: FactorData -> [(Integer, Integer)]
  67. doSieve fd = concatMap (\i -> (rip fd) $ runSTArray $ do
  68.                            a <- newArray_ (i * s, (i + 1) * s)
  69.                            fill (quadF fd) a
  70.                            sieve a fd
  71.                            return a
  72.                        ) [0..]
  73.   where s = segSize fd
  74.  
  75. -- Factors smooth numbers over the factor base, with exponents mod 2
  76. smoothFactor :: [Integer] -> Integer -> [(Integer, Integer)]
  77. smoothFactor [] _ = []
  78. smoothFactor (p:ps) y = (p, e `mod` 2) : smoothFactor ps d
  79.   where (d,e) = powsN y p
  80.  
  81. -- Converts a smooth number to its exponent vector over the factor base
  82. toBitVector :: [Integer] -> Integer -> [Int]
  83. toBitVector ps = (map (fromIntegral . snd)) . (smoothFactor ps)
  84.  
  85. -- External module that has been thoroughly tested
  86. nullSpace2 :: [[Int]] -> [[Int]]
  87. nullSpace2 = allNullVectorsF2 . transpose
  88.  
  89. -- Finds all (a,b) such that a^2 = b^2 (mod n)
  90. findAB :: FactorData -> [(Integer, Integer)]
  91. findAB fd = map (\vect ->
  92.                   (squareRoot $ product $ zipWith (Prelude.^) smooth vect,
  93.                    product $ zipWith (Prelude.^) xs vect)) choices
  94.   where sieved  = take (1 + smoothNum fd) (doSieve fd)
  95.         fb      = factorBase fd
  96.         xs      = map fst sieved
  97.         smooth  = map snd sieved
  98.         vectors = map (toBitVector fb) smooth
  99.         choices = nullSpace2 vectors
  100.  
  101. -- Checks to see whether (a-b) or (a+b) share any factors with n
  102. checkAB :: Integer -> (Integer, Integer) -> Maybe Integer
  103. checkAB n (a,b) = if g1 == 1 || g1 == n then
  104.                     if g2 == 1 || g2 == n then Nothing
  105.                     else Just g2
  106.                   else Just g1
  107.   where
  108.     g1 = gcd (a-b) n
  109.     g2 = gcd (a+b) n
  110.  
  111. -- Merges two sorted lists of factors
  112. merge :: (Num a, Ord a, Num b) => [(a, b)] -> [(a, b)] -> [(a, b)]
  113. merge [] [] = []
  114. merge l1 [] = l1
  115. merge [] l2 = l2
  116. merge l1@((p1,e1):fs1) l2@((p2,e2):fs2)
  117.   | p1 == 1   = merge fs1 l2
  118.   | p2 == 1   = merge l1 fs2
  119.   | p1 == p2  = (p1, e1 + e2) : merge fs1 fs2
  120.   | p1 < p2   = (p1, e1) : merge fs1 l2
  121.   | otherwise = (p2, e2) : merge l1 fs2
  122.  
  123. unSquare :: Integer -> (Integer, Int)
  124. unSquare n
  125.   | isSquare n = fmap (+1) (unSquare (squareRoot n))
  126.   | otherwise  = (n, 0)
  127.  
  128. -- The normal quadratic sieve has a serious issue with squares
  129. qsieveSquare :: Integer -> [(Integer, Integer)]
  130. qsieveSquare n = let (q, s) = unSquare n in
  131.   map (fmap (* 2^s)) (qsieve q)
  132.  
  133. -- | Factors an integer using only the quadratic sieve. You are better off
  134. --   calling factor, which will try simpler methods before resorting to the
  135. --   quadratic sieve
  136. qsieve :: Integer -> [(Integer, Integer)]
  137. qsieve n
  138.   | n <= 1     = [(n,1)]
  139.   | isPrime n  = [(n,1)]
  140.   | isSquare n = qsieveSquare n
  141.   | otherwise  = case mapMaybe (checkAB n) aBs of
  142.     [] -> error "I seriously don't know what to do here"
  143.     (g:_) -> qsieve' g
  144.  where
  145.    aBs = findAB (mkFactorData n)
  146.    qsieve' g = let (q,s) = powsN n g in
  147.       merge (map (fmap (*s)) (qsieve g)) (qsieve q)
Advertisement
Add Comment
Please, Sign In to add comment