{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Bulletproofs.Fq where
import Protolude
import Crypto.Random (MonadRandom)
import Crypto.Number.Generate (generateMax)
import Bulletproofs.Curve
newtype Fq = Fq Integer
deriving (Show, Eq, Bits, Ord)
instance Num Fq where
(+) = fqAdd
(*) = fqMul
abs = panic "There is no absolute value in a finite field"
signum = panic "This function doesn't make sense in a finite field"
negate = fqNeg
fromInteger = new
instance Fractional Fq where
(/) = fqDiv
fromRational (a :% b) = Fq a / Fq b
new :: Integer -> Fq
new a = Fq (a `mod` q)
{-# INLINE norm #-}
norm :: Fq -> Fq
norm (Fq a) = Fq (a `mod` q)
{-# INLINE fqAdd #-}
fqAdd :: Fq -> Fq -> Fq
fqAdd (Fq a) (Fq b) = norm (Fq (a+b))
{-# INLINE fqMul #-}
fqMul :: Fq -> Fq -> Fq
fqMul (Fq a) (Fq b) = norm (Fq (a*b))
{-# INLINE fqNeg #-}
fqNeg :: Fq -> Fq
fqNeg (Fq a) = Fq ((-a) `mod` q)
{-# INLINE fqDiv #-}
fqDiv :: Fq -> Fq -> Fq
fqDiv a b = fqMul a (inv b)
{-# INLINE fqInv #-}
fqInv :: Fq -> Fq
fqInv x = 1 / x
{-# INLINE fqZero #-}
fqZero :: Fq
fqZero = Fq 0
{-# INLINE fqOne #-}
fqOne :: Fq
fqOne = Fq 1
fqSquare :: Fq -> Fq
fqSquare x = fqMul x x
fqCube :: Fq -> Fq
fqCube x = fqMul x (fqMul x x)
inv :: Fq -> Fq
inv (Fq a) = Fq $ euclidean a q `mod` q
asInteger :: Fq -> Integer
asInteger (Fq n) = n
euclidean :: (Integral a) => a -> a -> a
euclidean a b = fst (inv' a b)
{-# INLINEABLE inv' #-}
{-# SPECIALISE inv' :: Integer -> Integer -> (Integer, Integer) #-}
inv' :: (Integral a) => a -> a -> (a, a)
inv' a b =
case b of
1 -> (0, 1)
_ -> let (e, f) = inv' b d
in (f, e - c*f)
where c = a `div` b
d = a `mod` b
random :: MonadRandom m => Integer -> m Fq
random n = Fq <$> generateMax (2^n)
fqAddV :: [Fq] -> [Fq] -> [Fq]
fqAddV = zipWith (+)
fqSubV :: [Fq] -> [Fq] -> [Fq]
fqSubV = zipWith (-)
fqMulV :: [Fq] -> [Fq] -> [Fq]
fqMulV = zipWith (*)