@@ -24,37 +24,48 @@ import (
2424 "crypto/elliptic"
2525 "errors"
2626 "fmt"
27- "math/big"
2827
29- "github.com/btcsuite/btcd/btcec"
28+ "github.com/btcsuite/btcd/btcec/v2"
29+ btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa"
3030)
3131
3232// Ecrecover returns the uncompressed public key that created the given signature.
3333func Ecrecover (hash , sig []byte ) ([]byte , error ) {
34- pub , err := SigToPub (hash , sig )
34+ pub , err := sigToPub (hash , sig )
3535 if err != nil {
3636 return nil , err
3737 }
38- bytes := ( * btcec . PublicKey )( pub ) .SerializeUncompressed ()
38+ bytes := pub .SerializeUncompressed ()
3939 return bytes , err
4040}
4141
42- // SigToPub returns the public key that created the given signature.
43- func SigToPub (hash , sig []byte ) (* ecdsa.PublicKey , error ) {
42+ func sigToPub (hash , sig []byte ) (* btcec.PublicKey , error ) {
43+ if len (sig ) != SignatureLength {
44+ return nil , errors .New ("invalid signature" )
45+ }
4446 // Convert to btcec input format with 'recovery id' v at the beginning.
4547 btcsig := make ([]byte , SignatureLength )
46- btcsig [0 ] = sig [64 ] + 27
48+ btcsig [0 ] = sig [RecoveryIDOffset ] + 27
4749 copy (btcsig [1 :], sig )
4850
49- pub , _ , err := btcec .RecoverCompact (btcec .S256 (), btcsig , hash )
50- return (* ecdsa .PublicKey )(pub ), err
51+ pub , _ , err := btc_ecdsa .RecoverCompact (btcsig , hash )
52+ return pub , err
53+ }
54+
55+ // SigToPub returns the public key that created the given signature.
56+ func SigToPub (hash , sig []byte ) (* ecdsa.PublicKey , error ) {
57+ pub , err := sigToPub (hash , sig )
58+ if err != nil {
59+ return nil , err
60+ }
61+ return pub .ToECDSA (), nil
5162}
5263
5364// Sign calculates an ECDSA signature.
5465//
5566// This function is susceptible to chosen plaintext attacks that can leak
5667// information about the private key that is used for signing. Callers must
57- // be aware that the given hash cannot be chosen by an adversery . Common
68+ // be aware that the given hash cannot be chosen by an adversary . Common
5869// solution is to hash any input before calculating the signature.
5970//
6071// The produced signature is in the [R || S || V] format where V is 0 or 1.
@@ -65,14 +76,20 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
6576 if prv .Curve != btcec .S256 () {
6677 return nil , fmt .Errorf ("private key curve is not secp256k1" )
6778 }
68- sig , err := btcec .SignCompact (btcec .S256 (), (* btcec .PrivateKey )(prv ), hash , false )
79+ // ecdsa.PrivateKey -> btcec.PrivateKey
80+ var priv btcec.PrivateKey
81+ if overflow := priv .Key .SetByteSlice (prv .D .Bytes ()); overflow || priv .Key .IsZero () {
82+ return nil , fmt .Errorf ("invalid private key" )
83+ }
84+ defer priv .Zero ()
85+ sig , err := btc_ecdsa .SignCompact (& priv , hash , false ) // ref uncompressed pubkey
6986 if err != nil {
7087 return nil , err
7188 }
7289 // Convert to Ethereum signature format with 'recovery id' v at the end.
7390 v := sig [0 ] - 27
7491 copy (sig , sig [1 :])
75- sig [64 ] = v
92+ sig [RecoveryIDOffset ] = v
7693 return sig , nil
7794}
7895
@@ -83,13 +100,20 @@ func VerifySignature(pubkey, hash, signature []byte) bool {
83100 if len (signature ) != 64 {
84101 return false
85102 }
86- sig := & btcec.Signature {R : new (big.Int ).SetBytes (signature [:32 ]), S : new (big.Int ).SetBytes (signature [32 :])}
87- key , err := btcec .ParsePubKey (pubkey , btcec .S256 ())
103+ var r , s btcec.ModNScalar
104+ if r .SetByteSlice (signature [:32 ]) {
105+ return false // overflow
106+ }
107+ if s .SetByteSlice (signature [32 :]) {
108+ return false
109+ }
110+ sig := btc_ecdsa .NewSignature (& r , & s )
111+ key , err := btcec .ParsePubKey (pubkey )
88112 if err != nil {
89113 return false
90114 }
91115 // Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
92- if sig . S . Cmp ( secp256k1halfN ) > 0 {
116+ if s . IsOverHalfOrder () {
93117 return false
94118 }
95119 return sig .Verify (hash , key )
@@ -100,16 +124,26 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
100124 if len (pubkey ) != 33 {
101125 return nil , errors .New ("invalid compressed public key length" )
102126 }
103- key , err := btcec .ParsePubKey (pubkey , btcec . S256 () )
127+ key , err := btcec .ParsePubKey (pubkey )
104128 if err != nil {
105129 return nil , err
106130 }
107131 return key .ToECDSA (), nil
108132}
109133
110- // CompressPubkey encodes a public key to the 33-byte compressed format.
134+ // CompressPubkey encodes a public key to the 33-byte compressed format. The
135+ // provided PublicKey must be valid. Namely, the coordinates must not be larger
136+ // than 32 bytes each, they must be less than the field prime, and it must be a
137+ // point on the secp256k1 curve. This is the case for a PublicKey constructed by
138+ // elliptic.Unmarshal (see UnmarshalPubkey), or by ToECDSA and ecdsa.GenerateKey
139+ // when constructing a PrivateKey.
111140func CompressPubkey (pubkey * ecdsa.PublicKey ) []byte {
112- return (* btcec .PublicKey )(pubkey ).SerializeCompressed ()
141+ // NOTE: the coordinates may be validated with
142+ // btcec.ParsePubKey(FromECDSAPub(pubkey))
143+ var x , y btcec.FieldVal
144+ x .SetByteSlice (pubkey .X .Bytes ())
145+ y .SetByteSlice (pubkey .Y .Bytes ())
146+ return btcec .NewPublicKey (& x , & y ).SerializeCompressed ()
113147}
114148
115149// S256 returns an instance of the secp256k1 curve.
0 commit comments