{-# OPTIONS_GHC -O2 -feager-blackholing #-}
{-# LANGUAGE Safe, BangPatterns, NoImplicitPrelude #-}
module Crypto.Fi ( FPrime
, eq
, add
, addr
, sub
, subr
, neg
, shift
, mul
, mulr
, redc
, square
, pow
, inv
, fromInteger
, toInteger
, condBit
)
where
import safe Prelude ((==),Integer,Int,Bool(),($),(+),(-),(*),(^),mod,otherwise,(<))
import safe qualified Prelude as P (fromInteger,toInteger)
import safe qualified Data.Bits as B (Bits(..),shift,(.&.))
import safe Crypto.Common (log2len)
type FPrime = Integer
eq :: FPrime -> FPrime -> Bool
eq !a !b = a == b
{-# INLINABLE eq #-}
add :: FPrime -> FPrime -> FPrime
add !a !b = a + b
{-# INLINABLE add #-}
addr :: FPrime -> FPrime -> FPrime -> FPrime
addr !p !a !b = redc p $ a + b
{-# INLINABLE addr #-}
sub :: FPrime -> FPrime -> FPrime
sub !a !b = a - b
{-# INLINABLE sub #-}
subr :: FPrime -> FPrime -> FPrime -> FPrime
subr !p !a !b = redc p (a - b)
{-# INLINABLE subr #-}
neg :: FPrime -> FPrime -> FPrime
neg !p !a = redc p (-a)
{-# INLINABLE neg #-}
shift :: FPrime -> Int -> FPrime
shift !a !b = B.shift a b
redc :: FPrime -> FPrime -> FPrime
redc !p !a = a `mod` p
{-# INLINABLE redc #-}
mul :: FPrime -> FPrime -> FPrime
mul !a !b = a * b
{-# INLINABLE mul #-}
mulr :: FPrime -> FPrime -> FPrime -> FPrime
mulr !p !a !b = redc p $ a * b
{-# INLINABLE mulr #-}
square :: FPrime -> FPrime -> FPrime
square !p !a = redc p (a ^ (2::Int))
{-# INLINABLE square #-}
pow :: FPrime -> FPrime -> Integer -> FPrime
pow !p !a' !k = let a = redc p a'
binlog = log2len a
alleeins = fromInteger binlog (2^binlog - 1)
eins = fromInteger binlog 1
ex erg i
| i < 0 = erg
| otherwise =
let s = condBit k i
pat = mul alleeins s
invpat = mul alleeins (sub eins s)
in redc p $ ex (mulr p (square p erg) (addr p (a B..&. pat) (eins B..&. invpat))) (i - 1)
in redc p $ ex 1 (log2len k - 1)
inv :: FPrime -> FPrime -> FPrime
inv !p !a = pow p a (toInteger p - 2)
fromInteger :: Int -> FPrime -> Integer
fromInteger !l !a = P.fromInteger (a `mod` (2^l))
{-# INLINABLE fromInteger #-}
toInteger :: FPrime -> Integer
toInteger !a = P.toInteger a
{-# INLINABLE toInteger #-}
condBit :: FPrime -> Int -> FPrime
condBit !a !i = shift (a B..&. fromInteger (i+1) ((2^(i+1)-1)::Integer)) (-i)
{-# INLINABLE condBit #-}