module Crypto.PubKey.ECC.ECDSA
( module Crypto.Types.PubKey.ECDSA
, signWith
, sign
, verify
) where
import Control.Monad
import Crypto.Random
import Data.Bits (shiftR)
import Data.ByteString (ByteString)
import Crypto.Number.ModArithmetic (inverse)
import Crypto.Number.Serialize
import Crypto.Number.Generate
import Crypto.Types.PubKey.ECDSA
import Crypto.Types.PubKey.ECC
import Crypto.PubKey.HashDescr
import Crypto.PubKey.ECC.Prim
signWith :: Integer
-> PrivateKey
-> HashFunction
-> ByteString
-> Maybe Signature
signWith k (PrivateKey curve d) hash msg = do
let z = tHash hash 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 :: CPRG g => g -> PrivateKey -> HashFunction -> ByteString -> (Signature, g)
sign rng pk hash msg =
case signWith k pk hash msg of
Nothing -> sign rng' pk hash msg
Just sig -> (sig, rng')
where n = ecc_n . common_curve $ private_curve pk
(k, rng') = generateBetween rng 1 (n 1)
verify :: HashFunction -> PublicKey -> Signature -> ByteString -> Bool
verify _ (PublicKey _ PointO) _ _ = False
verify hash 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 hash msg n
u1 = z * w `mod` n
u2 = r * w `mod` n
g' = pointMul curve u1 g
q' = pointMul curve u2 q
x = pointAdd curve g' 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 :: HashFunction -> ByteString -> Integer -> Integer
tHash hash m n
| d > 0 = shiftR e d
| otherwise = e
where e = os2ip $ hash m
d = log2 e log2 n
log2 = ceiling . logBase (2 :: Double) . fromIntegral