{-# 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 Ed25519
_ Element Ed25519
x 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 Ed25519
_ 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 Ed25519
_ = HasCallStack => ExtendedPoint 'Unknown -> ExtendedPoint 'Member
ExtendedPoint 'Unknown -> ExtendedPoint 'Member
assertInGroup ExtendedPoint 'Unknown
forall (a :: GroupMembership). ExtendedPoint a
extendedZero
encodeElement :: Ed25519 -> Element Ed25519 -> bytes
encodeElement Ed25519
_ 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 Ed25519
_ bytes
bytes = Either Error (ExtendedPoint 'Member)
-> CryptoFailable (ExtendedPoint 'Member)
forall a. Either Error a -> CryptoFailable a
toCryptoFailable (Either Error (ExtendedPoint 'Member)
-> CryptoFailable (ExtendedPoint 'Member))
-> Either Error (ExtendedPoint 'Member)
-> CryptoFailable (ExtendedPoint 'Member)
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 Ed25519
_ = Int
255
arbitraryElement :: Ed25519 -> bytes -> Element Ed25519
arbitraryElement Ed25519
group 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
+ Int
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 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 Ed25519
_ Scalar Ed25519
n 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 Ed25519
_ Integer
x = Integer
Scalar Ed25519
x
scalarToInteger :: Ed25519 -> Scalar Ed25519 -> Integer
scalarToInteger Ed25519
_ Scalar Ed25519
x = Integer
Scalar Ed25519
x
scalarSizeBits :: Ed25519 -> Int
scalarSizeBits Ed25519
_ = Int
255
generateElement :: Ed25519 -> randomly (KeyPair Ed25519)
generateElement 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 a
r) = a -> CryptoFailable a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
r
toCryptoFailable (Left Error
_) = 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 ExtendedPoint :: 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 ExtendedPoint 'Unknown
element =
case ExtendedPoint 'Unknown -> Either Error (ExtendedPoint 'Member)
ensureInGroup ExtendedPoint 'Unknown
element of
Left Error
err -> Text -> ExtendedPoint 'Member
forall a. HasCallStack => Text -> a
panic (Text -> ExtendedPoint 'Member) -> Text -> ExtendedPoint 'Member
forall a b. (a -> b) -> a -> b
$ Text
"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 -> 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 ExtendedPoint 'Member
x -> ExtendedPoint 'Member
x
q :: Integer
q :: Integer
q = Integer
2 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Integer
255 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
19
l :: Integer
l :: Integer
l = Integer
2 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Integer
252 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
27742317777372353535851937790883648493
dConst :: Integer
dConst :: Integer
dConst = (-Integer
121665 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer
inv Integer
121666) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`mod` Integer
q
i :: Integer
i :: Integer
i = Integer -> Integer -> Integer -> Integer
expSafe Integer
2 ((Integer
qInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
-Integer
1) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
4) Integer
q
generator :: Element Ed25519
generator :: Element Ed25519
generator = HasCallStack => ExtendedPoint 'Unknown -> ExtendedPoint 'Member
ExtendedPoint 'Unknown -> ExtendedPoint 'Member
assertInGroup (ExtendedPoint 'Unknown -> ExtendedPoint 'Member)
-> ExtendedPoint 'Unknown -> ExtendedPoint 'Member
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 Error
err -> Text -> AffinePoint
forall a. HasCallStack => Text -> a
panic (Text -> AffinePoint) -> Text -> AffinePoint
forall a b. (a -> b) -> a -> b
$ Text
"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 AffinePoint
r -> AffinePoint
r
x :: Integer
x = Integer -> Integer
xRecover Integer
y
y :: Integer
y = Integer
4 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer -> Integer
inv Integer
5
inv :: Integer -> Integer
inv :: Integer -> Integer
inv Integer
x = Integer -> Integer -> Integer
inverseCoprimes Integer
x Integer
q
xRecover :: Integer -> Integer
xRecover :: Integer -> Integer
xRecover 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
- Integer
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
+ Integer
1)
x' :: Integer
x' = Integer -> Integer -> Integer -> Integer
expSafe Integer
x'' ((Integer
q Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
3) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
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
/= Integer
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
ExtendedPoint a
point1 == :: ExtendedPoint a -> ExtendedPoint a -> Bool
== 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 = ExtendedPoint :: forall (groupMembership :: GroupMembership).
Integer
-> Integer -> Integer -> Integer -> ExtendedPoint groupMembership
ExtendedPoint {$sel:x:ExtendedPoint :: Integer
x = Integer
0, $sel:y:ExtendedPoint :: Integer
y = Integer
1, $sel:z:ExtendedPoint :: Integer
z = Integer
1, $sel:t:ExtendedPoint :: Integer
t = Integer
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
== Integer
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
/= Integer
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} =
ExtendedPoint :: 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
* (Integer
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
* Integer
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} =
ExtendedPoint :: 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 = Integer
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} =
ExtendedPoint :: 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 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 ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
_ Integer
0 ExtendedPoint a
_ = ExtendedPoint a
forall (a :: GroupMembership). ExtendedPoint a
extendedZero
scalarMultiplyExtendedPoint ExtendedPoint a -> ExtendedPoint a -> ExtendedPoint a
add Integer
n 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` Integer
2) ExtendedPoint a
x)
| Integer
n Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1 = ExtendedPoint a
x
| Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
0 = Text -> ExtendedPoint a
forall a. HasCallStack => Text -> a
panic (Text -> ExtendedPoint a) -> Text -> ExtendedPoint a
forall a b. (a -> b) -> a -> b
$ Text
"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
- Integer
1) ExtendedPoint a
x)
makeGroupMember :: Integer -> Either Error (Element Ed25519)
makeGroupMember :: Integer -> Either Error (Element Ed25519)
makeGroupMember 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 Integer
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 Integer
x Integer
y
| Integer -> Integer -> Bool
isOnCurve Integer
x Integer
y = AffinePoint -> Either Error AffinePoint
forall (f :: * -> *) a. Applicative f => a -> f a
pure AffinePoint :: 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 Integer
x' 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
- Integer
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
== Integer
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 Integer
1 Int
255)
decodeAffinePoint :: (ByteArray bytes, ByteArrayAccess bytes) => bytes -> Either Error AffinePoint
decodeAffinePoint :: bytes -> Either Error AffinePoint
decodeAffinePoint 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 Integer
1 Int
255 Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
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
.&. Integer
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 Integer
1 Int
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 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 = 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} =
ExtendedPoint :: 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 = Integer
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 Error
err -> Text -> AffinePoint
forall a. HasCallStack => Text -> a
panic (Text -> AffinePoint) -> Text -> AffinePoint
forall a b. (a -> b) -> a -> b
$ Text
"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 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