-- | Table of Conway polynomials -- -- The data is from -- -- The text file from the above link is converted to a C source file during the -- build process, and the resulting object file is then linked. -- This should be much faster (in compilation time) than encoding it as a Haskell -- data structure, because GHC does not like big constants. Also the in-memory representation -- can be controlled more precisely. -- {-# LANGUAGE ForeignFunctionInterface, BangPatterns, KindSignatures, GADTs #-} module Math.FiniteField.Conway.Internal where -------------------------------------------------------------------------------- import Data.Word import Data.Bits import GHC.TypeNats (Nat) import qualified Data.IntMap.Strict as IntMap import Data.IntMap.Strict (IntMap) import Foreign.C import Foreign.Ptr import Foreign.Storable import Foreign.Marshal import Foreign.Marshal.Array import qualified System.IO.Unsafe as Unsafe -------------------------------------------------------------------------------- -- * The witness (it's here so internal modules can acces the inside of it) newtype ConwayPoly (p :: Nat) (m :: Nat) where ConwayWitness :: Ptr Word32 -> ConwayPoly p m fromConwayPoly :: ConwayPoly p m -> Ptr Word32 fromConwayPoly (ConwayWitness ptr) = ptr -- | @(prime,exponent)@ conwayParams_ :: ConwayPoly p m -> (Word64,Int) conwayParams_ (ConwayWitness ptr) = Unsafe.unsafePerformIO $ do (p,m) <- getConwayEntryParams ptr return (fromIntegral p, fromIntegral m) conwayPrime_ :: ConwayPoly p m -> Word64 conwayPrime_ (ConwayWitness ptr) = Unsafe.unsafePerformIO $ do (p,_) <- getConwayEntryParams ptr return p -- | We have some Conway polynomials for @m=1@ too; the roots of -- these linear polynomials are primitive roots in @F_p@ lookupConwayPrimRoot_ :: Int -> Maybe Word64 lookupConwayPrimRoot_ !p = case IntMap.lookup (encodePrimeExpo p 1) (fromConwayTable theConwayTable) of Nothing -> Nothing Just ptr -> case (Unsafe.unsafePerformIO $ marshalConwayEntry ptr) of (_,_,[c,1]) -> Just (fromIntegral p - fromIntegral c) _ -> error "lookupConwayPrimRoot: fatal error (should not happen)" -------------------------------------------------------------------------------- -- * The C table foreign import ccall "get_conway_table_size" c_conway_table_size :: Word32 foreign import ccall "get_conway_table_ptr" c_conway_table_ptr :: Ptr Word32 getConwayEntryParams :: Ptr Word32 -> IO (Word64,Int) getConwayEntryParams !ptr = do p <- peek ptr :: IO Word32 m <- peek (plusPtr ptr 4) :: IO Word32 return (fromIntegral p, fromIntegral m) marshalConwayEntry :: Ptr Word32 -> IO (Word64,Int,[Word64]) marshalConwayEntry !ptr = do p <- peek ptr :: IO Word32 m <- peek (plusPtr ptr 4) :: IO Word32 coeffs <- peekArray (fromIntegral m + 1) (plusPtr ptr 8) :: IO [Word32] return (fromIntegral p , fromIntegral m , map fromIntegral coeffs) -------------------------------------------------------------------------------- -- * The global table newtype ConwayTable = ConwayTable { fromConwayTable :: IntMap (Ptr Word32) } encodePrimeExpo :: Int -> Int -> Int encodePrimeExpo !prime !expo = prime .|. (shiftL expo 20) decodePrimeExpo :: Int -> (Int,Int) decodePrimeExpo !code = (code .&. 0xfffff , shiftR code 20) {-# NOINLINE theConwayTable #-} theConwayTable :: ConwayTable theConwayTable = Unsafe.unsafePerformIO readConwayTableIO {-# NOINLINE lookupConwayEntry #-} lookupConwayEntry :: Int -> Int -> Maybe (Word64,Int,[Word64]) lookupConwayEntry p m = case IntMap.lookup (encodePrimeExpo p m) (fromConwayTable theConwayTable) of Nothing -> Nothing Just ptr -> Just (Unsafe.unsafePerformIO (marshalConwayEntry ptr)) -------------------------------------------------------------------------------- -- * Parse the C table into a lookup table readConwayTableIO :: IO ConwayTable readConwayTableIO = do list <- go c_conway_table_size c_conway_table_ptr let f (p,m,ptr) = (encodePrimeExpo (fromIntegral p) (fromIntegral m) , ptr) return $ ConwayTable $ IntMap.fromList (map f list) where go :: Word32 -> Ptr Word32 -> IO [(Word32,Word32,Ptr Word32)] go 0 _ = return [] go !k !ptr = do p <- peek ptr :: IO Word32 m <- peek (plusPtr ptr 4) :: IO Word32 let ptr' = plusPtr ptr (8 + 4*(fromIntegral m + 1)) let this = (p,m,ptr) rest <- go (k-1) ptr' return (this:rest) --------------------------------------------------------------------------------