From 2fecddc41f52cc544eaf5c9b9fa3e4062c054d38 Mon Sep 17 00:00:00 2001 From: tony Date: Thu, 7 Nov 2024 18:14:27 +0800 Subject: [PATCH] bump btcsuite/btcd/btcec/v2 and sync crypto@v1.14.11 with upstream --- crypto/blake2b/blake2b_f_fuzz_test.go | 75 +++++++ crypto/bn256/cloudflare/gfp_decl.go | 2 +- crypto/bn256/google/bn256.go | 4 +- crypto/crypto.go | 135 +++++++++--- crypto/crypto_test.go | 93 ++++++-- crypto/ecies/ecies.go | 201 +++++++----------- crypto/ecies/ecies_test.go | 183 ++++++---------- crypto/ecies/params.go | 34 ++- crypto/secp256k1/curve.go | 89 ++++---- .../secp256k1/libsecp256k1/contrib/dummy.go | 1 + crypto/secp256k1/libsecp256k1/dummy.go | 1 + .../secp256k1/libsecp256k1/include/dummy.go | 1 + .../libsecp256k1/include/secp256k1.h | 2 +- .../libsecp256k1/sage/group_prover.sage | 2 +- crypto/secp256k1/libsecp256k1/src/dummy.go | 1 + .../libsecp256k1/src/modules/dummy.go | 1 + .../libsecp256k1/src/modules/ecdh/dummy.go | 1 + .../src/modules/recovery/dummy.go | 1 + crypto/secp256k1/scalar_mult_cgo.go | 10 +- crypto/secp256k1/scalar_mult_nocgo.go | 2 +- crypto/secp256k1/secp256.go | 5 +- crypto/secp256k1/secp256_test.go | 5 +- crypto/signature_cgo.go | 29 ++- crypto/signature_nocgo.go | 130 ++++++++--- crypto/signature_test.go | 2 +- go.mod | 5 +- go.sum | 11 +- 27 files changed, 625 insertions(+), 401 deletions(-) create mode 100644 crypto/blake2b/blake2b_f_fuzz_test.go diff --git a/crypto/blake2b/blake2b_f_fuzz_test.go b/crypto/blake2b/blake2b_f_fuzz_test.go new file mode 100644 index 000000000000..1de9a62de9d7 --- /dev/null +++ b/crypto/blake2b/blake2b_f_fuzz_test.go @@ -0,0 +1,75 @@ +// Only enable fuzzer on platforms with AVX enabled +//go:build go1.7 && amd64 && !gccgo && !appengine +// +build go1.7,amd64,!gccgo,!appengine + +package blake2b + +import ( + "encoding/binary" + "testing" +) + +func Fuzz(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzz(data) + }) +} + +func fuzz(data []byte) { + // Make sure the data confirms to the input model + if len(data) != 211 { + return + } + // Parse everything and call all the implementations + var ( + rounds = binary.BigEndian.Uint16(data[0:2]) + + h [8]uint64 + m [16]uint64 + t [2]uint64 + f uint64 + ) + + for i := 0; i < 8; i++ { + offset := 2 + i*8 + h[i] = binary.LittleEndian.Uint64(data[offset : offset+8]) + } + for i := 0; i < 16; i++ { + offset := 66 + i*8 + m[i] = binary.LittleEndian.Uint64(data[offset : offset+8]) + } + t[0] = binary.LittleEndian.Uint64(data[194:202]) + t[1] = binary.LittleEndian.Uint64(data[202:210]) + + if data[210]%2 == 1 { // Avoid spinning the fuzzer to hit 0/1 + f = 0xFFFFFFFFFFFFFFFF + } + + // Run the blake2b compression on all instruction sets and cross reference + want := h + fGeneric(&want, &m, t[0], t[1], f, uint64(rounds)) + + have := h + if useSSE4 { + fSSE4(&have, &m, t[0], t[1], f, uint64(rounds)) + if have != want { + panic("SSE4 mismatches generic algo") + } + } + + if useAVX { + have = h + fAVX(&have, &m, t[0], t[1], f, uint64(rounds)) + if have != want { + panic("AVX mismatches generic algo") + } + } + + if useAVX2 { + have = h + fAVX2(&have, &m, t[0], t[1], f, uint64(rounds)) + if have != want { + panic("AVX2 mismatches generic algo") + } + } +} diff --git a/crypto/bn256/cloudflare/gfp_decl.go b/crypto/bn256/cloudflare/gfp_decl.go index cf7f5654239f..1954d14a4a5a 100644 --- a/crypto/bn256/cloudflare/gfp_decl.go +++ b/crypto/bn256/cloudflare/gfp_decl.go @@ -13,7 +13,7 @@ import ( //nolint:varcheck,unused,deadcode var hasBMI2 = cpu.X86.HasBMI2 -// go:noescape +//go:noescape func gfpNeg(c, a *gfP) //go:noescape diff --git a/crypto/bn256/google/bn256.go b/crypto/bn256/google/bn256.go index 0a9d5cd35dce..aca9cf62de1b 100644 --- a/crypto/bn256/google/bn256.go +++ b/crypto/bn256/google/bn256.go @@ -29,7 +29,7 @@ import ( ) // BUG(agl): this implementation is not constant time. -// TODO(agl): keep GF(p²) elements in Mongomery form. +// TODO(agl): keep GF(p²) elements in Montgomery form. // G1 is an abstract cyclic group. The zero value is suitable for use as the // output of an operation, but cannot be used as an input. @@ -166,7 +166,7 @@ type G2 struct { p *twistPoint } -// RandomG1 returns x and g₂ˣ where x is a random, non-zero number read from r. +// RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r. func RandomG2(r io.Reader) (*big.Int, *G2, error) { var k *big.Int var err error diff --git a/crypto/crypto.go b/crypto/crypto.go index 3211957e0ab9..aaa5cc43a2d0 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -17,53 +17,95 @@ package crypto import ( + "bufio" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "encoding/hex" "errors" "fmt" + "hash" "io" - "io/ioutil" "math/big" "os" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/crypto/sha3" ) +// SignatureLength indicates the byte length required to carry a signature with recovery id. +const SignatureLength = 64 + 1 // 64 bytes ECDSA signature + 1 byte recovery id + +// RecoveryIDOffset points to the byte offset within the signature that contains the recovery id. +const RecoveryIDOffset = 64 + +// DigestLength sets the signature digest exact length +const DigestLength = 32 + var ( - secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) + secp256k1N = S256().Params().N secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) ) var errInvalidPubkey = errors.New("invalid secp256k1 public key") +// EllipticCurve contains curve operations. +type EllipticCurve interface { + elliptic.Curve + + // Point marshaling/unmarshaing. + Marshal(x, y *big.Int) []byte + Unmarshal(data []byte) (x, y *big.Int) +} + +// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports +// Read to get a variable amount of data from the hash state. Read is faster than Sum +// because it doesn't copy the internal state, but also modifies the internal state. +type KeccakState interface { + hash.Hash + Read([]byte) (int, error) +} + +// NewKeccakState creates a new KeccakState +func NewKeccakState() KeccakState { + return sha3.NewLegacyKeccak256().(KeccakState) +} + +// HashData hashes the provided data using the KeccakState and returns a 32 byte hash +func HashData(kh KeccakState, data []byte) (h common.Hash) { + kh.Reset() + kh.Write(data) + kh.Read(h[:]) + return h +} + // Keccak256 calculates and returns the Keccak256 hash of the input data. func Keccak256(data ...[]byte) []byte { - d := sha3.NewKeccak256() + b := make([]byte, 32) + d := NewKeccakState() for _, b := range data { d.Write(b) } - return d.Sum(nil) + d.Read(b) + return b } // Keccak256Hash calculates and returns the Keccak256 hash of the input data, // converting it to an internal Hash data structure. func Keccak256Hash(data ...[]byte) (h common.Hash) { - d := sha3.NewKeccak256() + d := NewKeccakState() for _, b := range data { d.Write(b) } - d.Sum(h[:0]) + d.Read(h[:]) return h } // Keccak512 calculates and returns the Keccak512 hash of the input data. func Keccak512(data ...[]byte) []byte { - d := sha3.NewKeccak512() + d := sha3.NewLegacyKeccak512() for _, b := range data { d.Write(b) } @@ -77,9 +119,9 @@ func CreateAddress(b common.Address, nonce uint64) common.Address { } // CreateAddress2 creates an ethereum address given the address bytes, initial -// contract code and a salt. -func CreateAddress2(b common.Address, salt [32]byte, code []byte) common.Address { - return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], Keccak256(code))[12:]) +// contract code hash and a salt. +func CreateAddress2(b common.Address, salt [32]byte, inithash []byte) common.Address { + return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:]) } // ToECDSA creates a private key with the given D value. @@ -108,14 +150,14 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) { // The priv.D must < N if priv.D.Cmp(secp256k1N) >= 0 { - return nil, fmt.Errorf("invalid private key, >=N") + return nil, errors.New("invalid private key, >=N") } // The priv.D must not be zero or negative. if priv.D.Sign() <= 0 { - return nil, fmt.Errorf("invalid private key, zero or negative") + return nil, errors.New("invalid private key, zero or negative") } - priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d) + priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(d) if priv.PublicKey.X == nil { return nil, errors.New("invalid private key") } @@ -132,7 +174,7 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte { // UnmarshalPubkey converts bytes to a secp256k1 public key. func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) { - x, y := elliptic.Unmarshal(S256(), pub) + x, y := S256().Unmarshal(pub) if x == nil { return nil, errInvalidPubkey } @@ -143,44 +185,83 @@ func FromECDSAPub(pub *ecdsa.PublicKey) []byte { if pub == nil || pub.X == nil || pub.Y == nil { return nil } - return elliptic.Marshal(S256(), pub.X, pub.Y) + return S256().Marshal(pub.X, pub.Y) } // HexToECDSA parses a secp256k1 private key. func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) { b, err := hex.DecodeString(hexkey) - if err != nil { - return nil, errors.New("invalid hex string") + if byteErr, ok := err.(hex.InvalidByteError); ok { + return nil, fmt.Errorf("invalid hex character %q in private key", byte(byteErr)) + } else if err != nil { + return nil, errors.New("invalid hex data for private key") } return ToECDSA(b) } // LoadECDSA loads a secp256k1 private key from the given file. func LoadECDSA(file string) (*ecdsa.PrivateKey, error) { - buf := make([]byte, 64) fd, err := os.Open(file) if err != nil { return nil, err } defer fd.Close() - if _, err := io.ReadFull(fd, buf); err != nil { - return nil, err - } - key, err := hex.DecodeString(string(buf)) + r := bufio.NewReader(fd) + buf := make([]byte, 64) + n, err := readASCII(buf, r) if err != nil { return nil, err + } else if n != len(buf) { + return nil, errors.New("key file too short, want 64 hex characters") + } + if err := checkKeyFileEnd(r); err != nil { + return nil, err + } + + return HexToECDSA(string(buf)) +} + +// readASCII reads into 'buf', stopping when the buffer is full or +// when a non-printable control character is encountered. +func readASCII(buf []byte, r *bufio.Reader) (n int, err error) { + for ; n < len(buf); n++ { + buf[n], err = r.ReadByte() + switch { + case err == io.EOF || buf[n] < '!': + return n, nil + case err != nil: + return n, err + } + } + return n, nil +} + +// checkKeyFileEnd skips over additional newlines at the end of a key file. +func checkKeyFileEnd(r *bufio.Reader) error { + for i := 0; ; i++ { + b, err := r.ReadByte() + switch { + case err == io.EOF: + return nil + case err != nil: + return err + case b != '\n' && b != '\r': + return fmt.Errorf("invalid character %q at end of key file", b) + case i >= 2: + return errors.New("key file too long, want 64 hex characters") + } } - return ToECDSA(key) } // SaveECDSA saves a secp256k1 private key to the given file with // restrictive permissions. The key data is saved hex-encoded. func SaveECDSA(file string, key *ecdsa.PrivateKey) error { k := hex.EncodeToString(FromECDSA(key)) - return ioutil.WriteFile(file, []byte(k), 0600) + return os.WriteFile(file, []byte(k), 0600) } +// GenerateKey generates a new private key. func GenerateKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(S256(), rand.Reader) } @@ -206,7 +287,5 @@ func PubkeyToAddress(p ecdsa.PublicKey) common.Address { } func zeroBytes(bytes []byte) { - for i := range bytes { - bytes[i] = 0 - } + clear(bytes) } diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 177c19c0cfca..da123cf980a8 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -20,7 +20,6 @@ import ( "bytes" "crypto/ecdsa" "encoding/hex" - "io/ioutil" "math/big" "os" "reflect" @@ -42,6 +41,13 @@ func TestKeccak256Hash(t *testing.T) { checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp) } +func TestKeccak256Hasher(t *testing.T) { + msg := []byte("abc") + exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") + hasher := NewKeccakState() + checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := HashData(hasher, in); return h[:] }, msg, exp) +} + func TestToECDSAErrors(t *testing.T) { if _, err := HexToECDSA("0000000000000000000000000000000000000000000000000000000000000000"); err == nil { t.Fatal("HexToECDSA should've returned error") @@ -139,39 +145,82 @@ func TestNewContractAddress(t *testing.T) { checkAddr(t, common.HexToAddress("c9ddedf451bc62ce88bf9292afb13df35b670699"), caddr2) } -func TestLoadECDSAFile(t *testing.T) { - keyBytes := common.FromHex(testPrivHex) - fileName0 := "test_key0" - fileName1 := "test_key1" - checkKey := func(k *ecdsa.PrivateKey) { - checkAddr(t, PubkeyToAddress(k.PublicKey), common.HexToAddress(testAddrHex)) - loadedKeyBytes := FromECDSA(k) - if !bytes.Equal(loadedKeyBytes, keyBytes) { - t.Fatalf("private key mismatch: want: %x have: %x", keyBytes, loadedKeyBytes) - } +func TestLoadECDSA(t *testing.T) { + tests := []struct { + input string + err string + }{ + // good + {input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, + {input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"}, + {input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\r"}, + {input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"}, + {input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\n"}, + {input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\r"}, + // bad + { + input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde", + err: "key file too short, want 64 hex characters", + }, + { + input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\n", + err: "key file too short, want 64 hex characters", + }, + { + input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdeX", + err: "invalid hex character 'X' in private key", + }, + { + input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefX", + err: "invalid character 'X' at end of key file", + }, + { + input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\n\n", + err: "key file too long, want 64 hex characters", + }, } - ioutil.WriteFile(fileName0, []byte(testPrivHex), 0600) - defer os.Remove(fileName0) + for _, test := range tests { + f, err := os.CreateTemp("", "loadecdsa_test.*.txt") + if err != nil { + t.Fatal(err) + } + filename := f.Name() + f.WriteString(test.input) + f.Close() + + _, err = LoadECDSA(filename) + switch { + case err != nil && test.err == "": + t.Fatalf("unexpected error for input %q:\n %v", test.input, err) + case err != nil && err.Error() != test.err: + t.Fatalf("wrong error for input %q:\n %v", test.input, err) + case err == nil && test.err != "": + t.Fatalf("LoadECDSA did not return error for input %q", test.input) + } + } +} - key0, err := LoadECDSA(fileName0) +func TestSaveECDSA(t *testing.T) { + f, err := os.CreateTemp("", "saveecdsa_test.*.txt") if err != nil { t.Fatal(err) } - checkKey(key0) + file := f.Name() + f.Close() + defer os.Remove(file) - // again, this time with SaveECDSA instead of manual save: - err = SaveECDSA(fileName1, key0) - if err != nil { + key, _ := HexToECDSA(testPrivHex) + if err := SaveECDSA(file, key); err != nil { t.Fatal(err) } - defer os.Remove(fileName1) - - key1, err := LoadECDSA(fileName1) + loaded, err := LoadECDSA(file) if err != nil { t.Fatal(err) } - checkKey(key1) + if !reflect.DeepEqual(key, loaded) { + t.Fatal("loaded key not equal to saved key") + } } func TestValidateSignatureValues(t *testing.T) { diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 1474181482b6..1b6c9e97c121 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -35,19 +35,21 @@ import ( "crypto/elliptic" "crypto/hmac" "crypto/subtle" - "fmt" + "encoding/binary" + "errors" "hash" "io" "math/big" + + "github.com/ethereum/go-ethereum/crypto" ) var ( - ErrImport = fmt.Errorf("ecies: failed to import key") - ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve") - ErrInvalidParams = fmt.Errorf("ecies: invalid ECIES parameters") - ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key") - ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity") - ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big") + ErrImport = errors.New("ecies: failed to import key") + ErrInvalidCurve = errors.New("ecies: invalid elliptic curve") + ErrInvalidPublicKey = errors.New("ecies: invalid public key") + ErrSharedKeyIsPointAtInfinity = errors.New("ecies: shared key is point at infinity") + ErrSharedKeyTooBig = errors.New("ecies: shared key params are too big") ) // PublicKey is a representation of an elliptic curve public key. @@ -95,15 +97,15 @@ func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { // Generate an elliptic curve public / private keypair. If params is nil, // the recommended default parameters for the key will be chosen. func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { - pb, x, y, err := elliptic.GenerateKey(curve, rand) + sk, err := ecdsa.GenerateKey(curve, rand) if err != nil { return } prv = new(PrivateKey) - prv.PublicKey.X = x - prv.PublicKey.Y = y + prv.PublicKey.X = sk.X + prv.PublicKey.Y = sk.Y prv.PublicKey.Curve = curve - prv.D = new(big.Int).SetBytes(pb) + prv.D = new(big.Int).Set(sk.D) if params == nil { params = ParamsFromCurve(curve) } @@ -138,57 +140,39 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b } var ( - ErrKeyDataTooLong = fmt.Errorf("ecies: can't supply requested key data") - ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long") - ErrInvalidMessage = fmt.Errorf("ecies: invalid message") + ErrSharedTooLong = errors.New("ecies: shared secret is too long") + ErrInvalidMessage = errors.New("ecies: invalid message") ) -var ( - big2To32 = new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil) - big2To32M1 = new(big.Int).Sub(big2To32, big.NewInt(1)) -) - -func incCounter(ctr []byte) { - if ctr[3]++; ctr[3] != 0 { - return - } - if ctr[2]++; ctr[2] != 0 { - return - } - if ctr[1]++; ctr[1] != 0 { - return - } - if ctr[0]++; ctr[0] != 0 { - return - } -} - // NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1). -func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) (k []byte, err error) { - if s1 == nil { - s1 = make([]byte, 0) - } - - reps := ((kdLen + 7) * 8) / (hash.BlockSize() * 8) - if big.NewInt(int64(reps)).Cmp(big2To32M1) > 0 { - fmt.Println(big2To32M1) - return nil, ErrKeyDataTooLong - } - - counter := []byte{0, 0, 0, 1} - k = make([]byte, 0) - - for i := 0; i <= reps; i++ { - hash.Write(counter) +func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) []byte { + counterBytes := make([]byte, 4) + k := make([]byte, 0, roundup(kdLen, hash.Size())) + for counter := uint32(1); len(k) < kdLen; counter++ { + binary.BigEndian.PutUint32(counterBytes, counter) + hash.Reset() + hash.Write(counterBytes) hash.Write(z) hash.Write(s1) - k = append(k, hash.Sum(nil)...) - hash.Reset() - incCounter(counter) + k = hash.Sum(k) } + return k[:kdLen] +} - k = k[:kdLen] - return +// roundup rounds size up to the next multiple of blocksize. +func roundup(size, blocksize int) int { + return size + blocksize - (size % blocksize) +} + +// deriveKeys creates the encryption and MAC keys using concatKDF. +func deriveKeys(hash hash.Hash, z, s1 []byte, keyLen int) (Ke, Km []byte) { + K := concatKDF(hash, z, s1, 2*keyLen) + Ke = K[:keyLen] + Km = K[keyLen:] + hash.Reset() + hash.Write(Km) + Km = hash.Sum(Km[:0]) + return Ke, Km } // messageTag computes the MAC of a message (called the tag) as per @@ -209,7 +193,6 @@ func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) { } // symEncrypt carries out CTR encryption using the block cipher specified in the -// parameters. func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) { c, err := params.Cipher(key) if err != nil { @@ -249,46 +232,40 @@ func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) { // ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the // shared information parameters aren't being used, they should be nil. func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) { - params := pub.Params - if params == nil { - if params = ParamsFromCurve(pub.Curve); params == nil { - err = ErrUnsupportedECIESParameters - return - } + params, err := pubkeyParams(pub) + if err != nil { + return nil, err } + R, err := GenerateKey(rand, pub.Curve, params) if err != nil { - return + return nil, err } - hash := params.Hash() z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen) if err != nil { - return - } - K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen) - if err != nil { - return + return nil, err } - Ke := K[:params.KeyLen] - Km := K[params.KeyLen:] - hash.Write(Km) - Km = hash.Sum(nil) - hash.Reset() + + hash := params.Hash() + Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) em, err := symEncrypt(rand, params, Ke, m) if err != nil || len(em) <= params.BlockSize { - return + return nil, err } d := messageTag(params.Hash, Km, em, s2) - Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y) - ct = make([]byte, len(Rb)+len(em)+len(d)) - copy(ct, Rb) - copy(ct[len(Rb):], em) - copy(ct[len(Rb)+len(em):], d) - return + if curve, ok := pub.Curve.(crypto.EllipticCurve); ok { + Rb := curve.Marshal(R.PublicKey.X, R.PublicKey.Y) + ct = make([]byte, len(Rb)+len(em)+len(d)) + copy(ct, Rb) + copy(ct[len(Rb):], em) + copy(ct[len(Rb)+len(em):], d) + return ct, nil + } + return nil, ErrInvalidCurve } // Decrypt decrypts an ECIES ciphertext. @@ -296,13 +273,11 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { if len(c) == 0 { return nil, ErrInvalidMessage } - params := prv.PublicKey.Params - if params == nil { - if params = ParamsFromCurve(prv.PublicKey.Curve); params == nil { - err = ErrUnsupportedECIESParameters - return - } + params, err := pubkeyParams(&prv.PublicKey) + if err != nil { + return nil, err } + hash := params.Hash() var ( @@ -316,12 +291,10 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { case 2, 3, 4: rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4 if len(c) < (rLen + hLen + 1) { - err = ErrInvalidMessage - return + return nil, ErrInvalidMessage } default: - err = ErrInvalidPublicKey - return + return nil, ErrInvalidPublicKey } mStart = rLen @@ -329,38 +302,24 @@ func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) { R := new(PublicKey) R.Curve = prv.PublicKey.Curve - R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen]) - if R.X == nil { - err = ErrInvalidPublicKey - return - } - if !R.Curve.IsOnCurve(R.X, R.Y) { - err = ErrInvalidCurve - return - } - z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) - if err != nil { - return - } - - K, err := concatKDF(hash, z, s1, params.KeyLen+params.KeyLen) - if err != nil { - return - } + if curve, ok := R.Curve.(crypto.EllipticCurve); ok { + R.X, R.Y = curve.Unmarshal(c[:rLen]) + if R.X == nil { + return nil, ErrInvalidPublicKey + } - Ke := K[:params.KeyLen] - Km := K[params.KeyLen:] - hash.Write(Km) - Km = hash.Sum(nil) - hash.Reset() + z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen) + if err != nil { + return nil, err + } + Ke, Km := deriveKeys(hash, z, s1, params.KeyLen) - d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) - if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { - err = ErrInvalidMessage - return + d := messageTag(params.Hash, Km, c[mStart:mEnd], s2) + if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 { + return nil, ErrInvalidMessage + } + return symDecrypt(params, Ke, c[mStart:mEnd]) } - - m, err = symDecrypt(params, Ke, c[mStart:mEnd]) - return + return nil, ErrInvalidCurve } diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 400339aa53a8..e3da71010edd 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -35,30 +35,34 @@ import ( "crypto/rand" "crypto/sha256" "encoding/hex" - "fmt" + "errors" "math/big" "testing" "github.com/ethereum/go-ethereum/crypto" ) -// Ensure the KDF generates appropriately sized keys. func TestKDF(t *testing.T) { - msg := []byte("Hello, world") - h := sha256.New() - - k, err := concatKDF(h, msg, nil, 64) - if err != nil { - fmt.Println(err.Error()) - t.FailNow() - } - if len(k) != 64 { - fmt.Printf("KDF: generated key is the wrong size (%d instead of 64\n", len(k)) - t.FailNow() + tests := []struct { + length int + output []byte + }{ + {6, decode("858b192fa2ed")}, + {32, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0")}, + {48, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955")}, + {64, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955f3467fd6672cce1024c5b1effccc0f61")}, + } + + for _, test := range tests { + h := sha256.New() + k := concatKDF(h, []byte("input"), nil, test.length) + if !bytes.Equal(k, test.output) { + t.Fatalf("KDF: generated key %x does not match expected output %x", k, test.output) + } } } -var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match") +var ErrBadSharedKeys = errors.New("ecies: shared keys don't match") // cmpParams compares a set of ECIES parameters. We assume, as per the // docs, that AES is the only supported symmetric encryption algorithm. @@ -68,65 +72,31 @@ func cmpParams(p1, p2 *ECIESParams) bool { p1.BlockSize == p2.BlockSize } -// cmpPublic returns true if the two public keys represent the same pojnt. -func cmpPublic(pub1, pub2 PublicKey) bool { - if pub1.X == nil || pub1.Y == nil { - fmt.Println(ErrInvalidPublicKey.Error()) - return false - } - if pub2.X == nil || pub2.Y == nil { - fmt.Println(ErrInvalidPublicKey.Error()) - return false - } - pub1Out := elliptic.Marshal(pub1.Curve, pub1.X, pub1.Y) - pub2Out := elliptic.Marshal(pub2.Curve, pub2.X, pub2.Y) - - return bytes.Equal(pub1Out, pub2Out) -} - -// cmpPrivate returns true if the two private keys are the same. -func cmpPrivate(prv1, prv2 *PrivateKey) bool { - if prv1 == nil || prv1.D == nil { - return false - } else if prv2 == nil || prv2.D == nil { - return false - } else if prv1.D.Cmp(prv2.D) != 0 { - return false - } else { - return cmpPublic(prv1.PublicKey, prv2.PublicKey) - } -} - // Validate the ECDH component. func TestSharedKey(t *testing.T) { prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2 prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } if !bytes.Equal(sk1, sk2) { - fmt.Println(ErrBadSharedKeys.Error()) - t.FailNow() + t.Fatal(ErrBadSharedKeys) } } @@ -155,7 +125,7 @@ func TestSharedKeyPadding(t *testing.T) { // test shared secret generation sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16) if err != nil { - fmt.Println(err.Error()) + t.Log(err.Error()) } sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16) @@ -173,26 +143,22 @@ func TestSharedKeyPadding(t *testing.T) { func TestTooBigSharedKey(t *testing.T) { prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } _, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32) if err != ErrSharedKeyTooBig { - fmt.Println("ecdh: shared key should be too large for curve") - t.FailNow() + t.Fatal("ecdh: shared key should be too large for curve") } _, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32) if err != ErrSharedKeyTooBig { - fmt.Println("ecdh: shared key should be too large for curve") - t.FailNow() + t.Fatal("ecdh: shared key should be too large for curve") } } @@ -200,8 +166,7 @@ func TestTooBigSharedKey(t *testing.T) { func BenchmarkGenerateKeyP256(b *testing.B) { for i := 0; i < b.N; i++ { if _, err := GenerateKey(rand.Reader, elliptic.P256(), nil); err != nil { - fmt.Println(err.Error()) - b.FailNow() + b.Fatal(err) } } } @@ -210,15 +175,13 @@ func BenchmarkGenerateKeyP256(b *testing.B) { func BenchmarkGenSharedKeyP256(b *testing.B) { prv, err := GenerateKey(rand.Reader, elliptic.P256(), nil) if err != nil { - fmt.Println(err.Error()) - b.FailNow() + b.Fatal(err) } b.ResetTimer() for i := 0; i < b.N; i++ { _, err := prv.GenerateShared(&prv.PublicKey, 16, 16) if err != nil { - fmt.Println(err.Error()) - b.FailNow() + b.Fatal(err) } } } @@ -227,15 +190,13 @@ func BenchmarkGenSharedKeyP256(b *testing.B) { func BenchmarkGenSharedKeyS256(b *testing.B) { prv, err := GenerateKey(rand.Reader, crypto.S256(), nil) if err != nil { - fmt.Println(err.Error()) - b.FailNow() + b.Fatal(err) } b.ResetTimer() for i := 0; i < b.N; i++ { _, err := prv.GenerateShared(&prv.PublicKey, 16, 16) if err != nil { - fmt.Println(err.Error()) - b.FailNow() + b.Fatal(err) } } } @@ -244,38 +205,32 @@ func BenchmarkGenSharedKeyS256(b *testing.B) { func TestEncryptDecrypt(t *testing.T) { prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } message := []byte("Hello, world.") ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } if !bytes.Equal(pt, message) { - fmt.Println("ecies: plaintext doesn't match message") - t.FailNow() + t.Fatal("ecies: plaintext doesn't match message") } _, err = prv1.Decrypt(ct, nil, nil) if err == nil { - fmt.Println("ecies: encryption should not have succeeded") - t.FailNow() + t.Fatal("ecies: encryption should not have succeeded") } } @@ -324,7 +279,7 @@ var testCases = []testCase{ { Curve: elliptic.P384(), Name: "P384", - Expected: ECIES_AES256_SHA384, + Expected: ECIES_AES192_SHA384, }, { Curve: elliptic.P521(), @@ -344,53 +299,41 @@ func TestParamSelection(t *testing.T) { func testParamSelection(t *testing.T, c testCase) { params := ParamsFromCurve(c.Curve) - if params == nil && c.Expected != nil { - fmt.Printf("%s (%s)\n", ErrInvalidParams.Error(), c.Name) - t.FailNow() + if params == nil { + t.Fatal("ParamsFromCurve returned nil") } else if params != nil && !cmpParams(params, c.Expected) { - fmt.Printf("ecies: parameters should be invalid (%s)\n", - c.Name) - t.FailNow() + t.Fatalf("ecies: parameters should be invalid (%s)\n", c.Name) } prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Printf("%s (%s)\n", err.Error(), c.Name) - t.FailNow() + t.Fatalf("%s (%s)\n", err.Error(), c.Name) } prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Printf("%s (%s)\n", err.Error(), c.Name) - t.FailNow() + t.Fatalf("%s (%s)\n", err.Error(), c.Name) } message := []byte("Hello, world.") ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil) if err != nil { - fmt.Printf("%s (%s)\n", err.Error(), c.Name) - t.FailNow() + t.Fatalf("%s (%s)\n", err.Error(), c.Name) } pt, err := prv2.Decrypt(ct, nil, nil) if err != nil { - fmt.Printf("%s (%s)\n", err.Error(), c.Name) - t.FailNow() + t.Fatalf("%s (%s)\n", err.Error(), c.Name) } if !bytes.Equal(pt, message) { - fmt.Printf("ecies: plaintext doesn't match message (%s)\n", - c.Name) - t.FailNow() + t.Fatalf("ecies: plaintext doesn't match message (%s)\n", c.Name) } _, err = prv1.Decrypt(ct, nil, nil) if err == nil { - fmt.Printf("ecies: encryption should not have succeeded (%s)\n", - c.Name) - t.FailNow() + t.Fatalf("ecies: encryption should not have succeeded (%s)\n", c.Name) } - } // Ensure that the basic public key validation in the decryption operation @@ -400,23 +343,20 @@ func TestBasicKeyValidation(t *testing.T) { prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } message := []byte("Hello, world.") ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } for _, b := range badBytes { ct[0] = b _, err := prv.Decrypt(ct, nil, nil) if err != ErrInvalidPublicKey { - fmt.Println("ecies: validated an invalid key") - t.FailNow() + t.Fatal("ecies: validated an invalid key") } } } @@ -454,22 +394,19 @@ func TestSharedKeyStatic(t *testing.T) { sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatal(err) } if !bytes.Equal(sk1, sk2) { - fmt.Println(ErrBadSharedKeys.Error()) - t.FailNow() + t.Fatal(ErrBadSharedKeys) } - sk, _ := hex.DecodeString("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62") + sk := decode("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62") if !bytes.Equal(sk1, sk) { t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1) } @@ -482,3 +419,11 @@ func hexKey(prv string) *PrivateKey { } return ImportECDSA(key) } + +func decode(s string) []byte { + bytes, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return bytes +} diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go index 6312daf5a1c1..df7698ea0cbe 100644 --- a/crypto/ecies/params.go +++ b/crypto/ecies/params.go @@ -39,6 +39,7 @@ import ( "crypto/elliptic" "crypto/sha256" "crypto/sha512" + "errors" "fmt" "hash" @@ -47,10 +48,16 @@ import ( var ( DefaultCurve = ethcrypto.S256() - ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm") - ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters") + ErrUnsupportedECDHAlgorithm = errors.New("ecies: unsupported ECDH algorithm") + ErrUnsupportedECIESParameters = errors.New("ecies: unsupported ECIES parameters") + ErrInvalidKeyLen = fmt.Errorf("ecies: invalid key size (> %d) in ECIESParams", maxKeyLen) ) +// KeyLen is limited to prevent overflow of the counter +// in concatKDF. While the theoretical limit is much higher, +// no known cipher uses keys larger than 512 bytes. +const maxKeyLen = 512 + type ECIESParams struct { Hash func() hash.Hash // hash function hashAlgo crypto.Hash @@ -74,6 +81,14 @@ var ( KeyLen: 16, } + ECIES_AES192_SHA384 = &ECIESParams{ + Hash: sha512.New384, + hashAlgo: crypto.SHA384, + Cipher: aes.NewCipher, + BlockSize: aes.BlockSize, + KeyLen: 24, + } + ECIES_AES256_SHA256 = &ECIESParams{ Hash: sha256.New, hashAlgo: crypto.SHA256, @@ -102,7 +117,7 @@ var ( var paramsFromCurve = map[elliptic.Curve]*ECIESParams{ ethcrypto.S256(): ECIES_AES128_SHA256, elliptic.P256(): ECIES_AES128_SHA256, - elliptic.P384(): ECIES_AES256_SHA384, + elliptic.P384(): ECIES_AES192_SHA384, elliptic.P521(): ECIES_AES256_SHA512, } @@ -115,3 +130,16 @@ func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) { func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) { return paramsFromCurve[curve] } + +func pubkeyParams(key *PublicKey) (*ECIESParams, error) { + params := key.Params + if params == nil { + if params = ParamsFromCurve(key.Curve); params == nil { + return nil, ErrUnsupportedECIESParameters + } + } + if params.KeyLen > maxKeyLen { + return nil, ErrInvalidKeyLen + } + return params, nil +} diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index fa1b199a3484..85ba885d6f5f 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -79,53 +79,52 @@ type BitCurve struct { BitSize int // the size of the underlying field } -func (BitCurve *BitCurve) Params() *elliptic.CurveParams { +func (bitCurve *BitCurve) Params() *elliptic.CurveParams { return &elliptic.CurveParams{ - P: BitCurve.P, - N: BitCurve.N, - B: BitCurve.B, - Gx: BitCurve.Gx, - Gy: BitCurve.Gy, - BitSize: BitCurve.BitSize, + P: bitCurve.P, + N: bitCurve.N, + B: bitCurve.B, + Gx: bitCurve.Gx, + Gy: bitCurve.Gy, + BitSize: bitCurve.BitSize, } } // IsOnCurve returns true if the given (x,y) lies on the BitCurve. -func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { +func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { // y² = x³ + b y2 := new(big.Int).Mul(y, y) //y² - y2.Mod(y2, BitCurve.P) //y²%P + y2.Mod(y2, bitCurve.P) //y²%P x3 := new(big.Int).Mul(x, x) //x² x3.Mul(x3, x) //x³ - x3.Add(x3, BitCurve.B) //x³+B - x3.Mod(x3, BitCurve.P) //(x³+B)%P + x3.Add(x3, bitCurve.B) //x³+B + x3.Mod(x3, bitCurve.P) //(x³+B)%P return x3.Cmp(y2) == 0 } -//TODO: double check if the function is okay // affineFromJacobian reverses the Jacobian transform. See the comment at the // top of the file. -func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { +func (bitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { if z.Sign() == 0 { return new(big.Int), new(big.Int) } - zinv := new(big.Int).ModInverse(z, BitCurve.P) + zinv := new(big.Int).ModInverse(z, bitCurve.P) zinvsq := new(big.Int).Mul(zinv, zinv) xOut = new(big.Int).Mul(x, zinvsq) - xOut.Mod(xOut, BitCurve.P) + xOut.Mod(xOut, bitCurve.P) zinvsq.Mul(zinvsq, zinv) yOut = new(big.Int).Mul(y, zinvsq) - yOut.Mod(yOut, BitCurve.P) + yOut.Mod(yOut, bitCurve.P) return } // Add returns the sum of (x1,y1) and (x2,y2) -func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { // If one point is at infinity, return the other point. // Adding the point at infinity to any point will preserve the other point. if x1.Sign() == 0 && y1.Sign() == 0 { @@ -136,27 +135,27 @@ func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { } z := new(big.Int).SetInt64(1) if x1.Cmp(x2) == 0 && y1.Cmp(y2) == 0 { - return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z)) + return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z)) } - return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z)) + return bitCurve.affineFromJacobian(bitCurve.addJacobian(x1, y1, z, x2, y2, z)) } // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and // (x2, y2, z2) and returns their sum, also in Jacobian form. -func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { +func (bitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl z1z1 := new(big.Int).Mul(z1, z1) - z1z1.Mod(z1z1, BitCurve.P) + z1z1.Mod(z1z1, bitCurve.P) z2z2 := new(big.Int).Mul(z2, z2) - z2z2.Mod(z2z2, BitCurve.P) + z2z2.Mod(z2z2, bitCurve.P) u1 := new(big.Int).Mul(x1, z2z2) - u1.Mod(u1, BitCurve.P) + u1.Mod(u1, bitCurve.P) u2 := new(big.Int).Mul(x2, z1z1) - u2.Mod(u2, BitCurve.P) + u2.Mod(u2, bitCurve.P) h := new(big.Int).Sub(u2, u1) if h.Sign() == -1 { - h.Add(h, BitCurve.P) + h.Add(h, bitCurve.P) } i := new(big.Int).Lsh(h, 1) i.Mul(i, i) @@ -164,13 +163,13 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int s1 := new(big.Int).Mul(y1, z2) s1.Mul(s1, z2z2) - s1.Mod(s1, BitCurve.P) + s1.Mod(s1, bitCurve.P) s2 := new(big.Int).Mul(y2, z1) s2.Mul(s2, z1z1) - s2.Mod(s2, BitCurve.P) + s2.Mod(s2, bitCurve.P) r := new(big.Int).Sub(s2, s1) if r.Sign() == -1 { - r.Add(r, BitCurve.P) + r.Add(r, bitCurve.P) } r.Lsh(r, 1) v := new(big.Int).Mul(u1, i) @@ -180,7 +179,7 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int x3.Sub(x3, j) x3.Sub(x3, v) x3.Sub(x3, v) - x3.Mod(x3, BitCurve.P) + x3.Mod(x3, bitCurve.P) y3 := new(big.Int).Set(r) v.Sub(v, x3) @@ -188,33 +187,33 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int s1.Mul(s1, j) s1.Lsh(s1, 1) y3.Sub(y3, s1) - y3.Mod(y3, BitCurve.P) + y3.Mod(y3, bitCurve.P) z3 := new(big.Int).Add(z1, z2) z3.Mul(z3, z3) z3.Sub(z3, z1z1) if z3.Sign() == -1 { - z3.Add(z3, BitCurve.P) + z3.Add(z3, bitCurve.P) } z3.Sub(z3, z2z2) if z3.Sign() == -1 { - z3.Add(z3, BitCurve.P) + z3.Add(z3, bitCurve.P) } z3.Mul(z3, h) - z3.Mod(z3, BitCurve.P) + z3.Mod(z3, bitCurve.P) return x3, y3, z3 } // Double returns 2*(x,y) -func (BitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { z1 := new(big.Int).SetInt64(1) - return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z1)) + return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z1)) } // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and // returns its double, also in Jacobian form. -func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { +func (bitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l a := new(big.Int).Mul(x, x) //X1² @@ -232,30 +231,30 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D x3.Sub(f, x3) //F-2*D - x3.Mod(x3, BitCurve.P) + x3.Mod(x3, bitCurve.P) y3 := new(big.Int).Sub(d, x3) //D-X3 y3.Mul(e, y3) //E*(D-X3) y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C - y3.Mod(y3, BitCurve.P) + y3.Mod(y3, bitCurve.P) z3 := new(big.Int).Mul(y, z) //Y1*Z1 z3.Mul(big.NewInt(2), z3) //3*Y1*Z1 - z3.Mod(z3, BitCurve.P) + z3.Mod(z3, bitCurve.P) return x3, y3, z3 } // ScalarBaseMult returns k*G, where G is the base point of the group and k is // an integer in big-endian form. -func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { - return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k) +func (bitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + return bitCurve.ScalarMult(bitCurve.Gx, bitCurve.Gy, k) } // Marshal converts a point into the form specified in section 4.3.6 of ANSI // X9.62. -func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { - byteLen := (BitCurve.BitSize + 7) >> 3 +func (bitCurve *BitCurve) Marshal(x, y *big.Int) []byte { + byteLen := (bitCurve.BitSize + 7) >> 3 ret := make([]byte, 1+2*byteLen) ret[0] = 4 // uncompressed point flag readBits(x, ret[1:1+byteLen]) @@ -265,8 +264,8 @@ func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { // Unmarshal converts a point, serialised by Marshal, into an x, y pair. On // error, x = nil. -func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { - byteLen := (BitCurve.BitSize + 7) >> 3 +func (bitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { + byteLen := (bitCurve.BitSize + 7) >> 3 if len(data) != 1+2*byteLen { return } diff --git a/crypto/secp256k1/libsecp256k1/contrib/dummy.go b/crypto/secp256k1/libsecp256k1/contrib/dummy.go index fda594be9914..2c946210c54d 100644 --- a/crypto/secp256k1/libsecp256k1/contrib/dummy.go +++ b/crypto/secp256k1/libsecp256k1/contrib/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/dummy.go b/crypto/secp256k1/libsecp256k1/dummy.go index 379b16992f47..04bbe3d76ecc 100644 --- a/crypto/secp256k1/libsecp256k1/dummy.go +++ b/crypto/secp256k1/libsecp256k1/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/include/dummy.go b/crypto/secp256k1/libsecp256k1/include/dummy.go index 5af540c73c4a..64c71b8451d8 100644 --- a/crypto/secp256k1/libsecp256k1/include/dummy.go +++ b/crypto/secp256k1/libsecp256k1/include/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1.h b/crypto/secp256k1/libsecp256k1/include/secp256k1.h index f268e309d0bf..76af8396918e 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1.h @@ -357,7 +357,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( /** Verify an ECDSA signature. * * Returns: 1: correct signature - * 0: incorrect or unparseable signature + * 0: incorrect or unparsable signature * Args: ctx: a secp256k1 context object, initialized for verification. * In: sig: the signature being verified (cannot be NULL) * msg32: the 32-byte message hash being verified (cannot be NULL) diff --git a/crypto/secp256k1/libsecp256k1/sage/group_prover.sage b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage index ab580c5b23bb..68882e93659a 100644 --- a/crypto/secp256k1/libsecp256k1/sage/group_prover.sage +++ b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage @@ -17,7 +17,7 @@ # - A constraint describing the requirements of the law, called "require" # * Implementations are transliterated into functions that operate as well on # algebraic input points, and are called once per combination of branches -# exectured. Each execution returns: +# executed. Each execution returns: # - A constraint describing the assumptions this implementation requires # (such as Z1=1), called "assumeFormula" # - A constraint describing the assumptions this specific branch requires, diff --git a/crypto/secp256k1/libsecp256k1/src/dummy.go b/crypto/secp256k1/libsecp256k1/src/dummy.go index 65868f38a8ea..2df270adc35e 100644 --- a/crypto/secp256k1/libsecp256k1/src/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go index 3c7a696439f0..99c538db51b0 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go index b6fc38327ec8..48c2e0aa5453 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go index b9491f0cb9f4..8efbd7abe71b 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go index 8afa9d023b07..d11c11faf85b 100644 --- a/crypto/secp256k1/scalar_mult_cgo.go +++ b/crypto/secp256k1/scalar_mult_cgo.go @@ -21,7 +21,7 @@ extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned */ import "C" -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { // Ensure scalar is exactly 32 bytes. We pad always, even if // scalar is 32 bytes long, to avoid a timing side channel. if len(scalar) > 32 { @@ -44,12 +44,8 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, // Unpack the result and clear temporaries. x := new(big.Int).SetBytes(point[:32]) y := new(big.Int).SetBytes(point[32:]) - for i := range point { - point[i] = 0 - } - for i := range padded { - scalar[i] = 0 - } + clear(point) + clear(scalar) if res != 1 { return nil, nil } diff --git a/crypto/secp256k1/scalar_mult_nocgo.go b/crypto/secp256k1/scalar_mult_nocgo.go index 22f53ac6ae65..feb13a8dfd0e 100644 --- a/crypto/secp256k1/scalar_mult_nocgo.go +++ b/crypto/secp256k1/scalar_mult_nocgo.go @@ -9,6 +9,6 @@ package secp256k1 import "math/big" -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { panic("ScalarMult is not available when secp256k1 is built without cgo") } diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index c9c01b3209af..61abc1eaf04b 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -21,11 +21,14 @@ package secp256k1 # define USE_SCALAR_8X32 #endif +#ifndef NDEBUG +# define NDEBUG +#endif + #define USE_ENDOMORPHISM #define USE_NUM_NONE #define USE_FIELD_INV_BUILTIN #define USE_SCALAR_INV_BUILTIN -#define NDEBUG #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" #include "ext.h" diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index 74408d06d2bf..4827cc5b255c 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -10,7 +10,6 @@ package secp256k1 import ( "bytes" "crypto/ecdsa" - "crypto/elliptic" "crypto/rand" "encoding/hex" "io" @@ -24,7 +23,7 @@ func generateKeyPair() (pubkey, privkey []byte) { if err != nil { panic(err) } - pubkey = elliptic.Marshal(S256(), key.X, key.Y) + pubkey = S256().Marshal(key.X, key.Y) privkey = make([]byte, 32) blob := key.D.Bytes() @@ -49,7 +48,7 @@ func randSig() []byte { } // tests for malleability -// highest bit of signature ECDSA s value must be 0, in the 33th byte +// the highest bit of signature ECDSA s value must be 0, in the 33th byte func compactSigCheck(t *testing.T, sig []byte) { var b = int(sig[32]) if b < 0 { diff --git a/crypto/signature_cgo.go b/crypto/signature_cgo.go index 340bfc221eae..87289253c0ff 100644 --- a/crypto/signature_cgo.go +++ b/crypto/signature_cgo.go @@ -14,13 +14,14 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build !nacl,!js,!nocgo +//go:build !nacl && !js && cgo && !gofuzz +// +build !nacl,!js,cgo,!gofuzz package crypto import ( "crypto/ecdsa" - "crypto/elliptic" + "errors" "fmt" "github.com/ethereum/go-ethereum/common/math" @@ -38,40 +39,38 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { if err != nil { return nil, err } - - x, y := elliptic.Unmarshal(S256(), s) - return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil + return UnmarshalPubkey(s) } // Sign calculates an ECDSA signature. // // This function is susceptible to chosen plaintext attacks that can leak // information about the private key that is used for signing. Callers must -// be aware that the given hash cannot be chosen by an adversery. Common +// be aware that the given digest cannot be chosen by an adversary. Common // solution is to hash any input before calculating the signature. // // The produced signature is in the [R || S || V] format where V is 0 or 1. -func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { - if len(hash) != 32 { - return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash)) +func Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { + if len(digestHash) != DigestLength { + return nil, fmt.Errorf("hash is required to be exactly %d bytes (%d)", DigestLength, len(digestHash)) } seckey := math.PaddedBigBytes(prv.D, prv.Params().BitSize/8) defer zeroBytes(seckey) - return secp256k1.Sign(hash, seckey) + return secp256k1.Sign(digestHash, seckey) } -// VerifySignature checks that the given public key created signature over hash. +// VerifySignature checks that the given public key created signature over digest. // The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format. // The signature should have the 64 byte [R || S] format. -func VerifySignature(pubkey, hash, signature []byte) bool { - return secp256k1.VerifySignature(pubkey, hash, signature) +func VerifySignature(pubkey, digestHash, signature []byte) bool { + return secp256k1.VerifySignature(pubkey, digestHash, signature) } // DecompressPubkey parses a public key in the 33-byte compressed format. func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { x, y := secp256k1.DecompressPubkey(pubkey) if x == nil { - return nil, fmt.Errorf("invalid public key") + return nil, errors.New("invalid public key") } return &ecdsa.PublicKey{X: x, Y: y, Curve: S256()}, nil } @@ -82,6 +81,6 @@ func CompressPubkey(pubkey *ecdsa.PublicKey) []byte { } // S256 returns an instance of the secp256k1 curve. -func S256() elliptic.Curve { +func S256() EllipticCurve { return secp256k1.S256() } diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index e8fa18ed475d..5ac3765c7106 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -14,46 +14,64 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// +build nacl js nocgo +//go:build nacl || js || !cgo || gofuzz +// +build nacl js !cgo gofuzz package crypto import ( "crypto/ecdsa" - "crypto/elliptic" "errors" "fmt" "math/big" - "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcd/btcec/v2" + btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa" ) // Ecrecover returns the uncompressed public key that created the given signature. func Ecrecover(hash, sig []byte) ([]byte, error) { - pub, err := SigToPub(hash, sig) + pub, err := sigToPub(hash, sig) if err != nil { return nil, err } - bytes := (*btcec.PublicKey)(pub).SerializeUncompressed() + bytes := pub.SerializeUncompressed() return bytes, err } -// SigToPub returns the public key that created the given signature. -func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { +func sigToPub(hash, sig []byte) (*btcec.PublicKey, error) { + if len(sig) != SignatureLength { + return nil, errors.New("invalid signature") + } // Convert to btcec input format with 'recovery id' v at the beginning. - btcsig := make([]byte, 65) - btcsig[0] = sig[64] + 27 + btcsig := make([]byte, SignatureLength) + btcsig[0] = sig[RecoveryIDOffset] + 27 copy(btcsig[1:], sig) - pub, _, err := btcec.RecoverCompact(btcec.S256(), btcsig, hash) - return (*ecdsa.PublicKey)(pub), err + pub, _, err := btc_ecdsa.RecoverCompact(btcsig, hash) + return pub, err +} + +// SigToPub returns the public key that created the given signature. +func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { + pub, err := sigToPub(hash, sig) + if err != nil { + return nil, err + } + // We need to explicitly set the curve here, because we're wrapping + // the original curve to add (un-)marshalling + return &ecdsa.PublicKey{ + Curve: S256(), + X: pub.X(), + Y: pub.Y(), + }, nil } // Sign calculates an ECDSA signature. // // This function is susceptible to chosen plaintext attacks that can leak // information about the private key that is used for signing. Callers must -// be aware that the given hash cannot be chosen by an adversery. Common +// be aware that the given hash cannot be chosen by an adversary. Common // solution is to hash any input before calculating the signature. // // The produced signature is in the [R || S || V] format where V is 0 or 1. @@ -61,17 +79,20 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { if len(hash) != 32 { return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash)) } - if prv.Curve != btcec.S256() { - return nil, fmt.Errorf("private key curve is not secp256k1") + if prv.Curve != S256() { + return nil, errors.New("private key curve is not secp256k1") } - sig, err := btcec.SignCompact(btcec.S256(), (*btcec.PrivateKey)(prv), hash, false) - if err != nil { - return nil, err + // ecdsa.PrivateKey -> btcec.PrivateKey + var priv btcec.PrivateKey + if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() { + return nil, errors.New("invalid private key") } + defer priv.Zero() + sig := btc_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[64] = v + sig[RecoveryIDOffset] = v return sig, nil } @@ -82,13 +103,20 @@ func VerifySignature(pubkey, hash, signature []byte) bool { if len(signature) != 64 { return false } - sig := &btcec.Signature{R: new(big.Int).SetBytes(signature[:32]), S: new(big.Int).SetBytes(signature[32:])} - key, err := btcec.ParsePubKey(pubkey, btcec.S256()) + var r, s btcec.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) if err != nil { return false } // Reject malleable signatures. libsecp256k1 does this check but btcec doesn't. - if sig.S.Cmp(secp256k1halfN) > 0 { + if s.IsOverHalfOrder() { return false } return sig.Verify(hash, key) @@ -99,19 +127,67 @@ 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, btcec.S256()) + key, err := btcec.ParsePubKey(pubkey) if err != nil { return nil, err } - return key.ToECDSA(), nil + // We need to explicitly set the curve here, because we're wrapping + // the original curve to add (un-)marshalling + return &ecdsa.PublicKey{ + Curve: S256(), + X: key.X(), + Y: key.Y(), + }, nil } -// CompressPubkey encodes a public key to the 33-byte compressed format. +// CompressPubkey encodes a public key to the 33-byte compressed format. The +// provided PublicKey must be valid. Namely, the coordinates must not be larger +// than 32 bytes each, they must be less than the field prime, and it must be a +// point on the secp256k1 curve. This is the case for a PublicKey constructed by +// elliptic.Unmarshal (see UnmarshalPubkey), or by ToECDSA and ecdsa.GenerateKey +// when constructing a PrivateKey. func CompressPubkey(pubkey *ecdsa.PublicKey) []byte { - return (*btcec.PublicKey)(pubkey).SerializeCompressed() + // NOTE: the coordinates may be validated with + // btcec.ParsePubKey(FromECDSAPub(pubkey)) + var x, y btcec.FieldVal + x.SetByteSlice(pubkey.X.Bytes()) + y.SetByteSlice(pubkey.Y.Bytes()) + return btcec.NewPublicKey(&x, &y).SerializeCompressed() } // S256 returns an instance of the secp256k1 curve. -func S256() elliptic.Curve { - return btcec.S256() +func S256() EllipticCurve { + return btCurve{btcec.S256()} +} + +type btCurve struct { + *btcec.KoblitzCurve +} + +// Marshal converts a point given as (x, y) into a byte slice. +func (curve btCurve) Marshal(x, y *big.Int) []byte { + byteLen := (curve.Params().BitSize + 7) / 8 + + ret := make([]byte, 1+2*byteLen) + ret[0] = 4 // uncompressed point + + x.FillBytes(ret[1 : 1+byteLen]) + y.FillBytes(ret[1+byteLen : 1+2*byteLen]) + + return ret +} + +// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On +// error, x = nil. +func (curve btCurve) Unmarshal(data []byte) (x, y *big.Int) { + byteLen := (curve.Params().BitSize + 7) / 8 + if len(data) != 1+2*byteLen { + return nil, nil + } + if data[0] != 4 { // uncompressed form + return nil, nil + } + x = new(big.Int).SetBytes(data[1 : 1+byteLen]) + y = new(big.Int).SetBytes(data[1+byteLen:]) + return } diff --git a/crypto/signature_test.go b/crypto/signature_test.go index aecff76bfbda..74d683b50758 100644 --- a/crypto/signature_test.go +++ b/crypto/signature_test.go @@ -71,7 +71,7 @@ func TestVerifySignature(t *testing.T) { wrongkey := common.CopyBytes(testpubkey) wrongkey[10]++ if VerifySignature(wrongkey, testmsg, sig) { - t.Errorf("signature valid with with wrong public key") + t.Errorf("signature valid with wrong public key") } } diff --git a/go.mod b/go.mod index 34e8d933291c..b5f05bc7de9b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 require ( github.com/Azure/azure-storage-blob-go v0.0.0-20180712005634-eaae161d9d5e github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 - github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 + github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/cespare/cp v0.1.0 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea @@ -33,7 +33,7 @@ require ( github.com/rjeczalik/notify v0.9.1-0.20180808203925-4e54e7fd043e github.com/robertkrimen/otto v0.1.0 github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.8.0 github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3 golang.org/x/crypto v0.22.0 golang.org/x/net v0.24.0 @@ -50,6 +50,7 @@ require ( require ( github.com/Azure/azure-pipeline-go v0.0.0-20180607212504-7571e8eb0876 // indirect github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect diff --git a/go.sum b/go.sum index d9cd2f0cb76d..807a4244efab 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4 github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +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/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -17,6 +19,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/docker/docker v17.12.0-ce-rc1.0.20180625184442-8e610b2b55bf+incompatible h1:XLx1EvrRmI+cbbsUzVZV63UNGj7J75jjnG6b0Kl7mno= github.com/docker/docker v17.12.0-ce-rc1.0.20180625184442-8e610b2b55bf+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM= @@ -123,9 +129,12 @@ github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9Ac github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 h1:3hxavr+IHMsQBrYUPQM5v0CgENFktkkbg1sfpgM3h20= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3 h1:sAlSBRDl4psFR3ysKXRSE8ss6Mt90+ma1zRTroTNBJA= github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=