From a3c1e547fe917b148a25c6cc00ee0521f1bea84d Mon Sep 17 00:00:00 2001 From: ucwong Date: Wed, 16 Oct 2024 02:30:51 +0800 Subject: [PATCH] use decred secp256k1 directly --- crypto/signature_nocgo.go | 39 ++- go.mod | 2 +- go.sum | 3 - tests/fuzzers/secp256k1/secp_fuzzer.go | 50 ---- tests/fuzzers/secp256k1/secp_test.go | 35 ++- .../btcsuite/btcd/btcec/v2/ecdsa/error.go | 18 -- .../btcsuite/btcd/btcec/v2/ecdsa/signature.go | 256 ------------------ vendor/modules.txt | 1 - 8 files changed, 52 insertions(+), 352 deletions(-) delete mode 100644 tests/fuzzers/secp256k1/secp_fuzzer.go delete mode 100644 vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/error.go delete mode 100644 vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 663d207b10..4c7146e3f2 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -25,8 +25,8 @@ import ( "fmt" "math/big" - "github.com/btcsuite/btcd/btcec/v2" - btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + decred_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" ) // 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 } -func sigToPub(hash, sig []byte) (*btcec.PublicKey, error) { +func sigToPub(hash, sig []byte) (*secp256k1.PublicKey, error) { if len(sig) != SignatureLength { 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[0] = sig[RecoveryIDOffset] + 27 copy(btcsig[1:], sig) - pub, _, err := btc_ecdsa.RecoverCompact(btcsig, hash) + pub, _, err := decred_ecdsa.RecoverCompact(btcsig, hash) return pub, err } @@ -82,15 +82,14 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { if prv.Curve != S256() { return nil, errors.New("private key curve is not secp256k1") } - // ecdsa.PrivateKey -> btcec.PrivateKey - var priv btcec.PrivateKey + // ecdsa.PrivateKey -> secp256k1.PrivateKey + var priv secp256k1.PrivateKey if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() { return nil, fmt.Errorf("invalid private key") } defer priv.Zero() - sig := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey - - // Convert to Cortex signature format with 'recovery id' v at the end. + sig := decred_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey + // Convert to Ethereum signature format with 'recovery id' v at the end. v := sig[0] - 27 copy(sig, sig[1:]) sig[RecoveryIDOffset] = v @@ -104,19 +103,19 @@ func VerifySignature(pubkey, hash, signature []byte) bool { if len(signature) != 64 { return false } - var r, s btcec.ModNScalar + var r, s secp256k1.ModNScalar if r.SetByteSlice(signature[:32]) { return false // overflow } if s.SetByteSlice(signature[32:]) { return false } - sig := btc_ecdsa.NewSignature(&r, &s) - key, err := btcec.ParsePubKey(pubkey) + sig := decred_ecdsa.NewSignature(&r, &s) + key, err := secp256k1.ParsePubKey(pubkey) if err != nil { 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() { return false } @@ -128,7 +127,7 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { if len(pubkey) != 33 { return nil, errors.New("invalid compressed public key length") } - key, err := btcec.ParsePubKey(pubkey) + key, err := secp256k1.ParsePubKey(pubkey) if err != nil { return nil, err } @@ -149,20 +148,20 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { // when constructing a PrivateKey. func CompressPubkey(pubkey *ecdsa.PublicKey) []byte { // NOTE: the coordinates may be validated with - // btcec.ParsePubKey(FromECDSAPub(pubkey)) - var x, y btcec.FieldVal + // secp256k1.ParsePubKey(FromECDSAPub(pubkey)) + var x, y secp256k1.FieldVal x.SetByteSlice(pubkey.X.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. func S256() EllipticCurve { - return btCurve{btcec.S256()} + return btCurve{secp256k1.S256()} } type btCurve struct { - *btcec.KoblitzCurve + *secp256k1.KoblitzCurve } // Marshall converts a point given as (x, y) into a byte slice. diff --git a/go.mod b/go.mod index 729ed86b51..9c0d683cad 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( github.com/crate-crypto/go-kzg-4844 v1.1.0 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/deckarep/golang-set/v2 v2.6.0 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3 github.com/ethereum/c-kzg-4844 v1.0.3 github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 @@ -138,7 +139,6 @@ require ( github.com/consensys/bavard v0.1.22 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgraph-io/badger/v4 v4.3.1 // indirect github.com/dgraph-io/ristretto v1.0.0 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect diff --git a/go.sum b/go.sum index 646d7a3069..7ef7c23c5d 100644 --- a/go.sum +++ b/go.sum @@ -315,11 +315,8 @@ github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2w github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.23.4 h1:IzV6qqkfwbItOS/sg/aDfPDsjPP8twrCOE2R93hxMlQ= 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.2-0.20220413172512-bf64c8bdbbbf h1:x2qACX+i7TMsmaE1YPYyRISOAPKnVlOW+E+vJJz2vSo= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2-0.20220413172512-bf64c8bdbbbf/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= diff --git a/tests/fuzzers/secp256k1/secp_fuzzer.go b/tests/fuzzers/secp256k1/secp_fuzzer.go deleted file mode 100644 index 77a7004838..0000000000 --- a/tests/fuzzers/secp256k1/secp_fuzzer.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2021 The go-ethereum Authors -// This file is part of The go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with The go-ethereum library. If not, see . - -// build +gofuzz - -package secp256k1 - -import ( - "fmt" - - "github.com/CortexFoundation/CortexTheseus/crypto/secp256k1" - "github.com/btcsuite/btcd/btcec/v2" - fuzz "github.com/google/gofuzz" -) - -func Fuzz(input []byte) int { - var ( - fuzzer = fuzz.NewFromGoFuzz(input) - curveA = secp256k1.S256() - curveB = btcec.S256() - dataP1 []byte - dataP2 []byte - ) - // first point - fuzzer.Fuzz(&dataP1) - x1, y1 := curveB.ScalarBaseMult(dataP1) - // second point - fuzzer.Fuzz(&dataP2) - x2, y2 := curveB.ScalarBaseMult(dataP2) - resAX, resAY := curveA.Add(x1, y1, x2, y2) - resBX, resBY := curveB.Add(x1, y1, x2, y2) - if resAX.Cmp(resBX) != 0 || resAY.Cmp(resBY) != 0 { - fmt.Printf("%s %s %s %s\n", x1, y1, x2, y2) - panic(fmt.Sprintf("Addition failed: geth: %s %s btcd: %s %s", resAX, resAY, resBX, resBY)) - } - return 0 -} diff --git a/tests/fuzzers/secp256k1/secp_test.go b/tests/fuzzers/secp256k1/secp_test.go index 76bae87086..5ff21c7a95 100644 --- a/tests/fuzzers/secp256k1/secp_test.go +++ b/tests/fuzzers/secp256k1/secp_test.go @@ -1,8 +1,37 @@ package secp256k1 -import "testing" +import ( + "fmt" + "testing" + + "github.com/CortexFoundation/CortexTheseus/crypto/secp256k1" + dcred_secp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4" +) func TestFuzzer(t *testing.T) { - test := "00000000N0000000/R00000000000000000U0000S0000000mkhP000000000000000U" - Fuzz([]byte(test)) + a, b := "00000000N0000000/R0000000000000000", "0U0000S0000000mkhP000000000000000U" + fuzz([]byte(a), []byte(b)) +} + +func Fuzz(f *testing.F) { + f.Fuzz(func(t *testing.T, a, b []byte) { + fuzz(a, b) + }) +} + +func fuzz(dataP1, dataP2 []byte) { + var ( + curveA = secp256k1.S256() + curveB = dcred_secp256k1.S256() + ) + // first point + x1, y1 := curveB.ScalarBaseMult(dataP1) + // second points + x2, y2 := curveB.ScalarBaseMult(dataP2) + resAX, resAY := curveA.Add(x1, y1, x2, y2) + resBX, resBY := curveB.Add(x1, y1, x2, y2) + if resAX.Cmp(resBX) != 0 || resAY.Cmp(resBY) != 0 { + fmt.Printf("%s %s %s %s\n", x1, y1, x2, y2) + panic(fmt.Sprintf("Addition failed: geth: %s %s btcd: %s %s", resAX, resAY, resBX, resBY)) + } } diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/error.go b/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/error.go deleted file mode 100644 index a30d63b636..0000000000 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/error.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2013-2021 The btcsuite developers -// Copyright (c) 2015-2021 The Decred developers - -package ecdsa - -import ( - secp_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" -) - -// ErrorKind identifies a kind of error. It has full support for -// errors.Is and errors.As, so the caller can directly check against -// an error kind when determining the reason for an error. -type ErrorKind = secp_ecdsa.ErrorKind - -// Error identifies an error related to an ECDSA signature. It has full -// support for errors.Is and errors.As, so the caller can ascertain the -// specific reason for the error by checking the underlying error. -type Error = secp_ecdsa.ErrorKind diff --git a/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go b/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go deleted file mode 100644 index a2574f8794..0000000000 --- a/vendor/github.com/btcsuite/btcd/btcec/v2/ecdsa/signature.go +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) 2013-2017 The btcsuite developers -// Copyright (c) 2015-2021 The Decred developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package ecdsa - -import ( - "errors" - "fmt" - "math/big" - - "github.com/btcsuite/btcd/btcec/v2" - secp_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" -) - -// Errors returned by canonicalPadding. -var ( - errNegativeValue = errors.New("value may be interpreted as negative") - errExcessivelyPaddedValue = errors.New("value is excessively padded") -) - -// Signature is a type representing an ecdsa signature. -type Signature = secp_ecdsa.Signature - -// NewSignature instantiates a new signature given some r and s values. -func NewSignature(r, s *btcec.ModNScalar) *Signature { - return secp_ecdsa.NewSignature(r, s) -} - -var ( - // Used in RFC6979 implementation when testing the nonce for correctness - one = big.NewInt(1) - - // oneInitializer is used to fill a byte slice with byte 0x01. It is provided - // here to avoid the need to create it multiple times. - oneInitializer = []byte{0x01} -) - -const ( - // MinSigLen is the minimum length of a DER encoded signature and is when both R - // and S are 1 byte each. - // 0x30 + <1-byte> + 0x02 + 0x01 + + 0x2 + 0x01 + - MinSigLen = 8 - - // MaxSigLen is the maximum length of a DER encoded signature and is - // when both R and S are 33 bytes each. It is 33 bytes because a - // 256-bit integer requires 32 bytes and an additional leading null byte - // might be required if the high bit is set in the value. - // - // 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes> - MaxSigLen = 72 -) - -// canonicalPadding checks whether a big-endian encoded integer could -// possibly be misinterpreted as a negative number (even though OpenSSL -// treats all numbers as unsigned), or if there is any unnecessary -// leading zero padding. -func canonicalPadding(b []byte) error { - switch { - case b[0]&0x80 == 0x80: - return errNegativeValue - case len(b) > 1 && b[0] == 0x00 && b[1]&0x80 != 0x80: - return errExcessivelyPaddedValue - default: - return nil - } -} - -func parseSig(sigStr []byte, der bool) (*Signature, error) { - // Originally this code used encoding/asn1 in order to parse the - // signature, but a number of problems were found with this approach. - // Despite the fact that signatures are stored as DER, the difference - // between go's idea of a bignum (and that they have sign) doesn't agree - // with the openssl one (where they do not). The above is true as of - // Go 1.1. In the end it was simpler to rewrite the code to explicitly - // understand the format which is this: - // 0x30 <0x02> 0x2 - // . - - // The signature must adhere to the minimum and maximum allowed length. - totalSigLen := len(sigStr) - if totalSigLen < MinSigLen { - return nil, errors.New("malformed signature: too short") - } - if der && totalSigLen > MaxSigLen { - return nil, errors.New("malformed signature: too long") - } - - // 0x30 - index := 0 - if sigStr[index] != 0x30 { - return nil, errors.New("malformed signature: no header magic") - } - index++ - // length of remaining message - siglen := sigStr[index] - index++ - - // siglen should be less than the entire message and greater than - // the minimal message size. - if int(siglen+2) > len(sigStr) || int(siglen+2) < MinSigLen { - return nil, errors.New("malformed signature: bad length") - } - // trim the slice we're working on so we only look at what matters. - sigStr = sigStr[:siglen+2] - - // 0x02 - if sigStr[index] != 0x02 { - return nil, - errors.New("malformed signature: no 1st int marker") - } - index++ - - // Length of signature R. - rLen := int(sigStr[index]) - // must be positive, must be able to fit in another 0x2, - // hence the -3. We assume that the length must be at least one byte. - index++ - if rLen <= 0 || rLen > len(sigStr)-index-3 { - return nil, errors.New("malformed signature: bogus R length") - } - - // Then R itself. - rBytes := sigStr[index : index+rLen] - if der { - switch err := canonicalPadding(rBytes); err { - case errNegativeValue: - return nil, errors.New("signature R is negative") - case errExcessivelyPaddedValue: - return nil, errors.New("signature R is excessively padded") - } - } - - // Strip leading zeroes from R. - for len(rBytes) > 0 && rBytes[0] == 0x00 { - rBytes = rBytes[1:] - } - - // R must be in the range [1, N-1]. Notice the check for the maximum number - // of bytes is required because SetByteSlice truncates as noted in its - // comment so it could otherwise fail to detect the overflow. - var r btcec.ModNScalar - if len(rBytes) > 32 { - str := "invalid signature: R is larger than 256 bits" - return nil, errors.New(str) - } - if overflow := r.SetByteSlice(rBytes); overflow { - str := "invalid signature: R >= group order" - return nil, errors.New(str) - } - if r.IsZero() { - str := "invalid signature: R is 0" - return nil, errors.New(str) - } - index += rLen - // 0x02. length already checked in previous if. - if sigStr[index] != 0x02 { - return nil, errors.New("malformed signature: no 2nd int marker") - } - index++ - - // Length of signature S. - sLen := int(sigStr[index]) - index++ - // S should be the rest of the string. - if sLen <= 0 || sLen > len(sigStr)-index { - return nil, errors.New("malformed signature: bogus S length") - } - - // Then S itself. - sBytes := sigStr[index : index+sLen] - if der { - switch err := canonicalPadding(sBytes); err { - case errNegativeValue: - return nil, errors.New("signature S is negative") - case errExcessivelyPaddedValue: - return nil, errors.New("signature S is excessively padded") - } - } - - // Strip leading zeroes from S. - for len(sBytes) > 0 && sBytes[0] == 0x00 { - sBytes = sBytes[1:] - } - - // S must be in the range [1, N-1]. Notice the check for the maximum number - // of bytes is required because SetByteSlice truncates as noted in its - // comment so it could otherwise fail to detect the overflow. - var s btcec.ModNScalar - if len(sBytes) > 32 { - str := "invalid signature: S is larger than 256 bits" - return nil, errors.New(str) - } - if overflow := s.SetByteSlice(sBytes); overflow { - str := "invalid signature: S >= group order" - return nil, errors.New(str) - } - if s.IsZero() { - str := "invalid signature: S is 0" - return nil, errors.New(str) - } - index += sLen - - // sanity check length parsing - if index != len(sigStr) { - return nil, fmt.Errorf("malformed signature: bad final length %v != %v", - index, len(sigStr)) - } - - return NewSignature(&r, &s), nil -} - -// ParseSignature parses a signature in BER format for the curve type `curve' -// into a Signature type, performing some basic sanity checks. If parsing -// according to the more strict DER format is needed, use ParseDERSignature. -func ParseSignature(sigStr []byte) (*Signature, error) { - return parseSig(sigStr, false) -} - -// ParseDERSignature parses a signature in DER format for the curve type -// `curve` into a Signature type. If parsing according to the less strict -// BER format is needed, use ParseSignature. -func ParseDERSignature(sigStr []byte) (*Signature, error) { - return parseSig(sigStr, true) -} - -// SignCompact produces a compact signature of the data in hash with the given -// private key on the given koblitz curve. The isCompressed parameter should -// be used to detail if the given signature should reference a compressed -// public key or not. If successful the bytes of the compact signature will be -// returned in the format: -// <(byte of 27+public key solution)+4 if compressed >< padded bytes for signature R> -// where the R and S parameters are padde up to the bitlengh of the curve. -func SignCompact(key *btcec.PrivateKey, hash []byte, - isCompressedKey bool) []byte { - - return secp_ecdsa.SignCompact(key, hash, isCompressedKey) -} - -// RecoverCompact verifies the compact signature "signature" of "hash" for the -// Koblitz curve in "curve". If the signature matches then the recovered public -// key will be returned as well as a boolean if the original key was compressed -// or not, else an error will be returned. -func RecoverCompact(signature, hash []byte) (*btcec.PublicKey, bool, error) { - return secp_ecdsa.RecoverCompact(signature, hash) -} - -// Sign generates an ECDSA signature over the secp256k1 curve for the provided -// hash (which should be the result of hashing a larger message) using the -// given private key. The produced signature is deterministic (same message and -// same key yield the same signature) and canonical in accordance with RFC6979 -// and BIP0062. -func Sign(key *btcec.PrivateKey, hash []byte) *Signature { - return secp_ecdsa.Sign(key, hash) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index b0f9d03c21..335b749b49 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -335,7 +335,6 @@ github.com/bradfitz/iter # github.com/btcsuite/btcd/btcec/v2 v2.3.4 ## explicit; go 1.17 github.com/btcsuite/btcd/btcec/v2 -github.com/btcsuite/btcd/btcec/v2/ecdsa # github.com/bwmarrin/snowflake v0.3.0 ## explicit github.com/bwmarrin/snowflake