{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Spake2.Groups.Ed25519
( Ed25519(..)
, l
, generator
) where
import Protolude hiding (group)
import Crypto.Error (CryptoFailable(..), CryptoError(..))
import Crypto.Number.Generate (generateMax)
import Crypto.Number.ModArithmetic (expSafe, inverseCoprimes)
import Crypto.Number.Serialize (i2osp, os2ip)
import Data.ByteArray (ByteArray, ByteArrayAccess)
import qualified Data.ByteArray as ByteArray
import qualified Data.List as List
import Crypto.Spake2.Group (AbelianGroup(..), Group(..), KeyPair(..), scalarSizeBytes)
import Crypto.Spake2.Util (bytesToNumber, expandArbitraryElementSeed)
data Ed25519 = Ed25519 deriving (Ed25519 -> Ed25519 -> Bool
(Ed25519 -> Ed25519 -> Bool)
-> (Ed25519 -> Ed25519 -> Bool) -> Eq Ed25519
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Ed25519 -> Ed25519 -> Bool
$c/= :: Ed25519 -> Ed25519 -> Bool
== :: Ed25519 -> Ed25519 -> Bool
$c== :: Ed25519 -> Ed25519 -> Bool
Eq, Int -> Ed25519 -> ShowS
[Ed25519] -> ShowS
Ed25519 -> String
(Int -> Ed25519 -> ShowS)
-> (Ed25519 -> String) -> ([Ed25519] -> ShowS) -> Show Ed25519
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Ed25519] -> ShowS
$cshowList :: [Ed25519] -> ShowS
show :: Ed25519 -> String
$cshow :: Ed25519 -> String
showsPrec :: Int -> Ed25519 -> ShowS
$cshowsPrec :: Int -> Ed25519 -> ShowS
Show)
instance Group Ed25519 where
type Element Ed25519 = ExtendedPoint 'Member
elementAdd :: Ed25519 -> Element Ed25519 -> Element Ed25519 -> Element Ed25519
elementAdd _ x :: Element Ed25519
x y :: Element Ed25519
y = ExtendedPoint 'Member
-> ExtendedPoint 'Member -> ExtendedPoint 'Member
forall (a :: GroupMembership).
ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
addExtendedPoints Element Ed25519
ExtendedPoint 'Member
x Element Ed25519
ExtendedPoint 'Member
y
elementNegate :: Ed25519 -> Element Ed25519 -> Element Ed25519
elementNegate _ x :: Element Ed25519
x = ExtendedPoint 'Member -> ExtendedPoint 'Member
forall (preserving :: GroupMembership).
ExtendedPoint preserving -> ExtendedPoint preserving
negateExtendedPoint Element Ed25519
ExtendedPoint 'Member
x
groupIdentity :: Ed25519 -> Element Ed25519
groupIdentity _ = HasCallStack => ExtendedPoint 'Unknown -> ExtendedPoint 'Member
ExtendedPoint 'Unknown -> ExtendedPoint 'Member
assertInGroup ExtendedPoint 'Unknown
forall (a :: GroupMembership). ExtendedPoint a
extendedZero
encodeElement :: Ed25519 -> Element Ed25519 -> bytes
encodeElement _ x :: Element Ed25519
x = AffinePoint -> bytes
forall bytes.
(ByteArray bytes, ByteArrayAccess bytes) =>
AffinePoint -> bytes
encodeAffinePoint (ExtendedPoint 'Member -> AffinePoint
forall (a :: GroupMembership). ExtendedPoint a -> AffinePoint
extendedToAffine' Element Ed25519
ExtendedPoint 'Member
x)
decodeElement :: Ed25519 -> bytes -> CryptoFailable (Element Ed25519)
decodeElement _ bytes :: bytes
bytes = Either Error (ExtendedPoint 'Member)
-> CryptoFailable (Element Ed25519)
forall a. Either Error a -> CryptoFailable a
toCryptoFailable (Either Error (ExtendedPoint 'Member)
-> CryptoFailable (Element Ed25519))
-> Either Error (ExtendedPoint 'Member)
-> CryptoFailable (Element Ed25519)
forall a b. (a -> b) -> a -> b
$ do
ExtendedPoint 'Unknown
extended <- AffinePoint -> ExtendedPoint 'Unknown
affineToExtended (AffinePoint -> ExtendedPoint 'Unknown)
-> Either Error AffinePoint
-> Either Error (ExtendedPoint 'Unknown)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> bytes -> Either Error AffinePoint
forall bytes.
(ByteArray bytes, ByteArrayAccess bytes) =>
bytes -> Either Error AffinePoint
decodeAffinePoint bytes
bytes
ExtendedPoint 'Unknown -> Either Error (ExtendedPoint 'Member)
ensureInGroup ExtendedPoint 'Unknown
extended
elementSizeBits :: Ed25519 -> Int
elementSizeBits _ = 255
arbitraryElement :: Ed25519 -> bytes -> Element Ed25519
arbitraryElement group :: Ed25519
group bytes :: bytes
bytes =
let seed :: ByteString
seed = bytes -> Int -> ByteString
forall ikm out.
(ByteArrayAccess ikm, ByteArray out) =>
ikm -> Int -> out
expandArbitraryElementSeed bytes
bytes (Ed25519 -> Int
forall group. AbelianGroup group => group -> Int
scalarSizeBytes Ed25519
group Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 16) :: ByteString
y :: Integer
y = ByteString -> Integer
forall bytes. ByteArrayAccess bytes => bytes -> Integer
bytesToNumber ByteString
seed Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
in
[ExtendedPoint 'Member] -> ExtendedPoint 'Member
forall a. [a] -> a
List.head [ ExtendedPoint 'Member
element | Right element :: ExtendedPoint 'Member
element <- (Integer -> Either Error (ExtendedPoint 'Member))
-> [Integer] -> [Either Error (ExtendedPoint 'Member)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map Integer -> Either Error (Element Ed25519)
Integer -> Either Error (ExtendedPoint 'Member)
makeGroupMember [Integer
y..] ]
instance AbelianGroup Ed25519 where
type Scalar Ed25519 = Integer
scalarMultiply :: Ed25519 -> Scalar Ed25519 -> Element Ed25519 -> Element Ed25519
scalarMultiply _ n :: Scalar Ed25519
n x :: Element Ed25519
x = Integer -> ExtendedPoint 'Member -> ExtendedPoint 'Member
forall (a :: GroupMembership).
Integer -> ExtendedPoint a -> ExtendedPoint a
safeScalarMultiply Integer
Scalar Ed25519
n Element Ed25519
ExtendedPoint 'Member
x
integerToScalar :: Ed25519 -> Integer -> Scalar Ed25519
integerToScalar _ x :: Integer
x = Integer
Scalar Ed25519
x
scalarToInteger :: Ed25519 -> Scalar Ed25519 -> Integer
scalarToInteger _ x :: Scalar Ed25519
x = Integer
Scalar Ed25519
x
scalarSizeBits :: Ed25519 -> Int
scalarSizeBits _ = 255
generateElement :: Ed25519 -> randomly (KeyPair Ed25519)
generateElement group :: Ed25519
group = do
Integer
scalar <- Integer -> randomly Integer
forall (m :: * -> *). MonadRandom m => Integer -> m Integer
generateMax Integer
l
let element :: Element Ed25519
element = Ed25519 -> Scalar Ed25519 -> Element Ed25519 -> Element Ed25519
forall group.
AbelianGroup group =>
group -> Scalar group -> Element group -> Element group
scalarMultiply Ed25519
group Integer
Scalar Ed25519
scalar Element Ed25519
generator
KeyPair Ed25519 -> randomly (KeyPair Ed25519)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Element Ed25519 -> Scalar Ed25519 -> KeyPair Ed25519
forall group. Element group -> Scalar group -> KeyPair group
KeyPair Element Ed25519
element Integer
Scalar Ed25519
scalar)
data Error
= NotOnCurve Integer Integer
| NotInGroup (ExtendedPoint 'Unknown)
| LowOrderPoint (ExtendedPoint 'Unknown)
deriving (Error -> Error -> Bool
(Error -> Error -> Bool) -> (Error -> Error -> Bool) -> Eq Error
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Error -> Error -> Bool
$c/= :: Error -> Error -> Bool
== :: Error -> Error -> Bool
$c== :: Error -> Error -> Bool
Eq, Int -> Error -> ShowS
[Error] -> ShowS
Error -> String
(Int -> Error -> ShowS)
-> (Error -> String) -> ([Error] -> ShowS) -> Show Error
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Error] -> ShowS
$cshowList :: [Error] -> ShowS
show :: Error -> String
$cshow :: Error -> String
showsPrec :: Int -> Error -> ShowS
$cshowsPrec :: Int -> Error -> ShowS
Show)
toCryptoFailable :: Either Error a -> CryptoFailable a
toCryptoFailable :: Either Error a -> CryptoFailable a
toCryptoFailable (Right r :: a
r) = a -> CryptoFailable a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
r
toCryptoFailable (Left _) = CryptoError -> CryptoFailable a
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_PointCoordinatesInvalid
ensureInGroup :: ExtendedPoint 'Unknown -> Either Error (ExtendedPoint 'Member)
ensureInGroup :: ExtendedPoint 'Unknown -> Either Error (ExtendedPoint 'Member)
ensureInGroup element :: ExtendedPoint 'Unknown
element@ExtendedPoint{Integer
$sel:x:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
x :: Integer
x, Integer
$sel:y:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
y :: Integer
y, Integer
$sel:z:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
z :: Integer
z, Integer
$sel:t:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
t :: Integer
t} =
if ExtendedPoint 'Unknown -> Bool
forall (irrelevant :: GroupMembership).
ExtendedPoint irrelevant -> Bool
isExtendedZero (Integer -> ExtendedPoint 'Unknown -> ExtendedPoint 'Unknown
forall (a :: GroupMembership).
Integer -> ExtendedPoint a -> ExtendedPoint a
safeScalarMultiply Integer
l ExtendedPoint 'Unknown
element)
then ExtendedPoint 'Member -> Either Error (ExtendedPoint 'Member)
forall (f :: * -> *) a. Applicative f => a -> f a
pure $WExtendedPoint :: forall (groupMembership :: GroupMembership).
Integer
-> Integer -> Integer -> Integer -> ExtendedPoint groupMembership
ExtendedPoint { $sel:x:ExtendedPoint :: Integer
x = Integer
x, $sel:y:ExtendedPoint :: Integer
y = Integer
y, $sel:z:ExtendedPoint :: Integer
z = Integer
z, $sel:t:ExtendedPoint :: Integer
t = Integer
t}
else Error -> Either Error (ExtendedPoint 'Member)
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (Error -> Either Error (ExtendedPoint 'Member))
-> Error -> Either Error (ExtendedPoint 'Member)
forall a b. (a -> b) -> a -> b
$ ExtendedPoint 'Unknown -> Error
NotInGroup ExtendedPoint 'Unknown
element
assertInGroup :: HasCallStack => ExtendedPoint 'Unknown -> ExtendedPoint 'Member
assertInGroup :: ExtendedPoint 'Unknown -> ExtendedPoint 'Member
assertInGroup element :: ExtendedPoint 'Unknown
element =
case ExtendedPoint 'Unknown -> Either Error (ExtendedPoint 'Member)
ensureInGroup ExtendedPoint 'Unknown
element of
Left err :: Error
err -> Text -> ExtendedPoint 'Member
forall a. HasCallStack => Text -> a
panic (Text -> ExtendedPoint 'Member) -> Text -> ExtendedPoint 'Member
forall a b. (a -> b) -> a -> b
$ "Element not in group (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Error -> Text
forall a b. (Show a, ConvertText String b) => a -> b
show Error
err Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "): " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ExtendedPoint 'Unknown -> Text
forall a b. (Show a, ConvertText String b) => a -> b
show ExtendedPoint 'Unknown
element
Right x :: ExtendedPoint 'Member
x -> ExtendedPoint 'Member
x
q :: Integer
q :: Integer
q = 2 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ 255 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- 19
l :: Integer
l :: Integer
l = 2 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ 252 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ 27742317777372353535851937790883648493
dConst :: Integer
dConst :: Integer
dConst = (-121665 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer
inv 121666) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
i :: Integer
i :: Integer
i = Integer -> Integer -> Integer -> Integer
expSafe 2 ((Integer
qInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-1) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` 4) Integer
q
generator :: Element Ed25519
generator :: Element Ed25519
generator = HasCallStack => ExtendedPoint 'Unknown -> ExtendedPoint 'Member
ExtendedPoint 'Unknown -> Element Ed25519
assertInGroup (ExtendedPoint 'Unknown -> Element Ed25519)
-> ExtendedPoint 'Unknown -> Element Ed25519
forall a b. (a -> b) -> a -> b
$ AffinePoint -> ExtendedPoint 'Unknown
affineToExtended AffinePoint
b
where
b :: AffinePoint
b = case Integer -> Integer -> Either Error AffinePoint
makeAffinePoint (Integer
x Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q) (Integer
y Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q) of
Left err :: Error
err -> Text -> AffinePoint
forall a. HasCallStack => Text -> a
panic (Text -> AffinePoint) -> Text -> AffinePoint
forall a b. (a -> b) -> a -> b
$ "Generator is not affine point: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Error -> Text
forall a b. (Show a, ConvertText String b) => a -> b
show Error
err
Right r :: AffinePoint
r -> AffinePoint
r
x :: Integer
x = Integer -> Integer
xRecover Integer
y
y :: Integer
y = 4 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer
inv 5
inv :: Integer -> Integer
inv :: Integer -> Integer
inv x :: Integer
x = Integer -> Integer -> Integer
inverseCoprimes Integer
x Integer
q
xRecover :: Integer -> Integer
xRecover :: Integer -> Integer
xRecover y :: Integer
y =
let x'' :: Integer
x'' = (Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- 1) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer
inv(Integer
dConst Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ 1)
x' :: Integer
x' = Integer -> Integer -> Integer -> Integer
expSafe Integer
x'' ((Integer
q Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ 3) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` 8) Integer
q
x :: Integer
x = if (Integer
x' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
x' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
x'') Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= 0
then (Integer
x' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
i) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
else Integer
x'
in
if Integer -> Bool
forall a. Integral a => a -> Bool
even Integer
x then Integer
x else Integer
q Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
x
data GroupMembership = Unknown | Member
data ExtendedPoint (groupMembership :: GroupMembership)
= ExtendedPoint
{ ExtendedPoint groupMembership -> Integer
x :: !Integer
, ExtendedPoint groupMembership -> Integer
y :: !Integer
, ExtendedPoint groupMembership -> Integer
z :: !Integer
, ExtendedPoint groupMembership -> Integer
t :: !Integer
} deriving (Int -> ExtendedPoint groupMembership -> ShowS
[ExtendedPoint groupMembership] -> ShowS
ExtendedPoint groupMembership -> String
(Int -> ExtendedPoint groupMembership -> ShowS)
-> (ExtendedPoint groupMembership -> String)
-> ([ExtendedPoint groupMembership] -> ShowS)
-> Show (ExtendedPoint groupMembership)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (groupMembership :: GroupMembership).
Int -> ExtendedPoint groupMembership -> ShowS
forall (groupMembership :: GroupMembership).
[ExtendedPoint groupMembership] -> ShowS
forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> String
showList :: [ExtendedPoint groupMembership] -> ShowS
$cshowList :: forall (groupMembership :: GroupMembership).
[ExtendedPoint groupMembership] -> ShowS
show :: ExtendedPoint groupMembership -> String
$cshow :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> String
showsPrec :: Int -> ExtendedPoint groupMembership -> ShowS
$cshowsPrec :: forall (groupMembership :: GroupMembership).
Int -> ExtendedPoint groupMembership -> ShowS
Show)
instance Eq (ExtendedPoint a) where
point1 :: ExtendedPoint a
point1 == :: ExtendedPoint a -> ExtendedPoint a -> Bool
== point2 :: ExtendedPoint a
point2 = ExtendedPoint a -> AffinePoint
forall (a :: GroupMembership). ExtendedPoint a -> AffinePoint
extendedToAffine' ExtendedPoint a
point1 AffinePoint -> AffinePoint -> Bool
forall a. Eq a => a -> a -> Bool
== ExtendedPoint a -> AffinePoint
forall (a :: GroupMembership). ExtendedPoint a -> AffinePoint
extendedToAffine' ExtendedPoint a
point2
extendedZero :: ExtendedPoint a
extendedZero :: ExtendedPoint a
extendedZero = $WExtendedPoint :: forall (groupMembership :: GroupMembership).
Integer
-> Integer -> Integer -> Integer -> ExtendedPoint groupMembership
ExtendedPoint {$sel:x:ExtendedPoint :: Integer
x = 0, $sel:y:ExtendedPoint :: Integer
y = 1, $sel:z:ExtendedPoint :: Integer
z = 1, $sel:t:ExtendedPoint :: Integer
t = 0}
isExtendedZero :: ExtendedPoint irrelevant -> Bool
isExtendedZero :: ExtendedPoint irrelevant -> Bool
isExtendedZero ExtendedPoint{Integer
x :: Integer
$sel:x:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
x, Integer
y :: Integer
$sel:y:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
y, Integer
z :: Integer
$sel:z:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
z} = Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 0 Bool -> Bool -> Bool
&& Integer
y' Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
z' Bool -> Bool -> Bool
&& Integer
y' Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= 0
where
y' :: Integer
y' = Integer
y Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
z' :: Integer
z' = Integer
z Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
addExtendedPoints :: ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
addExtendedPoints :: ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
addExtendedPoints ExtendedPoint{$sel:x:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
x = Integer
x1, $sel:y:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
y = Integer
y1, $sel:z:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
z = Integer
z1, $sel:t:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
t = Integer
t1} ExtendedPoint{$sel:x:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
x = Integer
x2, $sel:y:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
y = Integer
y2, $sel:z:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
z = Integer
z2, $sel:t:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
t = Integer
t2} =
$WExtendedPoint :: forall (groupMembership :: GroupMembership).
Integer
-> Integer -> Integer -> Integer -> ExtendedPoint groupMembership
ExtendedPoint{$sel:x:ExtendedPoint :: Integer
x = Integer
x3, $sel:y:ExtendedPoint :: Integer
y = Integer
y3, $sel:z:ExtendedPoint :: Integer
z = Integer
z3, $sel:t:ExtendedPoint :: Integer
t = Integer
t3}
where
x3 :: Integer
x3 = (Integer
e Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
f) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
y3 :: Integer
y3 = (Integer
g Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
h) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
z3 :: Integer
z3 = (Integer
f Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
g) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
t3 :: Integer
t3 = (Integer
e Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
h) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
e :: Integer
e = (Integer
b Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
a) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
f :: Integer
f = (Integer
d' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
c) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
g :: Integer
g = (Integer
d' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
c) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
h :: Integer
h = (Integer
b Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
a) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
a :: Integer
a = ((Integer
y1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
x1) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* (Integer
y2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
x2)) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
b :: Integer
b = ((Integer
y1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
x1) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* (Integer
y2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
x2)) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
c :: Integer
c = (Integer
t1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* (2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
dConst) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
t2) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
d' :: Integer
d' = (Integer
z1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* 2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
z2) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
doubleExtendedPoint :: ExtendedPoint preserving -> ExtendedPoint preserving
doubleExtendedPoint :: ExtendedPoint preserving -> ExtendedPoint preserving
doubleExtendedPoint ExtendedPoint{$sel:x:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
x = Integer
x1, $sel:y:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
y = Integer
y1, $sel:z:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
z = Integer
z1} =
$WExtendedPoint :: forall (groupMembership :: GroupMembership).
Integer
-> Integer -> Integer -> Integer -> ExtendedPoint groupMembership
ExtendedPoint{$sel:x:ExtendedPoint :: Integer
x= Integer
x3, $sel:y:ExtendedPoint :: Integer
y = Integer
y3, $sel:z:ExtendedPoint :: Integer
z = Integer
z3, $sel:t:ExtendedPoint :: Integer
t = Integer
t3}
where
x3 :: Integer
x3 = (Integer
e Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
f) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
y3 :: Integer
y3 = (Integer
g Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
h) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
z3 :: Integer
z3 = (Integer
f Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
g) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
t3 :: Integer
t3 = (Integer
e Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
h) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
e :: Integer
e = (Integer
j Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
j Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
a Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
b) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
f :: Integer
f = (Integer
g Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
c) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
g :: Integer
g = (Integer
d' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
b) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
h :: Integer
h = (Integer
d' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
b) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
a :: Integer
a = Integer
x1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
x1
b :: Integer
b = Integer
y1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y1
c :: Integer
c = 2 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
z1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
z1
d' :: Integer
d' = (-Integer
a) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
j :: Integer
j = (Integer
x1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
y1) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
negateExtendedPoint :: ExtendedPoint preserving -> ExtendedPoint preserving
negateExtendedPoint :: ExtendedPoint preserving -> ExtendedPoint preserving
negateExtendedPoint ExtendedPoint{$sel:x:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
x = Integer
x1, $sel:y:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
y = Integer
y1, $sel:z:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
z = Integer
z1, $sel:t:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
t = Integer
t1} =
$WExtendedPoint :: forall (groupMembership :: GroupMembership).
Integer
-> Integer -> Integer -> Integer -> ExtendedPoint groupMembership
ExtendedPoint{$sel:x:ExtendedPoint :: Integer
x= Integer
q Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
x1, $sel:y:ExtendedPoint :: Integer
y = Integer
y1, $sel:z:ExtendedPoint :: Integer
z = Integer
z1, $sel:t:ExtendedPoint :: Integer
t = Integer
q Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
t1}
safeScalarMultiply :: Integer -> ExtendedPoint a -> ExtendedPoint a
safeScalarMultiply :: Integer -> ExtendedPoint a -> ExtendedPoint a
safeScalarMultiply n :: Integer
n = (ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a)
-> Integer -> ExtendedPoint a -> ExtendedPoint a
forall (a :: GroupMembership).
(ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a)
-> Integer -> ExtendedPoint a -> ExtendedPoint a
scalarMultiplyExtendedPoint ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
forall (a :: GroupMembership).
ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
addExtendedPoints Integer
n
scalarMultiplyExtendedPoint :: (ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a) -> Integer -> ExtendedPoint a -> ExtendedPoint a
scalarMultiplyExtendedPoint :: (ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a)
-> Integer -> ExtendedPoint a -> ExtendedPoint a
scalarMultiplyExtendedPoint _ 0 _ = ExtendedPoint a
forall (a :: GroupMembership). ExtendedPoint a
extendedZero
scalarMultiplyExtendedPoint add :: ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
add n :: Integer
n x :: ExtendedPoint a
x
| Integer -> Bool
forall a. Integral a => a -> Bool
even Integer
n = ExtendedPoint a -> ExtendedPoint a
forall (preserving :: GroupMembership).
ExtendedPoint preserving -> ExtendedPoint preserving
doubleExtendedPoint ((ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a)
-> Integer -> ExtendedPoint a -> ExtendedPoint a
forall (a :: GroupMembership).
(ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a)
-> Integer -> ExtendedPoint a -> ExtendedPoint a
scalarMultiplyExtendedPoint ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
add (Integer
n Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` 2) ExtendedPoint a
x)
| Integer
n Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 1 = ExtendedPoint a
x
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= 0 = Text -> ExtendedPoint a
forall a. HasCallStack => Text -> a
panic (Text -> ExtendedPoint a) -> Text -> ExtendedPoint a
forall a b. (a -> b) -> a -> b
$ "Unexpected negative multiplier: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Integer -> Text
forall a b. (Show a, ConvertText String b) => a -> b
show Integer
n
| Bool
otherwise = ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
add ExtendedPoint a
x ((ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a)
-> Integer -> ExtendedPoint a -> ExtendedPoint a
forall (a :: GroupMembership).
(ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a)
-> Integer -> ExtendedPoint a -> ExtendedPoint a
scalarMultiplyExtendedPoint ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
add (Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- 1) ExtendedPoint a
x)
makeGroupMember :: Integer -> Either Error (Element Ed25519)
makeGroupMember :: Integer -> Either Error (Element Ed25519)
makeGroupMember y :: Integer
y = do
ExtendedPoint 'Unknown
point <- AffinePoint -> ExtendedPoint 'Unknown
affineToExtended (AffinePoint -> ExtendedPoint 'Unknown)
-> Either Error AffinePoint
-> Either Error (ExtendedPoint 'Unknown)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Integer -> Integer -> Either Error AffinePoint
makeAffinePoint (Integer -> Integer
xRecover Integer
y) Integer
y
let point8 :: ExtendedPoint 'Unknown
point8 = Integer -> ExtendedPoint 'Unknown -> ExtendedPoint 'Unknown
forall (a :: GroupMembership).
Integer -> ExtendedPoint a -> ExtendedPoint a
safeScalarMultiply 8 ExtendedPoint 'Unknown
point
if ExtendedPoint 'Unknown -> Bool
forall (irrelevant :: GroupMembership).
ExtendedPoint irrelevant -> Bool
isExtendedZero ExtendedPoint 'Unknown
point8
then Error -> Either Error (ExtendedPoint 'Member)
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (Error -> Either Error (ExtendedPoint 'Member))
-> Error -> Either Error (ExtendedPoint 'Member)
forall a b. (a -> b) -> a -> b
$ ExtendedPoint 'Unknown -> Error
LowOrderPoint ExtendedPoint 'Unknown
point
else ExtendedPoint 'Unknown -> Either Error (ExtendedPoint 'Member)
ensureInGroup ExtendedPoint 'Unknown
point8
data AffinePoint
= AffinePoint
{ AffinePoint -> Integer
x :: !Integer
, AffinePoint -> Integer
y :: !Integer
} deriving (AffinePoint -> AffinePoint -> Bool
(AffinePoint -> AffinePoint -> Bool)
-> (AffinePoint -> AffinePoint -> Bool) -> Eq AffinePoint
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AffinePoint -> AffinePoint -> Bool
$c/= :: AffinePoint -> AffinePoint -> Bool
== :: AffinePoint -> AffinePoint -> Bool
$c== :: AffinePoint -> AffinePoint -> Bool
Eq, Int -> AffinePoint -> ShowS
[AffinePoint] -> ShowS
AffinePoint -> String
(Int -> AffinePoint -> ShowS)
-> (AffinePoint -> String)
-> ([AffinePoint] -> ShowS)
-> Show AffinePoint
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AffinePoint] -> ShowS
$cshowList :: [AffinePoint] -> ShowS
show :: AffinePoint -> String
$cshow :: AffinePoint -> String
showsPrec :: Int -> AffinePoint -> ShowS
$cshowsPrec :: Int -> AffinePoint -> ShowS
Show)
makeAffinePoint :: Integer -> Integer -> Either Error AffinePoint
makeAffinePoint :: Integer -> Integer -> Either Error AffinePoint
makeAffinePoint x :: Integer
x y :: Integer
y
| Integer -> Integer -> Bool
isOnCurve Integer
x Integer
y = AffinePoint -> Either Error AffinePoint
forall (f :: * -> *) a. Applicative f => a -> f a
pure $WAffinePoint :: Integer -> Integer -> AffinePoint
AffinePoint { $sel:x:AffinePoint :: Integer
x = Integer
x, $sel:y:AffinePoint :: Integer
y = Integer
y }
| Bool
otherwise = Error -> Either Error AffinePoint
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (Error -> Either Error AffinePoint)
-> Error -> Either Error AffinePoint
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Error
NotOnCurve Integer
x Integer
y
where
isOnCurve :: Integer -> Integer -> Bool
isOnCurve x' :: Integer
x' y' :: Integer
y' = ((-Integer
x') Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
x' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
y' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- 1 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
dConst Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
x' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
x' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y' Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y') Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 0
encodeAffinePoint :: (ByteArray bytes, ByteArrayAccess bytes) => AffinePoint -> bytes
encodeAffinePoint :: AffinePoint -> bytes
encodeAffinePoint AffinePoint{Integer
x :: Integer
$sel:x:AffinePoint :: AffinePoint -> Integer
x, Integer
y :: Integer
$sel:y:AffinePoint :: AffinePoint -> Integer
y}
| Integer -> Bool
forall a. Integral a => a -> Bool
even Integer
x = Integer -> bytes
forall bytes. ByteArray bytes => Integer -> bytes
numberToLitteEndianBytes Integer
y
| Bool
otherwise = Integer -> bytes
forall bytes. ByteArray bytes => Integer -> bytes
numberToLitteEndianBytes (Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer -> Int -> Integer
forall a. Bits a => a -> Int -> a
shift 1 255)
decodeAffinePoint :: (ByteArray bytes, ByteArrayAccess bytes) => bytes -> Either Error AffinePoint
decodeAffinePoint :: bytes -> Either Error AffinePoint
decodeAffinePoint bytes :: bytes
bytes =
let unclamped :: Integer
unclamped = bytes -> Integer
forall bytes.
(ByteArray bytes, ByteArrayAccess bytes) =>
bytes -> Integer
littleEndianBytesToNumber bytes
bytes
clamp :: Integer
clamp = Integer -> Int -> Integer
forall a. Bits a => a -> Int -> a
shift 1 255 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- 1
y :: Integer
y = Integer
unclamped Integer -> Integer -> Integer
forall a. Bits a => a -> a -> a
.&. Integer
clamp
x :: Integer
x = Integer -> Integer
xRecover Integer
y
x' :: Integer
x' = if Integer
x Integer -> Integer -> Integer
forall a. Bits a => a -> a -> a
.&. 1 Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
unclamped Integer -> Integer -> Integer
forall a. Bits a => a -> a -> a
.&. Integer -> Int -> Integer
forall a. Bits a => a -> Int -> a
shift 1 255 then Integer
x else Integer
q Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
x
in Integer -> Integer -> Either Error AffinePoint
makeAffinePoint Integer
x' Integer
y
numberToLitteEndianBytes :: ByteArray bytes => Integer -> bytes
numberToLitteEndianBytes :: Integer -> bytes
numberToLitteEndianBytes n :: Integer
n = [Word8] -> bytes
forall a. ByteArray a => [Word8] -> a
ByteArray.pack ([Word8] -> [Word8]
forall a. [a] -> [a]
reverse (ByteString -> [Word8]
forall a. ByteArrayAccess a => a -> [Word8]
ByteArray.unpack (Integer -> ByteString
forall bytes. ByteArray bytes => Integer -> bytes
i2osp Integer
n :: ByteString)))
littleEndianBytesToNumber :: (ByteArray bytes, ByteArrayAccess bytes) => bytes -> Integer
littleEndianBytesToNumber :: bytes -> Integer
littleEndianBytesToNumber bytes :: bytes
bytes = ByteString -> Integer
forall bytes. ByteArrayAccess bytes => bytes -> Integer
os2ip ([Word8] -> ByteString
forall a. ByteArray a => [Word8] -> a
ByteArray.pack ([Word8] -> [Word8]
forall a. [a] -> [a]
reverse (bytes -> [Word8]
forall a. ByteArrayAccess a => a -> [Word8]
ByteArray.unpack bytes
bytes)) :: ByteString)
affineToExtended :: AffinePoint -> ExtendedPoint 'Unknown
affineToExtended :: AffinePoint -> ExtendedPoint 'Unknown
affineToExtended AffinePoint{Integer
x :: Integer
$sel:x:AffinePoint :: AffinePoint -> Integer
x, Integer
y :: Integer
$sel:y:AffinePoint :: AffinePoint -> Integer
y} =
$WExtendedPoint :: forall (groupMembership :: GroupMembership).
Integer
-> Integer -> Integer -> Integer -> ExtendedPoint groupMembership
ExtendedPoint
{ $sel:x:ExtendedPoint :: Integer
x = Integer
x Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
, $sel:y:ExtendedPoint :: Integer
y = Integer
y Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
, $sel:z:ExtendedPoint :: Integer
z = 1
, $sel:t:ExtendedPoint :: Integer
t = (Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
}
extendedToAffine' :: ExtendedPoint a -> AffinePoint
extendedToAffine' :: ExtendedPoint a -> AffinePoint
extendedToAffine' ExtendedPoint{Integer
x :: Integer
$sel:x:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
x, Integer
y :: Integer
$sel:y:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
y, Integer
z :: Integer
$sel:z:ExtendedPoint :: forall (groupMembership :: GroupMembership).
ExtendedPoint groupMembership -> Integer
z} =
case Integer -> Integer -> Either Error AffinePoint
makeAffinePoint Integer
x' Integer
y' of
Left err :: Error
err -> Text -> AffinePoint
forall a. HasCallStack => Text -> a
panic (Text -> AffinePoint) -> Text -> AffinePoint
forall a b. (a -> b) -> a -> b
$ "Could not make affine point: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Error -> Text
forall a b. (Show a, ConvertText String b) => a -> b
show Error
err
Right r :: AffinePoint
r -> AffinePoint
r
where
x' :: Integer
x' = (Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer
inv Integer
z) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
y' :: Integer
y' = (Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer
inv Integer
z) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q