-- | The finite field Fn of n elements, where n is the order of the elliptic curve secp256k1 (which happens to be a prime). -- -- Naive implementation. -- {-# LANGUAGE BangPatterns #-} 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 -------------------------------------------------------------------------------- -- * for the signatures, we also need mod n arithmetic, not only mod p... -- | The prime field Fn (n seems to be a prime, after all) 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 (x-y) 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) -------------------------------------------------------------------------------- -- | helper function: Modulo n modn :: Integer -> Integer modn !a = mod a secp256k1_n -- | Multiplicative inverse in Fp invFn :: Integer -> Integer invFn !a = powFn a (secp256k1_n - 2) -- | (Fast) exponentiation in Fn 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) --------------------------------------------------------------------------------