Skip to content

Commit

Permalink
add eip191 signmode support
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed Dec 19, 2023
1 parent 4b6143e commit 80a3ce7
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 1 deletion.
2 changes: 2 additions & 0 deletions client/tx/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ func Sign(ctx context.Context, txf Factory, name string, txBuilder client.TxBuil
if err != nil {
return err
}
} else if signMode == signing.SignMode_SIGN_MODE_EIP_191 {
return fmt.Errorf("EIP191 signing is not supported in cli")
}

k, err := txf.keybase.Key(name)
Expand Down
13 changes: 13 additions & 0 deletions crypto/keys/secp256k1/secp256k1_cgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package secp256k1

import (
"github.com/cometbft/cometbft/crypto"
"golang.org/x/crypto/sha3"

"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1/internal/secp256k1"
)
Expand All @@ -25,3 +26,15 @@ func (privKey *PrivKey) Sign(msg []byte) ([]byte, error) {
func (pubKey *PubKey) VerifySignature(msg, sigStr []byte) bool {
return secp256k1.VerifySignature(pubKey.Bytes(), crypto.Sha256(msg), sigStr)
}

// VerifySignatureEIP191 validates the signature.
// The msg will be hashed prior to signature verification.
func (pubKey *PubKey) VerifySignatureEIP191(msg []byte, sigStr []byte) bool {
return secp256k1.VerifySignature(pubKey.Bytes(), keccak256(msg), sigStr)
}

func keccak256(bytes []byte) []byte {
hasher := sha3.NewLegacyKeccak256()
hasher.Write(bytes)
return hasher.Sum(nil)
}
26 changes: 26 additions & 0 deletions crypto/keys/secp256k1/secp256k1_nocgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package secp256k1
import (
"errors"

"golang.org/x/crypto/sha3"

"github.com/cometbft/cometbft/crypto"
secp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
Expand Down Expand Up @@ -39,6 +41,24 @@ func (pubKey *PubKey) VerifySignature(msg, sigStr []byte) bool {
return signature.Verify(crypto.Sha256(msg), pub)
}

// VerifySignatureEIP191 verifies a signature of the form R || S.
// It rejects signatures which are not in lower-S form.
func (pubKey *PubKey) VerifySignatureEIP191(msg []byte, sigStr []byte) bool {
if len(sigStr) != 64 {
return false
}
pub, err := secp256k1.ParsePubKey(pubKey.Key)
if err != nil {
return false
}
// parse the signature, will return error if it is not in lower-S form
signature, err := signatureFromBytes(sigStr)
if err != nil {
return false
}
return signature.Verify(keccak256(msg), pub)
}

// Read Signature struct from R || S. Caller needs to ensure
// that len(sigStr) == 64.
// Rejects malleable signatures (if S value if it is over half order).
Expand All @@ -53,3 +73,9 @@ func signatureFromBytes(sigStr []byte) (*ecdsa.Signature, error) {

return ecdsa.NewSignature(&r, &s), nil
}

func keccak256(bytes []byte) []byte {
hasher := sha3.NewLegacyKeccak256()
hasher.Write(bytes)
return hasher.Sum(nil)
}
15 changes: 14 additions & 1 deletion x/auth/signing/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package signing

import (
"context"
"encoding/hex"
"fmt"

signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
txsigning "cosmossdk.io/x/tx/signing"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
Expand Down Expand Up @@ -77,9 +79,20 @@ func VerifySignature(
if err != nil {
return err
}
if !pubKey.VerifySignature(signBytes, data.Signature) {

if data.SignMode == signing.SignMode_SIGN_MODE_EIP_191 {
secp256k1PubKey, ok := pubKey.(*secp256k1.PubKey)
if !ok {
return fmt.Errorf("eip191 sign mode requires pubkey to be of type cosmos.crypto.secp256k1.PubKey")
}

if !secp256k1PubKey.VerifySignatureEIP191(signBytes, data.Signature) {
return fmt.Errorf("unable to verify single signer eip191 signature %s for signBytes %s", hex.EncodeToString(data.Signature), hex.EncodeToString(signBytes))
}
} else if !pubKey.VerifySignature(signBytes, data.Signature) {
return fmt.Errorf("unable to verify single signer signature")
}

return nil

case *signing.MultiSignatureData:
Expand Down
6 changes: 6 additions & 0 deletions x/auth/tx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ var DefaultSignModes = []signingtypes.SignMode{
signingtypes.SignMode_SIGN_MODE_DIRECT,
signingtypes.SignMode_SIGN_MODE_DIRECT_AUX,
signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
signingtypes.SignMode_SIGN_MODE_EIP_191,
// signingtypes.SignMode_SIGN_MODE_TEXTUAL is not enabled by default, as it requires a x/bank keeper or gRPC connection.
}

Expand Down Expand Up @@ -152,6 +153,11 @@ func NewSigningHandlerMap(configOpts ConfigOptions) (*txsigning.HandlerMap, erro
if err != nil {
return nil, err
}
case signingtypes.SignMode_SIGN_MODE_EIP_191:
handlers[i] = NewSignModeEIP191Handler(aminojson.SignModeHandlerOptions{
FileResolver: signingOpts.FileResolver,
TypeResolver: signingOpts.TypeResolver,
})
}
}
for i, m := range configOpts.CustomSignModes {
Expand Down
48 changes: 48 additions & 0 deletions x/auth/tx/eip191.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tx

import (
"context"
"strconv"

signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
"cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/tx/signing/aminojson"
)

const EIP191MessagePrefix = "\x19Ethereum Signed Message:\n"

const eip191NonCriticalFieldsError = "protobuf transaction contains unknown non-critical fields. This is a transaction malleability issue and SIGN_MODE_EIP_191 cannot be used."

// SignModeEIP191Handler defines the SIGN_MODE_DIRECT SignModeHandler
type SignModeEIP191Handler struct {
*aminojson.SignModeHandler
}

// NewSignModeEIP191Handler returns a new SignModeEIP191Handler.
func NewSignModeEIP191Handler(options aminojson.SignModeHandlerOptions) *SignModeEIP191Handler {
return &SignModeEIP191Handler{
SignModeHandler: aminojson.NewSignModeHandler(options),
}
}

var _ signing.SignModeHandler = SignModeEIP191Handler{}

// Mode implements signing.SignModeHandler.Mode.
func (SignModeEIP191Handler) Mode() signingv1beta1.SignMode {
return signingv1beta1.SignMode_SIGN_MODE_EIP_191
}

// GetSignBytes implements SignModeHandler.GetSignBytes
func (h SignModeEIP191Handler) GetSignBytes(
ctx context.Context, data signing.SignerData, txData signing.TxData,
) ([]byte, error) {
aminoJSONBz, err := h.SignModeHandler.GetSignBytes(ctx, data, txData)
if err != nil {
return nil, err
}

return append(append(
[]byte(EIP191MessagePrefix),
[]byte(strconv.Itoa(len(aminoJSONBz)))...,
), aminoJSONBz...), nil
}

0 comments on commit 80a3ce7

Please sign in to comment.