ECDSA with digest

This commit is contained in:
Olivier Chéron 2019-05-08 08:18:07 +02:00
parent 15327ecd4f
commit b9a8a6b83d

View File

@ -37,8 +37,11 @@ module Crypto.PubKey.ECDSA
, signatureToIntegers , signatureToIntegers
-- * Generation and verification -- * Generation and verification
, signWith , signWith
, signDigestWith
, sign , sign
, signDigest
, verify , verify
, verifyDigest
) where ) where
import Control.Monad import Control.Monad
@ -162,11 +165,11 @@ toPublic :: EllipticCurveECDSA curve
=> proxy curve -> PrivateKey curve -> PublicKey curve => proxy curve -> PrivateKey curve -> PublicKey curve
toPublic = pointBaseSmul toPublic = pointBaseSmul
-- | Sign message using the private key and an explicit k scalar. -- | Sign digest using the private key and an explicit k scalar.
signWith :: (EllipticCurveECDSA curve, ByteArrayAccess msg, HashAlgorithm hash) signDigestWith :: (EllipticCurveECDSA curve, HashAlgorithm hash)
=> proxy curve -> Scalar curve -> PrivateKey curve -> hash -> msg -> Maybe (Signature curve) => proxy curve -> Scalar curve -> PrivateKey curve -> Digest hash -> Maybe (Signature curve)
signWith prx k d hashAlg msg = do signDigestWith prx k d digest = do
let z = tHash prx hashAlg msg let z = tHashDigest prx digest
point = pointBaseSmul prx k point = pointBaseSmul prx k
r <- pointX prx point r <- pointX prx point
kInv <- scalarInv prx k kInv <- scalarInv prx k
@ -174,24 +177,34 @@ signWith prx k d hashAlg msg = do
when (scalarIsZero prx r || scalarIsZero prx s) Nothing when (scalarIsZero prx r || scalarIsZero prx s) Nothing
return $ Signature r s return $ Signature r s
-- | Sign message using the private key and an explicit k scalar.
signWith :: (EllipticCurveECDSA curve, ByteArrayAccess msg, HashAlgorithm hash)
=> proxy curve -> Scalar curve -> PrivateKey curve -> hash -> msg -> Maybe (Signature curve)
signWith prx k d hashAlg msg = signDigestWith prx k d (hashWith hashAlg msg)
-- | Sign a digest using hash and private key.
signDigest :: (EllipticCurveECDSA curve, MonadRandom m, HashAlgorithm hash)
=> proxy curve -> PrivateKey curve -> Digest hash -> m (Signature curve)
signDigest prx pk digest = do
k <- curveGenerateScalar prx
case signDigestWith prx k pk digest of
Nothing -> signDigest prx pk digest
Just sig -> return sig
-- | Sign a message using hash and private key. -- | Sign a message using hash and private key.
sign :: (EllipticCurveECDSA curve, MonadRandom m, ByteArrayAccess msg, HashAlgorithm hash) sign :: (EllipticCurveECDSA curve, MonadRandom m, ByteArrayAccess msg, HashAlgorithm hash)
=> proxy curve -> PrivateKey curve -> hash -> msg -> m (Signature curve) => proxy curve -> PrivateKey curve -> hash -> msg -> m (Signature curve)
sign prx pk hashAlg msg = do sign prx pk hashAlg msg = signDigest prx pk (hashWith hashAlg msg)
k <- curveGenerateScalar prx
case signWith prx k pk hashAlg msg of
Nothing -> sign prx pk hashAlg msg
Just sig -> return sig
-- | Verify a signature using hash and public key. -- | Verify a digest using hash and public key.
verify :: (EllipticCurveECDSA curve, ByteArrayAccess msg, HashAlgorithm hash) verifyDigest :: (EllipticCurveECDSA curve, HashAlgorithm hash)
=> proxy curve -> hash -> PublicKey curve -> Signature curve -> msg -> Bool => proxy curve -> PublicKey curve -> Signature curve -> Digest hash -> Bool
verify prx hashAlg q (Signature r s) msg verifyDigest prx q (Signature r s) digest
| not (scalarIsValid prx r) = False | not (scalarIsValid prx r) = False
| not (scalarIsValid prx s) = False | not (scalarIsValid prx s) = False
| otherwise = maybe False (r ==) $ do | otherwise = maybe False (r ==) $ do
w <- scalarInv prx s w <- scalarInv prx s
let z = tHash prx hashAlg msg let z = tHashDigest prx digest
u1 = scalarMul prx z w u1 = scalarMul prx z w
u2 = scalarMul prx r w u2 = scalarMul prx r w
x = pointsSmulVarTime prx u1 u2 q x = pointsSmulVarTime prx u1 u2 q
@ -199,13 +212,21 @@ verify prx hashAlg q (Signature r s) msg
-- Note: precondition q /= PointO is not tested because we assume -- Note: precondition q /= PointO is not tested because we assume
-- point decoding never decodes point at infinity. -- point decoding never decodes point at infinity.
-- | Truncate and hash. -- | Verify a signature using hash and public key.
tHash :: (EllipticCurveECDSA curve, ByteArrayAccess msg, HashAlgorithm hash) verify :: (EllipticCurveECDSA curve, ByteArrayAccess msg, HashAlgorithm hash)
=> proxy curve -> hash -> msg -> Scalar curve => proxy curve -> hash -> PublicKey curve -> Signature curve -> msg -> Bool
tHash prx hashAlg m = verify prx hashAlg q sig msg = verifyDigest prx q sig (hashWith hashAlg msg)
-- | Truncate a digest based on curve order size.
tHashDigest :: (EllipticCurveECDSA curve, HashAlgorithm hash)
=> proxy curve -> Digest hash -> Scalar curve
tHashDigest prx digest =
throwCryptoError $ scalarFromInteger prx (if d > 0 then shiftR e d else e) throwCryptoError $ scalarFromInteger prx (if d > 0 then shiftR e d else e)
where e = os2ip $ hashWith hashAlg m where e = os2ip digest
d = hashDigestSize hashAlg * 8 - curveOrderBits prx d = hashDigestSize (getHashAlg digest) * 8 - curveOrderBits prx
getHashAlg :: Digest hash -> hash
getHashAlg _ = undefined
ecScalarIsValid :: Simple.Curve c => proxy c -> Simple.Scalar c -> Bool ecScalarIsValid :: Simple.Curve c => proxy c -> Simple.Scalar c -> Bool