module Crypto.PubKey.ECC.ECDSA
( Signature(..)
, PublicPoint
, PublicKey(..)
, PrivateNumber
, PrivateKey(..)
, KeyPair(..)
, toPublicKey
, toPrivateKey
, signWith
, sign
, verify
) where
import Control.Monad
import Crypto.Random.Types
import Data.Bits (shiftR)
import Crypto.Internal.ByteArray (ByteArrayAccess)
import Data.Data
import Crypto.Number.Basic (numBits)
import Crypto.Number.ModArithmetic (inverse)
import Crypto.Number.Serialize
import Crypto.Number.Generate
import Crypto.PubKey.ECC.Types
import Crypto.PubKey.ECC.Prim
import Crypto.Hash
import Crypto.Hash.Types (hashDigestSize)
data Signature = Signature
{ sign_r :: Integer
, sign_s :: Integer
} deriving (Show,Read,Eq,Data,Typeable)
data PrivateKey = PrivateKey
{ private_curve :: Curve
, private_d :: PrivateNumber
} deriving (Show,Read,Eq,Data,Typeable)
data PublicKey = PublicKey
{ public_curve :: Curve
, public_q :: PublicPoint
} deriving (Show,Read,Eq,Data,Typeable)
data KeyPair = KeyPair Curve PublicPoint PrivateNumber
deriving (Show,Read,Eq,Data,Typeable)
toPublicKey :: KeyPair -> PublicKey
toPublicKey (KeyPair curve pub _) = PublicKey curve pub
toPrivateKey :: KeyPair -> PrivateKey
toPrivateKey (KeyPair curve _ priv) = PrivateKey curve priv
signWith :: (ByteArrayAccess msg, HashAlgorithm hash)
=> Integer
-> PrivateKey
-> hash
-> msg
-> Maybe Signature
signWith k (PrivateKey curve d) hashAlg msg = do
let z = tHash hashAlg msg n
CurveCommon _ _ g n _ = common_curve curve
let point = pointMul curve k g
r <- case point of
PointO -> Nothing
Point x _ -> return $ x `mod` n
kInv <- inverse k n
let s = kInv * (z + r * d) `mod` n
when (r == 0 || s == 0) Nothing
return $ Signature r s
sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m)
=> PrivateKey -> hash -> msg -> m Signature
sign pk hashAlg msg = do
k <- generateBetween 1 (n 1)
case signWith k pk hashAlg msg of
Nothing -> sign pk hashAlg msg
Just sig -> return sig
where n = ecc_n . common_curve $ private_curve pk
verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool
verify _ (PublicKey _ PointO) _ _ = False
verify hashAlg pk@(PublicKey curve q) (Signature r s) msg
| r < 1 || r >= n || s < 1 || s >= n = False
| otherwise = maybe False (r ==) $ do
w <- inverse s n
let z = tHash hashAlg msg n
u1 = z * w `mod` n
u2 = r * w `mod` n
x = pointAddTwoMuls curve u1 g u2 q
case x of
PointO -> Nothing
Point x1 _ -> return $ x1 `mod` n
where n = ecc_n cc
g = ecc_g cc
cc = common_curve $ public_curve pk
tHash :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> msg -> Integer -> Integer
tHash hashAlg m n
| d > 0 = shiftR e d
| otherwise = e
where e = os2ip $ hashWith hashAlg m
d = hashDigestSize hashAlg * 8 numBits n