-- | /WARNING:/ Signature operations may leak the private key. Signature verification
-- should be safe.
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
-- | Sign message using the private key and an explicit k number.
--
-- /WARNING:/ Vulnerable to timing attacks.
signWith
::
Integer
-- ^ k random number
->
PrivateKey
-- ^ private key
->
HashFunction
-- ^ hash function
->
ByteString
-- ^ message to sign
->
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 message using the private key.
--
-- /WARNING:/ Vulnerable to timing attacks.
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 a bytestring using the public key.
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
-- TODO: Use Shamir's trick
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
-- | Truncate and hash.
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