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=