module Bitcoin.Crypto.FiniteField.Naive.Fn where
import Prelude hiding ( sqrt )
import Data.Char
import Data.Bits
import Data.Word
import Data.Maybe
secp256k1_n :: Integer
secp256k1_n = 115792089237316195423570985008687907852837564279074904382605163141518161494337
newtype Fn = Fn Integer deriving (Eq,Show)
toFn :: Integer -> Fn
toFn x = Fn (modn x)
fromFn :: Fn -> Integer
fromFn (Fn x) = x
instance Num Fn where
Fn x + Fn y = Fn $ modn (x+y)
Fn x Fn y = Fn $ modn (xy)
Fn x * Fn y = Fn $ modn (x*y)
negate (Fn x) = Fn $ modn (secp256k1_n x)
fromInteger = Fn . modn
abs = error "Fn/abs"
signum = error "Fn/signum"
instance Fractional Fn where
Fn x / Fn y = Fn $ modn ( x * invFn y )
recip (Fn x) = Fn $ invFn x
fromRational = error "Fn/fromRational"
pow_n :: Fn -> Fn -> Fn
pow_n (Fn b) (Fn e) = Fn (powFn b e)
modn :: Integer -> Integer
modn !a = mod a secp256k1_n
invFn :: Integer -> Integer
invFn !a = powFn a (secp256k1_n 2)
powFn :: Integer -> Integer -> Integer
powFn !base !exp = go 1 base exp where
go !acc _ 0 = acc
go !acc !b !e = if (e .&. 1 > 0)
then go (modn (acc*b)) (modn (b*b)) (shiftR e 1)
else go acc (modn (b*b)) (shiftR e 1)