module Crypto.Number.F2m
( BinaryPolynomial
, addF2m
, mulF2m
, squareF2m
, modF2m
, invF2m
, divF2m
) where
import Data.Bits ((.&.),(.|.),xor,shift,testBit)
import Crypto.Number.Basic
import Crypto.Internal.Imports
type BinaryPolynomial = Integer
addF2m :: Integer -> Integer -> Integer
addF2m = xor
modF2m :: BinaryPolynomial
-> Integer -> Integer
modF2m fx = go
where
lfx = log2 fx
go n | s == 0 = n `xor` fx
| s < 0 = n
| otherwise = go $ n `xor` shift fx s
where
s = log2 n lfx
mulF2m :: BinaryPolynomial
-> Integer -> Integer -> Integer
mulF2m fx n1 n2 = modF2m fx
$ go (if n2 `mod` 2 == 1 then n1 else 0) (log2 n2)
where
go n s | s == 0 = n
| otherwise = if testBit n2 s
then go (n `xor` shift n1 s) (s 1)
else go n (s 1)
squareF2m :: BinaryPolynomial
-> Integer -> Integer
squareF2m fx = modF2m fx . square
square :: Integer -> Integer
square n1 = go n1 ln1
where
ln1 = log2 n1
go n s | s == 0 = n
| otherwise = go (x .|. y) (s 1)
where
x = shift (shift n (2 * (s ln1) 1)) (2 * (ln1 s) + 2)
y = n .&. (shift 1 (2 * (ln1 s) + 1) 1)
invF2m :: BinaryPolynomial
-> Integer -> Maybe Integer
invF2m _ 0 = Nothing
invF2m fx n
| n >= fx = Nothing
| otherwise = go n fx 1 0
where
go u v g1 g2
| u == 1 = Just $ modF2m fx g1
| j < 0 = go u (v `xor` shift u (j)) g1 (g2 `xor` shift g1 (j))
| otherwise = go (u `xor` shift v j) v (g1 `xor` shift g2 j) g2
where
j = log2 u log2 v
divF2m :: BinaryPolynomial
-> Integer
-> Integer
-> Maybe Integer
divF2m fx n1 n2 = mulF2m fx n1 <$> invF2m fx n2