@@ -24,55 +24,72 @@ import (
24
24
"crypto/elliptic"
25
25
"errors"
26
26
"fmt"
27
- "math/big"
28
27
29
- "github.com/btcsuite/btcd/btcec"
28
+ "github.com/btcsuite/btcd/btcec/v2"
29
+ btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa"
30
30
)
31
31
32
32
// Ecrecover returns the uncompressed public key that created the given signature.
33
33
func Ecrecover (hash , sig []byte ) ([]byte , error ) {
34
- pub , err := SigToPub (hash , sig )
34
+ pub , err := sigToPub (hash , sig )
35
35
if err != nil {
36
36
return nil , err
37
37
}
38
- bytes := ( * btcec . PublicKey )( pub ) .SerializeUncompressed ()
38
+ bytes := pub .SerializeUncompressed ()
39
39
return bytes , err
40
40
}
41
41
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
+ }
44
46
// Convert to btcec input format with 'recovery id' v at the beginning.
45
47
btcsig := make ([]byte , SignatureLength )
46
- btcsig [0 ] = sig [64 ] + 27
48
+ btcsig [0 ] = sig [RecoveryIDOffset ] + 27
47
49
copy (btcsig [1 :], sig )
48
50
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
51
62
}
52
63
53
64
// Sign calculates an ECDSA signature.
54
65
//
55
66
// This function is susceptible to chosen plaintext attacks that can leak
56
67
// 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
58
69
// solution is to hash any input before calculating the signature.
59
70
//
60
71
// The produced signature is in the [R || S || V] format where V is 0 or 1.
61
72
func Sign (hash []byte , prv * ecdsa.PrivateKey ) ([]byte , error ) {
62
- if len (hash ) != DigestLength {
73
+ if len (hash ) != 32 {
63
74
return nil , fmt .Errorf ("hash is required to be exactly 32 bytes (%d)" , len (hash ))
64
75
}
65
76
if prv .Curve != btcec .S256 () {
66
77
return nil , fmt .Errorf ("private key curve is not secp256k1" )
67
78
}
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
69
86
if err != nil {
70
87
return nil , err
71
88
}
72
89
// Convert to Ethereum signature format with 'recovery id' v at the end.
73
90
v := sig [0 ] - 27
74
91
copy (sig , sig [1 :])
75
- sig [64 ] = v
92
+ sig [RecoveryIDOffset ] = v
76
93
return sig , nil
77
94
}
78
95
@@ -83,13 +100,20 @@ func VerifySignature(pubkey, hash, signature []byte) bool {
83
100
if len (signature ) != 64 {
84
101
return false
85
102
}
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 )
88
112
if err != nil {
89
113
return false
90
114
}
91
115
// Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
92
- if sig . S . Cmp ( secp256k1_halfN ) > 0 {
116
+ if s . IsOverHalfOrder () {
93
117
return false
94
118
}
95
119
return sig .Verify (hash , key )
@@ -100,16 +124,26 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
100
124
if len (pubkey ) != 33 {
101
125
return nil , errors .New ("invalid compressed public key length" )
102
126
}
103
- key , err := btcec .ParsePubKey (pubkey , btcec . S256 () )
127
+ key , err := btcec .ParsePubKey (pubkey )
104
128
if err != nil {
105
129
return nil , err
106
130
}
107
131
return key .ToECDSA (), nil
108
132
}
109
133
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.
111
140
func 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 ()
113
147
}
114
148
115
149
// S256 returns an instance of the secp256k1 curve.
0 commit comments