{-# LANGUAGE CPP #-}
#ifndef mingw32_HOST_OS
{-# LANGUAGE Safe #-}
#else
{-# LANGUAGE Trustworthy #-}
#endif
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Crypto.ECC.Ed25519.Sign ( genkeys
, publickey
, dsign
, sign
, dverify
, verify
, Message
, PubKey
, SecKey
, Signature
, SignedMessage
, SigOK(..)
, VerifyResult
)
where
import safe Crypto.ECC.Ed25519.Internal.Ed25519
import safe Prelude ((==),($),(<),IO,return,pure,Either(Left,Right),String,(&&))
import safe qualified Crypto.Fi as FP
import safe qualified Data.ByteString as BS
#ifndef mingw32_HOST_OS
import safe qualified Data.ByteString.Lazy.Char8 as BS8
#else
import qualified Crypto.Random as R
import safe Prelude (show)
#endif
genkeys :: IO (Either String (SecKey,PubKey))
genkeys :: IO (Either String (SecKey, PubKey))
genkeys = do
#ifndef mingw32_HOST_OS
ByteString
bytes <- String -> IO ByteString
BS8.readFile String
"/dev/urandom"
let sk :: SecKey
sk = PubKey -> SecKey
SecKeyBytes (PubKey -> SecKey) -> PubKey -> SecKey
forall a b. (a -> b) -> a -> b
$ ByteString -> PubKey
BS8.toStrict (ByteString -> PubKey) -> ByteString -> PubKey
forall a b. (a -> b) -> a -> b
$ Int64 -> ByteString -> ByteString
BS8.take Int64
32 ByteString
bytes
derived :: Either String PubKey
derived = SecKey -> Either String PubKey
publickey SecKey
sk
Either String (SecKey, PubKey)
-> IO (Either String (SecKey, PubKey))
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (SecKey, PubKey)
-> IO (Either String (SecKey, PubKey)))
-> Either String (SecKey, PubKey)
-> IO (Either String (SecKey, PubKey))
forall a b. (a -> b) -> a -> b
$ case Either String PubKey
derived of
Left String
e -> String -> Either String (SecKey, PubKey)
forall a b. a -> Either a b
Left String
e
Right PubKey
pk -> (SecKey, PubKey) -> Either String (SecKey, PubKey)
forall a b. b -> Either a b
Right (SecKey
sk,PubKey
pk)
#else
g <- (R.newGenIO :: IO R.SystemRandom)
let prngresult = R.genBytes 32 g
case prngresult of
Left e -> return $ Left $ show e
Right (bytes,_) -> let sk = SecKeyBytes bytes
derived = publickey sk
in return $ case derived of
Left e -> Left e
Right pk -> Right (sk,pk)
#endif
publickey :: SecKey -> Either String PubKey
publickey :: SecKey -> Either String PubKey
publickey (SecKeyBytes PubKey
sk) = let mysk :: PubKey
mysk = Int -> PubKey -> PubKey
BS.take Int
32 PubKey
sk
secret :: Either String FPrime
secret = PubKey -> Either String FPrime
clamp (PubKey -> Either String FPrime) -> PubKey -> Either String FPrime
forall a b. (a -> b) -> a -> b
$ Int -> PubKey -> PubKey
BS.take Int
32 (PubKey -> PubKey) -> PubKey -> PubKey
forall a b. (a -> b) -> a -> b
$ PubKey -> PubKey
h PubKey
mysk
in case Either String FPrime
secret of
Left String
e -> String -> Either String PubKey
forall a b. a -> Either a b
Left String
e
Right FPrime
sec -> let aB :: Point
aB = Point -> FPrime -> Point
pmul Point
bPoint FPrime
sec
in if Point -> Bool
ison Point
aB
then PubKey -> Either String PubKey
forall a b. b -> Either a b
Right (Point -> PubKey
pointtobs Point
aB)
else String -> Either String PubKey
forall a b. a -> Either a b
Left String
"public key is not on curve"
sign :: SecKey -> Message -> Either String SignedMessage
sign :: SecKey -> PubKey -> Either String PubKey
sign SecKey
sk PubKey
m = case SecKey -> PubKey -> Either String PubKey
dsign SecKey
sk PubKey
m of
Left String
e -> String -> Either String PubKey
forall a b. a -> Either a b
Left String
e
Right PubKey
sig -> PubKey -> Either String PubKey
forall a b. b -> Either a b
Right (PubKey -> PubKey -> PubKey
BS.append PubKey
sig PubKey
m)
verify :: PubKey -> SignedMessage -> VerifyResult
verify :: PubKey -> PubKey -> VerifyResult
verify PubKey
a_ PubKey
sigm = let sig :: PubKey
sig = Int -> PubKey -> PubKey
BS.take Int
64 PubKey
sigm
m :: PubKey
m = Int -> PubKey -> PubKey
BS.drop Int
64 PubKey
sigm
in PubKey -> PubKey -> PubKey -> VerifyResult
dverify PubKey
a_ PubKey
sig PubKey
m
dsign :: SecKey -> Message -> Either String Signature
dsign :: SecKey -> PubKey -> Either String PubKey
dsign (SecKeyBytes PubKey
sk) PubKey
m = do
let mysk :: PubKey
mysk = Int -> PubKey -> PubKey
BS.take Int
32 PubKey
sk
hsk :: PubKey
hsk = PubKey -> PubKey
h PubKey
mysk
ahsk :: PubKey
ahsk = Int -> PubKey -> PubKey
BS.take Int
32 PubKey
hsk
rhsk :: PubKey
rhsk = Int -> PubKey -> PubKey
BS.drop Int
32 PubKey
hsk
FPrime
r <- PubKey -> Either String FPrime
getFPrime64 (PubKey -> Either String FPrime) -> PubKey -> Either String FPrime
forall a b. (a -> b) -> a -> b
$ PubKey -> PubKey
h (PubKey -> PubKey) -> PubKey -> PubKey
forall a b. (a -> b) -> a -> b
$ PubKey
rhsk `BS.append ` PubKey
m
let rB_ :: PubKey
rB_ = Point -> PubKey
pointtobs (Point -> PubKey) -> Point -> PubKey
forall a b. (a -> b) -> a -> b
$ Point -> FPrime -> Point
pmul Point
bPoint (FPrime -> FPrime -> FPrime
FP.redc FPrime
l FPrime
r)
FPrime
a' <- PubKey -> Either String FPrime
clamp PubKey
ahsk
let aB_ :: PubKey
aB_ = Point -> PubKey
pointtobs (Point -> PubKey) -> Point -> PubKey
forall a b. (a -> b) -> a -> b
$ Point -> FPrime -> Point
pmul Point
bPoint FPrime
a'
FPrime
t' <- PubKey -> Either String FPrime
getFPrime64 (PubKey -> PubKey
h (PubKey -> PubKey) -> PubKey -> PubKey
forall a b. (a -> b) -> a -> b
$ PubKey
rB_ PubKey -> PubKey -> PubKey
`BS.append` PubKey
aB_ PubKey -> PubKey -> PubKey
`BS.append` PubKey -> PubKey
ph PubKey
m)
let s :: FPrime
s = FPrime -> FPrime -> FPrime -> FPrime
FP.addr FPrime
l FPrime
r (FPrime -> FPrime -> FPrime -> FPrime
FP.mulr FPrime
l FPrime
t' FPrime
a')
let s_ :: PubKey
s_ = FPrime -> PubKey
putFPrime FPrime
s
PubKey -> Either String PubKey
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PubKey -> Either String PubKey) -> PubKey -> Either String PubKey
forall a b. (a -> b) -> a -> b
$ PubKey -> PubKey -> PubKey
BS.append PubKey
rB_ PubKey
s_
dverify :: PubKey -> Signature -> Message -> VerifyResult
dverify :: PubKey -> PubKey -> PubKey -> VerifyResult
dverify PubKey
a_ PubKey
sig PubKey
m = do
let r_ :: PubKey
r_ = Int -> PubKey -> PubKey
BS.take Int
32 PubKey
sig
Point
r <- PubKey -> Either String Point
bstopoint PubKey
r_
Point
a' <- PubKey -> Either String Point
bstopoint PubKey
a_
FPrime
s' <- PubKey -> Either String FPrime
getFPrime32 (PubKey -> Either String FPrime) -> PubKey -> Either String FPrime
forall a b. (a -> b) -> a -> b
$ Int -> PubKey -> PubKey
BS.drop Int
32 PubKey
sig
FPrime
t <- PubKey -> Either String FPrime
getFPrime64 (PubKey -> Either String FPrime) -> PubKey -> Either String FPrime
forall a b. (a -> b) -> a -> b
$ PubKey -> PubKey
h (PubKey -> PubKey) -> PubKey -> PubKey
forall a b. (a -> b) -> a -> b
$ PubKey
r_ PubKey -> PubKey -> PubKey
`BS.append` PubKey
a_ PubKey -> PubKey -> PubKey
`BS.append` PubKey
m
if (FPrime -> FPrime
FP.toInteger FPrime
s' FPrime -> FPrime -> Bool
forall a. Ord a => a -> a -> Bool
< FPrime -> FPrime
FP.toInteger FPrime
l) Bool -> Bool -> Bool
&& (Point -> Point
scale (Point -> Point) -> Point -> Point
forall a b. (a -> b) -> a -> b
$ Point -> FPrime -> Point
pmul Point
bPoint (FPrime -> FPrime -> FPrime
FP.redc FPrime
l FPrime
s')) Point -> Point -> Bool
forall a. Eq a => a -> a -> Bool
== (Point -> Point
scale (Point -> Point) -> Point -> Point
forall a b. (a -> b) -> a -> b
$ Point -> Point -> Point
padd Point
r (Point -> Point) -> Point -> Point
forall a b. (a -> b) -> a -> b
$ Point -> FPrime -> Point
pmul Point
a' (FPrime -> FPrime -> FPrime
FP.redc FPrime
l FPrime
t))
then SigOK -> VerifyResult
forall a b. b -> Either a b
Right SigOK
SigOK
else String -> VerifyResult
forall a b. a -> Either a b
Left String
"bad Signature"