pairing-0.1.0: src/Pairing/Point.hs
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}
--
-- | Affine point arithmetic defining the group operation on an
-- elliptic curve E(F), for some field F. In our case the field F is
-- given as some type t with Num and Fractional instances.
module Pairing.Point (
Point(..),
gDouble,
gAdd,
gNeg,
gMul,
) where
import Protolude
import Pairing.Fq (Fq)
import Pairing.Fq2 (Fq2)
-- | Points on a curve over a field @a@ represented as either affine
-- coordinates or as a point at infinity.
data Point a
= Point a a -- ^ Affine point
| Infinity -- ^ Point at 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 #-}
-- | Point addition, provides a group structure on an elliptic curve
-- with the point at infinity as its unit.
gAdd
:: (Fractional t, Eq t)
=> Point t
-> Point t
-> Point t
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' = l^2 - x1 - x2
y' = -l * x' + l * x1 - y1
-- | Point doubling
gDouble :: (Fractional t, Eq t) => Point t -> Point t
gDouble Infinity = Infinity
gDouble (Point _ 0) = Infinity
gDouble (Point x y) = Point x' y'
where
l = 3*x^2 / (2*y)
x' = l^2 - 2*x
y' = -l * x' + l * x - y
-- | Negation (flipping the y component)
gNeg
:: (Fractional t, Eq t)
=> Point t
-> Point t
gNeg Infinity = Infinity
gNeg (Point x y) = Point x (-y)
-- | Multiplication by a scalar
gMul
:: (Eq t, Integral a, Fractional t)
=> Point t
-> a
-> Point t
gMul _ 0 = Infinity
gMul pt 1 = pt
gMul pt n
| n < 0 = panic "gMul: negative scalar not supported"
| even n = gMul (gDouble pt) (n `div` 2)
| otherwise = gAdd (gMul (gDouble pt) (n `div` 2)) pt