8000 fix: sigverify to attach eip191 prefix, only it is legacy amino json mode by beer-1 · Pull Request #377 · initia-labs/initia · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

fix: sigverify to attach eip191 prefix, only it is legacy amino json mode #377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions app/ante/sigverify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import (

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"

"github.com/initia-labs/initia/crypto/ethsecp256k1"
)

// internalSignModeToAPI converts a signing.SignMode to a protobuf SignMode.
Expand Down Expand Up @@ -54,18 +51,6 @@ func verifySignature(
return err
}

// TODO - remove this once `interwoven-1` has been upgraded to initia@v1.1.0 via software upgrade
// interwoven-1 eth pubkey verification has been changed to use EIP-191 prefix at block height 39652
if sdkCtx := sdk.UnwrapSDKContext(ctx); sdkCtx.ChainID() == "interwoven-1" && sdkCtx.BlockHeight() < 39652 {
if pubkey, ok := pubKey.(*ethsecp256k1.PubKey); ok {
if !pubkey.VerifySignatureWithoutEIP191(signBytes, data.Signature) {
return fmt.Errorf("unable to verify single signer signature")
}

return nil
}
}

if !pubKey.VerifySignature(signBytes, data.Signature) {
return fmt.Errorf("unable to verify single signer signature")
}
Expand Down
12 changes: 11 additions & 1 deletion cmd/initiad/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,17 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
return err
}

if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil {
// override the keyring if it's set
if initClientCtx.Keyring != nil {
kr, err := cryptokeyring.NewKeyring(initClientCtx, initClientCtx.Keyring.Backend())
if err != nil {
return err
}

initClientCtx = initClientCtx.WithKeyring(kr)
}

if err := client.SetCmdClientContext(cmd, initClientCtx); err != nil {
return err
}

Expand Down
22 changes: 1 addition & 21 deletions crypto/ethsecp256k1/ethsecp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import (
"fmt"
io "io"
"math/big"
"strings"

errorsmod "cosmossdk.io/errors"
"github.com/cometbft/cometbft/crypto"
"github.com/initia-labs/initia/tx"
"golang.org/x/crypto/sha3"

"github.com/cosmos/cosmos-sdk/codec"
Expand Down Expand Up @@ -137,11 +135,6 @@ func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
// provided hash of the message. The produced signature is 65 bytes
// where the last byte contains the recovery ID.
func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
// if message does not start with EIP-191 prefix, add it
if !strings.HasPrefix(string(msg), tx.EIP191MessagePrefix) {
msg = tx.FormatEIP191Message(msg)
}

priv := secp256k1.PrivKeyFromBytes(privKey.Key)

sig := ecdsa.SignCompact(priv, keccak256(msg), false)
Expand Down Expand Up @@ -242,23 +235,10 @@ func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error {
}

// VerifySignature verifies that the ECDSA public key created a given signature over
// the provided message. It will attach the EIP-191 prefix to the message if it is not already present.
// the provided message.
//
// CONTRACT: The signature should be in [R || S] format.
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
// if message does not start with EIP-191 prefix, add it
if !strings.HasPrefix(string(msg), tx.EIP191MessagePrefix) {
msg = tx.FormatEIP191Message(msg)
}

return pubKey.verifySignatureECDSA(msg, sig)
}

// VerifySignatureWithoutEIP191 verifies that the ECDSA public key created a given signature over
// the provided message. It does not attach the EIP-191 prefix to the message.
//
// CONTRACT: The signature should be in [R || S] format.
func (pubKey PubKey) VerifySignatureWithoutEIP191(msg, sig []byte) bool {
return pubKey.verifySignatureECDSA(msg, sig)
}

Expand Down
96 changes: 96 additions & 0 deletions crypto/keyring/keyring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package keyring

import (
"errors"
"fmt"

"github.com/cosmos/cosmos-sdk/client"
cosmoskeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/ledger"
"github.com/cosmos/cosmos-sdk/crypto/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"

"github.com/initia-labs/initia/crypto/ethsecp256k1"
"github.com/initia-labs/initia/tx"
)

type Keyring struct {
cosmoskeyring.Keyring
}

func NewKeyring(ctx client.Context, backend string) (*Keyring, error) {
kr, err := cosmoskeyring.New(sdk.KeyringServiceName(), backend, ctx.KeyringDir, ctx.Input, ctx.Codec, ctx.KeyringOptions...)
if err != nil {
return nil, err
}

Check warning on line 27 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L23-L27

Added lines #L23 - L27 were not covered by tests

return &Keyring{Keyring: kr}, nil

Check warning on line 29 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L29

Added line #L29 was not covered by tests
}

func (ks Keyring) Sign(uid string, msg []byte, signMode signing.SignMode) ([]byte, cryptotypes.PubKey, error) {
k, err := ks.Key(uid)
if err != nil {
return nil, nil, err
}

Check warning on line 36 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L32-L36

Added lines #L32 - L36 were not covered by tests

switch {
case k.GetLedger() != nil:
return SignWithLedger(k, msg, signMode)
default:
return ks.Keyring.Sign(uid, msg, signMode)

Check warning on line 42 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L38-L42

Added lines #L38 - L42 were not covered by tests
}
}

// SignWithLedger signs a binary message with the ledger device referenced by an Info object
// and returns the signed bytes and the public key. It returns an error if the device could
// not be queried or it returned an error.
func SignWithLedger(k *cosmoskeyring.Record, msg []byte, signMode signing.SignMode) (sig []byte, pub types.PubKey, err error) {
pubKey, err := k.GetPubKey()
if err != nil {
return nil, nil, err
}

Check warning on line 53 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L49-L53

Added lines #L49 - L53 were not covered by tests

// validate flags
_, isEthPubKey := pubKey.(*ethsecp256k1.PubKey)
if isEthPubKey && signMode != signing.SignMode_SIGN_MODE_EIP_191 {
return nil, nil, errors.New("must use --sign-mode=eip-191 for Ethereum Ledger")
} else if !isEthPubKey && signMode != signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON {
return nil, nil, errors.New("must use --sign-mode=amino-json for Cosmos Ledger")
}

Check warning on line 61 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L56-L61

Added lines #L56 - L61 were not covered by tests

signMsg := msg
if isEthPubKey {
// Remove EIP191 prefix from message since the Ledger device will
// automatically add the prefix before signing. This avoids double-prefixing
// which would result in an invalid signature.
signMsg = tx.RemoveEIP191Prefix(msg)
}

Check warning on line 69 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L63-L69

Added lines #L63 - L69 were not covered by tests

ledgerInfo := k.GetLedger()
if ledgerInfo == nil {
return nil, nil, cosmoskeyring.ErrNotLedgerObj
}

Check warning on line 74 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L71-L74

Added lines #L71 - L74 were not covered by tests

path := ledgerInfo.GetPath()
priv, err := ledger.NewPrivKeySecp256k1Unsafe(*path)
if err != nil {
return
}
ledgerPubKey := priv.PubKey()
if !pubKey.Equals(ledgerPubKey) {
return nil, nil, fmt.Errorf("the public key that the user attempted to sign with does not match the public key on the ledger device. %v does not match %v", pubKey.String(), ledgerPubKey.String())
}

Check warning on line 84 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L76-L84

Added lines #L76 - L84 were not covered by tests

sig, err = priv.SignLedgerAminoJSON(signMsg)
if err != nil {
return nil, nil, err
}

Check warning on line 89 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L86-L89

Added lines #L86 - L89 were not covered by tests

if !priv.PubKey().VerifySignature(msg, sig) {
return nil, nil, cosmoskeyring.ErrLedgerInvalidSignature
}

Check warning on line 93 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L91-L93

Added lines #L91 - L93 were not covered by tests

return sig, priv.PubKey(), nil

Check warning on line 95 in crypto/keyring/keyring.go

View check run for this annotation

Codecov / codecov/patch

crypto/keyring/keyring.go#L95

Added line #L95 was not covered by tests
}
22 changes: 19 additions & 3 deletions crypto/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package ledger

import (
"bytes"
"encoding/json"
"fmt"
"strings"

Expand Down Expand Up @@ -140,9 +142,23 @@ func (i *InitiaLedger) SignSECP256K1(hdPath []uint32, signBytes []byte, _ byte)
return nil, errors.Wrap(err, "failed to derive account")
}

fmt.Println("Please check your Ledger device for confirmation")
fmt.Println("Signing message:")
fmt.Println(string(signBytes))
// pretty print the sign bytes

var prettySignBytes bytes.Buffer
err = json.Indent(&prettySignBytes, signBytes, "", " ")
if err != nil {
return nil, errors.Wrap(err, "failed to indent sign bytes")
}

fmt.Printf(`
################################################
Please check your Ledger device for confirmation

Signing message:
%s
################################################

`, prettySignBytes.String())

sig, err := i.wallet.SignText(account, signBytes)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,18 @@ require github.com/cosmos/iavl v1.2.5-0.20250306174232-6cfb3dac2c71 // indirect

// initia custom
// use custom version for
//
// cometbft
// - https://github.com/initia-labs/cometbft/commit/cb3ed4ca9be4d6c55df7df2d927e9b92153bc3e2
// - https://github.com/initia-labs/cometbft/pull/14
//
// cosmos-sdk
// - https://github.com/initia-labs/cosmos-sdk/commit/2d8e8144a217545d4d4d35d4b82f0dcc711a2501
//
// connect
// - https://github.com/initia-labs/connect/pull/1
replace (
github.com/cometbft/cometbft => github.com/initia-labs/cometbft v0.0.0-20250324104207-ff0764c4444f
github.com/cosmos/cosmos-sdk => github.com/initia-labs/cosmos-sdk v0.0.0-20250325094132-2d8e8144a217
github.com/skip-mev/connect/v2 => github.com/initia-labs/connect/v2 v2.3.1
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,6 @@ github.com/cosmos/cosmos-db v1.1.1 h1:FezFSU37AlBC8S98NlSagL76oqBRWq/prTPvFcEJNC
github.com/cosmos/cosmos-db v1.1.1/go.mod h1:AghjcIPqdhSLP/2Z0yha5xPH3nLnskz81pBx3tcVSAw=
github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
github.com/cosmos/cosmos-sdk v0.50.13 h1:xQ32hhzVy7agEe7behMdZN0ezWhPss3KoLZsF9KoBnw=
github.com/cosmos/cosmos-sdk v0.50.13/go.mod h1:hrWEFMU1eoXqLJeE6VVESpJDQH67FS1nnMrQIjO2daw=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=
Expand Down Expand Up @@ -755,6 +753,8 @@ github.com/initia-labs/cometbft v0.0.0-20250324104207-ff0764c4444f h1:XA4MKOcB/V
github.com/initia-labs/cometbft v0.0.0-20250324104207-ff0764c4444f/go.mod h1:5l0SkgeLRXi6bBfQuevXjKqML1jjfJJlvI1Ulp02/o4=
github.com/initia-labs/connect/v2 v2.3.1 h1:Y32LCwUHDBgUzzQHqPBJeWeItYoNu2oYD57JKbZCtjw=
github.com/initia-labs/connect/v2 v2.3.1/go.mod h1:35hM7xSgI0h3GMUTgspzKY8Ff2yCXNGNwmAdjqo3z8s=
github.com/initia-labs/cosmos-sdk v0.0.0-20250325094132-2d8e8144a217 h1:MhVePu3T8Q1c9DmmDSVIhJ5OjzsDdjo48oMfRyL0xy4=
github.com/initia-labs/cosmos-sdk v0.0.0-20250325094132-2d8e8144a217/go.mod h1:hrWEFMU1eoXqLJeE6VVESpJDQH67FS1nnMrQIjO2daw=
github.com/initia-labs/movevm v1.0.0-beta.0 h1:ay/IOEkwH33vPis8W4WwC9BQ/ZtUtW/ekAlrZKPW5YI=
github.com/initia-labs/movevm v1.0.0-beta.0/go.mod h1:sj/kXD7mUQASqogPTjqltIr4Uid3xxnlcbfiFvvqeXA=
github.com/jhump/protoreflect v1.15.3 h1:6SFRuqU45u9hIZPJAoZ8c28T3nK64BNdp9w6jFonzls=
Expand Down
11 changes: 11 additions & 0 deletions tx/eip191.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import (
"context"
"strconv"
"strings"

signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
"cosmossdk.io/x/tx/signing"
Expand Down Expand Up @@ -49,3 +50,13 @@
[]byte(strconv.Itoa(len(msg)))...,
), msg...)
}

// RemoveEIP191Prefix removes the EIP-191 prefix from a message.
func RemoveEIP191Prefix(msg []byte) []byte {
idx := strings.Index(string(msg), "{")
if idx == -1 {
return msg
}

Check warning on line 59 in tx/eip191.go

View check run for this annotation

Codecov / codecov/patch

tx/eip191.go#L55-L59

Added lines #L55 - L59 were not covered by tests

return msg[idx:]

Check warning on line 61 in tx/eip191.go

View check run for this annotation

Codecov / codecov/patch

tx/eip191.go#L61

Added line #L61 was not covered by tests
}
Loading
0