module Pairing.Point
( Point(..)
, gDouble
, gAdd
, gNeg
, gMul
) where
import Protolude
import GaloisField (GaloisField(..))
import Pairing.Fq (Fq, Fq2)
data Point a
= Point a a
| Infinity
deriving (Eq, Ord, Show, Functor, Generic, NFData)
{-# SPECIALISE gDouble :: Point Fq -> Point Fq #-}
{-# SPECIALISE gDouble :: Point Fq2 -> Point Fq2 #-}
{-# SPECIALISE gAdd :: Point Fq -> Point Fq -> Point Fq #-}
{-# SPECIALISE gAdd :: Point Fq2 -> Point Fq2 -> Point Fq2 #-}
{-# SPECIALISE gNeg :: Point Fq -> Point Fq #-}
{-# SPECIALISE gNeg :: Point Fq2 -> Point Fq2 #-}
{-# SPECIALISE gMul :: Point Fq -> Integer -> Point Fq #-}
{-# SPECIALISE gMul :: Point Fq2 -> Integer -> Point Fq2 #-}
gAdd :: GaloisField k => Point k -> Point k -> Point k
gAdd Infinity a = a
gAdd a Infinity = a
gAdd (Point x1 y1) (Point x2 y2)
| x2 == x1 && y2 == y1 = gDouble (Point x1 y1)
| x2 == x1 = Infinity
| otherwise = Point x' y'
where
l = (y2 - y1) / (x2 - x1)
x' = pow l 2 - x1 - x2
y' = -l * x' + l * x1 - y1
gDouble :: GaloisField k => Point k -> Point k
gDouble Infinity = Infinity
gDouble (Point _ 0) = Infinity
gDouble (Point x y) = Point x' y'
where
l = 3 * pow x 2 / (2 * y)
x' = pow l 2 - 2 * x
y' = -l * x' + l * x - y
gNeg :: GaloisField k => Point k -> Point k
gNeg Infinity = Infinity
gNeg (Point x y) = Point x (-y)
gMul :: (Integral a, GaloisField k) => Point k -> a -> Point k
gMul _ 0 = Infinity
gMul pt 1 = pt
gMul pt n
| n < 0 = panic "gMul: negative scalar not supported"
| even n = gMul (gDouble pt) (div n 2)
| otherwise = gAdd (gMul (gDouble pt) (div n 2)) pt