/ tests / Semantics.hs
Semantics.hs
  1  
  2  {-# LANGUAGE BlockArguments #-}
  3  module Semantics where
  4  
  5  --------------------------------------------------------------------------------
  6  
  7  import Prelude hiding (div)
  8  import Control.Monad
  9  import System.Random
 10  
 11  --------------------------------------------------------------------------------
 12  
 13  type F    = Int
 14  type FExt = (F,F)
 15  
 16  fieldPrime :: Int
 17  fieldPrime = 2^8 - 2^4 + 1
 18  
 19  modp :: Int -> F
 20  modp x = mod x fieldPrime
 21  
 22  --------------------------------------------------------------------------------
 23  
 24  neg :: F -> F
 25  neg 0 = 0
 26  neg x = fieldPrime - x
 27  
 28  add :: F -> F -> F
 29  add x y = modp (x + y)
 30  
 31  sub :: F -> F -> F
 32  sub x y = modp (x - y)
 33  
 34  mul :: F -> F -> F
 35  mul x y = modp (x * y)
 36  
 37  sqr :: F -> F 
 38  sqr x = mul x x
 39  
 40  mul3 :: F -> F -> F -> F
 41  mul3 x y z = mul (mul x y) z
 42  
 43  pow :: F -> Int -> F
 44  pow x0 expo
 45    | expo < 0  = error "pow: negative exponent"
 46    | expo == 0 = 1
 47    | otherwise = go 1 x0 expo
 48    where
 49      go acc s 0 = acc
 50      go acc s e = case divMod e 2 of
 51        (e', 0) -> go      acc    (sqr s) e'
 52        (e' ,1) -> go (mul acc s) (sqr s) e'
 53  
 54  inv :: F -> F
 55  inv x = pow x (fieldPrime - 2)      
 56  
 57  div :: F -> F -> F
 58  div x y = mul x (inv y)
 59  
 60  --------------------------------------------------------------------------------
 61  
 62  negExt :: FExt -> FExt
 63  negExt (r,i) = (neg r, neg i)
 64  
 65  addExt :: FExt -> FExt -> FExt
 66  addExt (r1,i1) (r2,i2) = (add r1 r2, add i1 i2)
 67  
 68  subExt :: FExt -> FExt -> FExt
 69  subExt (r1,i1) (r2,i2) = (sub r1 r2, sub i1 i2)
 70  
 71  mulExt :: FExt -> FExt -> FExt
 72  mulExt (r1,i1) (r2,i2) = (r3,i3) where
 73    r3 = (mul r1 r2) `add` (mul3 7 i1 i2) 
 74    i3 = (mul r1 i2) `add` (mul i1 r2)
 75  
 76  sqrExt :: FExt -> FExt 
 77  sqrExt x = mulExt x x
 78  
 79  powExt :: FExt -> Int -> FExt
 80  powExt x0 expo
 81    | expo < 0  = error "pow: negative exponent"
 82    | expo == 0 = (1,0)
 83    | otherwise = go (1,0) x0 expo
 84    where
 85      go acc s 0 = acc
 86      go acc s e = case divMod e 2 of
 87        (e', 0) -> go         acc    (sqrExt s) e'
 88        (e' ,1) -> go (mulExt acc s) (sqrExt s) e'
 89  
 90  invExt :: FExt -> FExt
 91  invExt (r,i) = (r `mul` z , neg i `mul` z) where 
 92    denom = (sqr r) `sub` (mul3 7 i i)
 93    z = inv denom
 94  
 95  divExt :: FExt -> FExt -> FExt
 96  divExt x y = mulExt x (invExt y)
 97  
 98  --------------------------------------------------------------------------------
 99  -- some quick & dirty testing
100  
101  data Prop a 
102    = Prop1 String (a -> Bool)
103    | Prop2 String (a -> a -> Bool)
104    | Prop3 String (a -> a -> a -> Bool)
105  
106  propName :: Prop a -> String
107  propName prop = case prop of
108    Prop1 name _ -> name
109    Prop2 name _ -> name
110    Prop3 name _ -> name
111  
112  some_properties :: [Prop F]
113  some_properties = 
114    [ Prop2 "add-sub" \x y   -> add (sub x y) y == x 
115    , Prop2 "add-neg" \x y   -> sub x y == add x (neg y)
116    , Prop1 "inv-mul" \x     -> x == 0 || inv x `mul` x == 1
117    , Prop1 "inv-pow" \x     -> inv x == pow x (fieldPrime - 2)
118    , Prop2 "mul-div" \x y   -> y == 0 || mul (div x y) y == x 
119    , Prop3 "mul-add" \x y z -> mul (add x y) z == mul x z `add` mul y z 
120    , Prop1 "mul-pow" \x     -> mul (mul x x) x == pow x 3
121    ]
122  
123  some_ext_properties :: [Prop FExt]
124  some_ext_properties = 
125    [ Prop2 "add-sub" \x y   -> addExt (subExt x y) y == x 
126    , Prop2 "add-neg" \x y   -> subExt x y == addExt x (negExt y)
127    , Prop1 "inv-mul" \x     -> x == (0,0) || invExt x `mulExt` x == (1,0)
128    , Prop1 "inv-pow" \x     -> invExt x == powExt x (fieldPrime^2 - 2)
129    , Prop2 "mul-div" \x y   -> y == (0,0) || mulExt (divExt x y) y == x 
130    , Prop3 "mul-add" \x y z -> mulExt (addExt x y) z == mulExt x z `addExt` mulExt y z 
131    , Prop1 "mul-pow" \x     -> mulExt (mulExt x x) x == powExt x 3
132    ]
133  
134  --------------------------------------------------------------------------------
135  
136  runTests :: IO ()
137  runTests = do
138    let n = 1000
139    runTestsBase n
140    runTestsExt  n
141  
142  runTestsBase :: Int -> IO ()
143  runTestsBase n = do
144    putStrLn $ "\nbase field properties"
145    forM_ some_properties $ \prop -> do
146      oks <- replicateM n (runPropF prop) 
147      let good = length (filter id oks)
148      let bad  = if good < n then " - FAILED!" else " - OK."
149      putStrLn $ "  - " ++ propName prop ++ ": " ++ show good ++ " / " ++ show n ++ " passed. " ++ bad 
150  
151  runTestsExt :: Int -> IO ()
152  runTestsExt n = do
153    putStrLn $ "\nextension field properties"
154    forM_ some_ext_properties $ \prop -> do
155      oks <- replicateM n (runPropFExt prop) 
156      let good = length (filter id oks)
157      let bad  = if good < n then " - FAILED!" else " - OK."
158      putStrLn $ "  - " ++ propName prop ++ ": " ++ show good ++ " / " ++ show n ++ " passed. " ++ bad
159  
160  ----------------------------------------
161  
162  rndF :: IO F
163  rndF = randomRIO (0,fieldPrime-1)
164  
165  rndFExt :: IO FExt
166  rndFExt = (,) <$> rndF <*> rndF
167  
168  runPropF :: Prop F -> IO Bool
169  runPropF prop = case prop of
170    Prop1 _ f1 -> f1 <$> rndF
171    Prop2 _ f2 -> f2 <$> rndF <*> rndF
172    Prop3 _ f3 -> f3 <$> rndF <*> rndF <*> rndF
173  
174  runPropFExt :: Prop FExt -> IO Bool
175  runPropFExt prop = case prop of
176    Prop1 _ f1 -> f1 <$> rndFExt
177    Prop2 _ f2 -> f2 <$> rndFExt <*> rndFExt
178    Prop3 _ f3 -> f3 <$> rndFExt <*> rndFExt <*> rndFExt
179  
180  --------------------------------------------------------------------------------