Skip to content

Commit

Permalink
Merge PR #92: hashing api change
Browse files Browse the repository at this point in the history
* add test case

* lint++

* Hash all messages before prepending bytes in eth signatures

* Add passing values to the signature test

* Go tests all pass with ensuring hashing before verifying messages

Co-authored-by: Aleksandr Bezobchuk <[email protected]>
  • Loading branch information
zmanian and alexanderbez authored Jul 22, 2021
1 parent d87a157 commit 7f01342
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 10 deletions.
7 changes: 4 additions & 3 deletions module/x/gravity/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ func TestMsgSetDelegateAddresses(t *testing.T) {
Nonce: 0,
}
signMsgBz := input.Marshaler.MustMarshalBinaryBare(&ethMsg)

sig, err := types.NewEthereumSignature(signMsgBz, ethPrivKey)
hash := crypto.Keccak256Hash(signMsgBz).Bytes()
sig, err := types.NewEthereumSignature(hash, ethPrivKey)
require.NoError(t, err)

k := input.GravityKeeper
Expand Down Expand Up @@ -358,8 +358,9 @@ func TestMsgSetDelegateAddresses(t *testing.T) {
Nonce: 0,
}
signMsgBz = input.Marshaler.MustMarshalBinaryBare(&ethMsg)
hash = crypto.Keccak256Hash(signMsgBz).Bytes()

sig, err = types.NewEthereumSignature(signMsgBz, ethPrivKey2)
sig, err = types.NewEthereumSignature(hash, ethPrivKey2)
require.NoError(t, err)

msg = types.NewMsgDelegateKeys(valAddress, cosmosAddress2, ethAddress2.String(), sig)
Expand Down
5 changes: 4 additions & 1 deletion module/x/gravity/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"

"github.com/peggyjv/gravity-bridge/module/x/gravity/types"
)
Expand Down Expand Up @@ -76,7 +77,9 @@ func (k msgServer) SetDelegateKeys(c context.Context, msg *types.MsgDelegateKeys
Nonce: nonce,
})

if err = types.ValidateEthereumSignature(signMsgBz, msg.EthSignature, ethAddr); err != nil {
hash := crypto.Keccak256Hash(signMsgBz).Bytes()

if err = types.ValidateEthereumSignature(hash, msg.EthSignature, ethAddr); err != nil {
return nil, sdkerrors.Wrapf(
types.ErrDelegateKeys,
"failed to validate delegate keys signature for Ethereum address %X; %s",
Expand Down
69 changes: 64 additions & 5 deletions module/x/gravity/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package keeper

import (
"bytes"
"crypto/ecdsa"
"fmt"
"testing"

"github.com/ethereum/go-ethereum/crypto"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/peggyjv/gravity-bridge/module/x/gravity/types"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"

ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/peggyjv/gravity-bridge/module/x/gravity/types"
)

func TestMsgServer_SubmitEthereumSignature(t *testing.T) {
Expand Down Expand Up @@ -326,8 +329,9 @@ func TestMsgServer_SetDelegateKeys(t *testing.T) {
Nonce: 0,
}
signMsgBz := env.Marshaler.MustMarshalBinaryBare(&ethMsg)
hash := crypto.Keccak256Hash(signMsgBz).Bytes()

sig, err := types.NewEthereumSignature(signMsgBz, ethPrivKey)
sig, err := types.NewEthereumSignature(hash, ethPrivKey)
require.NoError(t, err)

msg := &types.MsgDelegateKeys{
Expand All @@ -340,3 +344,58 @@ func TestMsgServer_SetDelegateKeys(t *testing.T) {
_, err = msgServer.SetDelegateKeys(sdk.WrapSDKContext(ctx), msg)
require.NoError(t, err)
}

func TestEthVerify(t *testing.T) {
// Replace privKeyHexStr and addrHexStr with your own private key and address
// HEX values.
privKeyHexStr := "0xee63225c8a0928168d362147cd19859de6459e972ffcf9294a69382b4ad99720"
addrHexStr := "0xA093773C30Ad5c3e83B20E66CB4e6136aEa098B7"

// ==========================================================================
// setup
// ==========================================================================
privKeyBz, err := hexutil.Decode(privKeyHexStr)
require.NoError(t, err)

privKey, err := crypto.ToECDSA(privKeyBz)
require.NoError(t, err)
require.NotNil(t, privKey)

require.True(t, bytes.Equal(privKeyBz, crypto.FromECDSA(privKey)))
require.Equal(t, privKeyHexStr, hexutil.Encode(crypto.FromECDSA(privKey)))

publicKey := privKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
require.True(t, ok)

address := crypto.PubkeyToAddress(*publicKeyECDSA)
require.Equal(t, addrHexStr, address.Hex())

// ==========================================================================
// signature verification
// ==========================================================================
cdc := MakeTestMarshaler()

valAddr := "cosmosvaloper16k7rf90uvt4tgslqh280wvdzxp5q9ah6nxxupc"
signMsgBz, err := cdc.MarshalBinaryBare(&types.DelegateKeysSignMsg{
ValidatorAddress: valAddr,
Nonce: 0,
})

require.NoError(t, err)

fmt.Println("MESSAGE BYTES TO SIGN:", hexutil.Encode(signMsgBz))
hash := crypto.Keccak256Hash(signMsgBz).Bytes()

sig, err := types.NewEthereumSignature(hash, privKey)
sig[64] += 27 // change the V value
require.NoError(t, err)

err = types.ValidateEthereumSignature(hash, sig, address)
require.NoError(t, err)

// replace gorcSig with what the following command produces:
// $ gorc sign-delegate-keys <your-eth-key-name> cosmosvaloper1dmly9yyhd5lyhyl8qhs7wtcd4xt7gyxlesgvmc 0
gorcSig := "0xbda7037e448ca07ac91f5f386b72df37b6bbacf102b2c8f5acb58b5e053d68d96875ce9e442433bea55ac083230f492670ca2c07a8303c332dca06b1c0758c661b"
require.Equal(t, hexutil.Encode(sig), gorcSig)
}
3 changes: 2 additions & 1 deletion module/x/gravity/types/ethereum_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ func NewEthereumSignature(hash []byte, privateKey *ecdsa.PrivateKey) ([]byte, er
if privateKey == nil {
return nil, sdkerrors.Wrap(ErrInvalid, "did not pass in private key")
}
protectedHash := crypto.Keccak256Hash(append([]uint8(signaturePrefix), hash...))
protectedHash := crypto.Keccak256Hash(append([]byte(signaturePrefix), hash...))
return crypto.Sign(protectedHash.Bytes(), privateKey)
}

// ValidateEthereumSignature takes a message, an associated signature and public key and
// returns an error if the signature isn't valid
func ValidateEthereumSignature(hash []byte, signature []byte, ethAddress common.Address) error {

/// signature to public key: invalid signature length: invalid
/// signature not matching: invalid: invalid
if len(signature) < 65 {
Expand Down
2 changes: 2 additions & 0 deletions orchestrator/gorc/src/commands/sign_delegate_keys.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::application::APP;
use crate::prelude::*;
use abscissa_core::{Application, Command, Options, Runnable};
use gravity_proto::gravity as proto;

Expand Down Expand Up @@ -36,6 +37,7 @@ impl Runnable for SignDelegateKeysCmd {
prost::Message::encode(&msg, &mut buf)
.expect("Failed to encode DelegateKeysSignMsg!");

info!("MESSAGE BYTES TO SIGN:{}",clarity::utils::bytes_to_hex_str(&buf));
let signature = key.sign_ethereum_msg(&buf);

println!("{}", signature);
Expand Down

0 comments on commit 7f01342

Please sign in to comment.