crypto: use decred secp256k1 directly (#30595)
Use `github.com/decred/dcrd/dcrec/secp256k1/v4` directly rather than `github.com/btcsuite/btcd/btcec/v2` which is just a wrapper around the underlying decred library. Inspired by https://github.com/cosmos/cosmos-sdk/pull/15018 `github.com/btcsuite/btcd/btcec/v2` has a very annoying breaking change when upgrading from `v2.3.3` to `v2.3.4`. The easiest way to workaround this is to just remove the wrapper. Would be very nice if you could backport this to the release branches. References: - https://github.com/btcsuite/btcd/issues/2221 - https://github.com/cometbft/cometbft/pull/4294 - https://github.com/cometbft/cometbft/pull/3728 - https://github.com/zeta-chain/node/pull/2934
This commit is contained in:
parent
4b9c7821b9
commit
30ce17386b
|
@ -25,8 +25,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
decred_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ecrecover returns the uncompressed public key that created the given signature.
|
// Ecrecover returns the uncompressed public key that created the given signature.
|
||||||
|
@ -39,16 +39,16 @@ func Ecrecover(hash, sig []byte) ([]byte, error) {
|
||||||
return bytes, err
|
return bytes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func sigToPub(hash, sig []byte) (*btcec.PublicKey, error) {
|
func sigToPub(hash, sig []byte) (*secp256k1.PublicKey, error) {
|
||||||
if len(sig) != SignatureLength {
|
if len(sig) != SignatureLength {
|
||||||
return nil, errors.New("invalid signature")
|
return nil, errors.New("invalid signature")
|
||||||
}
|
}
|
||||||
// Convert to btcec input format with 'recovery id' v at the beginning.
|
// Convert to secp256k1 input format with 'recovery id' v at the beginning.
|
||||||
btcsig := make([]byte, SignatureLength)
|
btcsig := make([]byte, SignatureLength)
|
||||||
btcsig[0] = sig[RecoveryIDOffset] + 27
|
btcsig[0] = sig[RecoveryIDOffset] + 27
|
||||||
copy(btcsig[1:], sig)
|
copy(btcsig[1:], sig)
|
||||||
|
|
||||||
pub, _, err := btc_ecdsa.RecoverCompact(btcsig, hash)
|
pub, _, err := decred_ecdsa.RecoverCompact(btcsig, hash)
|
||||||
return pub, err
|
return pub, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,13 +82,13 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
|
||||||
if prv.Curve != S256() {
|
if prv.Curve != S256() {
|
||||||
return nil, errors.New("private key curve is not secp256k1")
|
return nil, errors.New("private key curve is not secp256k1")
|
||||||
}
|
}
|
||||||
// ecdsa.PrivateKey -> btcec.PrivateKey
|
// ecdsa.PrivateKey -> secp256k1.PrivateKey
|
||||||
var priv btcec.PrivateKey
|
var priv secp256k1.PrivateKey
|
||||||
if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() {
|
if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() {
|
||||||
return nil, errors.New("invalid private key")
|
return nil, errors.New("invalid private key")
|
||||||
}
|
}
|
||||||
defer priv.Zero()
|
defer priv.Zero()
|
||||||
sig := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey
|
sig := decred_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey
|
||||||
// Convert to Ethereum signature format with 'recovery id' v at the end.
|
// Convert to Ethereum signature format with 'recovery id' v at the end.
|
||||||
v := sig[0] - 27
|
v := sig[0] - 27
|
||||||
copy(sig, sig[1:])
|
copy(sig, sig[1:])
|
||||||
|
@ -103,19 +103,19 @@ func VerifySignature(pubkey, hash, signature []byte) bool {
|
||||||
if len(signature) != 64 {
|
if len(signature) != 64 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
var r, s btcec.ModNScalar
|
var r, s secp256k1.ModNScalar
|
||||||
if r.SetByteSlice(signature[:32]) {
|
if r.SetByteSlice(signature[:32]) {
|
||||||
return false // overflow
|
return false // overflow
|
||||||
}
|
}
|
||||||
if s.SetByteSlice(signature[32:]) {
|
if s.SetByteSlice(signature[32:]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
sig := btc_ecdsa.NewSignature(&r, &s)
|
sig := decred_ecdsa.NewSignature(&r, &s)
|
||||||
key, err := btcec.ParsePubKey(pubkey)
|
key, err := secp256k1.ParsePubKey(pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
|
// Reject malleable signatures. libsecp256k1 does this check but decred doesn't.
|
||||||
if s.IsOverHalfOrder() {
|
if s.IsOverHalfOrder() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
|
||||||
if len(pubkey) != 33 {
|
if len(pubkey) != 33 {
|
||||||
return nil, errors.New("invalid compressed public key length")
|
return nil, errors.New("invalid compressed public key length")
|
||||||
}
|
}
|
||||||
key, err := btcec.ParsePubKey(pubkey)
|
key, err := secp256k1.ParsePubKey(pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -148,20 +148,20 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
|
||||||
// when constructing a PrivateKey.
|
// when constructing a PrivateKey.
|
||||||
func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
|
func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
|
||||||
// NOTE: the coordinates may be validated with
|
// NOTE: the coordinates may be validated with
|
||||||
// btcec.ParsePubKey(FromECDSAPub(pubkey))
|
// secp256k1.ParsePubKey(FromECDSAPub(pubkey))
|
||||||
var x, y btcec.FieldVal
|
var x, y secp256k1.FieldVal
|
||||||
x.SetByteSlice(pubkey.X.Bytes())
|
x.SetByteSlice(pubkey.X.Bytes())
|
||||||
y.SetByteSlice(pubkey.Y.Bytes())
|
y.SetByteSlice(pubkey.Y.Bytes())
|
||||||
return btcec.NewPublicKey(&x, &y).SerializeCompressed()
|
return secp256k1.NewPublicKey(&x, &y).SerializeCompressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
// S256 returns an instance of the secp256k1 curve.
|
// S256 returns an instance of the secp256k1 curve.
|
||||||
func S256() EllipticCurve {
|
func S256() EllipticCurve {
|
||||||
return btCurve{btcec.S256()}
|
return btCurve{secp256k1.S256()}
|
||||||
}
|
}
|
||||||
|
|
||||||
type btCurve struct {
|
type btCurve struct {
|
||||||
*btcec.KoblitzCurve
|
*secp256k1.KoblitzCurve
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal converts a point given as (x, y) into a byte slice.
|
// Marshal converts a point given as (x, y) into a byte slice.
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -12,7 +12,6 @@ require (
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.18.45
|
github.com/aws/aws-sdk-go-v2/config v1.18.45
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.43
|
github.com/aws/aws-sdk-go-v2/credentials v1.13.43
|
||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4
|
|
||||||
github.com/cespare/cp v0.1.0
|
github.com/cespare/cp v0.1.0
|
||||||
github.com/cloudflare/cloudflare-go v0.79.0
|
github.com/cloudflare/cloudflare-go v0.79.0
|
||||||
github.com/cockroachdb/pebble v1.1.2
|
github.com/cockroachdb/pebble v1.1.2
|
||||||
|
@ -21,6 +20,7 @@ require (
|
||||||
github.com/crate-crypto/go-kzg-4844 v1.0.0
|
github.com/crate-crypto/go-kzg-4844 v1.0.0
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set/v2 v2.6.0
|
github.com/deckarep/golang-set/v2 v2.6.0
|
||||||
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
|
||||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
||||||
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
||||||
github.com/ethereum/c-kzg-4844 v1.0.0
|
github.com/ethereum/c-kzg-4844 v1.0.0
|
||||||
|
@ -102,7 +102,6 @@ require (
|
||||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||||
github.com/consensys/bavard v0.1.13 // indirect
|
github.com/consensys/bavard v0.1.13 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
|
||||||
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
||||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
github.com/dlclark/regexp2 v1.7.0 // indirect
|
||||||
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
|
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -92,10 +92,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
|
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
dcred_secp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ func Fuzz(f *testing.F) {
|
||||||
func fuzz(dataP1, dataP2 []byte) {
|
func fuzz(dataP1, dataP2 []byte) {
|
||||||
var (
|
var (
|
||||||
curveA = secp256k1.S256()
|
curveA = secp256k1.S256()
|
||||||
curveB = btcec.S256()
|
curveB = dcred_secp256k1.S256()
|
||||||
)
|
)
|
||||||
// first point
|
// first point
|
||||||
x1, y1 := curveB.ScalarBaseMult(dataP1)
|
x1, y1 := curveB.ScalarBaseMult(dataP1)
|
||||||
|
|
Loading…
Reference in New Issue