Skip to content
Open
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
18 changes: 5 additions & 13 deletions app/extend_vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package app
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
Expand All @@ -15,6 +14,7 @@ import (

abci "github.com/cometbft/cometbft/abci/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/spf13/viper"
bridgetypes "github.com/tellor-io/layer/x/bridge/types"
oracletypes "github.com/tellor-io/layer/x/oracle/types"
Expand Down Expand Up @@ -283,19 +283,11 @@ func (h *VoteExtHandler) SignInitialMessage(operatorAddress string) ([]byte, []b
messageA := fmt.Sprintf("TellorLayer: Initial bridge signature A for operator %s", operatorAddress)
messageB := fmt.Sprintf("TellorLayer: Initial bridge signature B for operator %s", operatorAddress)

// convert message to bytes
msgBytesA := []byte(messageA)
msgBytesB := []byte(messageB)
// hash messages with Keccak256 (Ethereum standard) then keyring auto-hashes with SHA256
// producing SHA256(Keccak256(message)) to match the bridge contract's _verifySig scheme
msgHashABytes := crypto.Keccak256([]byte(messageA))
msgHashBBytes := crypto.Keccak256([]byte(messageB))

// hash message
msgHashABytes32 := sha256.Sum256(msgBytesA)
msgHashBBytes32 := sha256.Sum256(msgBytesB)

// convert [32]byte to []byte
msgHashABytes := msgHashABytes32[:]
msgHashBBytes := msgHashBBytes32[:]

// sign message
sigA, err := h.SignMessage(msgHashABytes)
if err != nil {
return nil, nil, err
Expand Down
13 changes: 4 additions & 9 deletions app/testutils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,12 @@ func GenerateSignatures(t *testing.T) (sigA, sigB []byte, evmAddr common.Address

msgA := "TellorLayer: Initial bridge signature A"
msgB := "TellorLayer: Initial bridge signature B"
msgBytesA := []byte(msgA)
msgBytesB := []byte(msgB)

// hash messages
msgHashBytes32A := sha256.Sum256(msgBytesA)
msgHashBytesA := msgHashBytes32A[:]
// hash messages with Keccak256 (matching the updated EVMAddressFromSignatures)
msgHashBytesA := crypto.Keccak256([]byte(msgA))
msgHashBytesB := crypto.Keccak256([]byte(msgB))

msgHashBytes32B := sha256.Sum256(msgBytesB)
msgHashBytesB := msgHashBytes32B[:]

// hash the hash, since the keyring signer automatically hashes the message
// hash the hash to simulate the keyring signer's auto-hash with SHA256
msgDoubleHashBytes32A := sha256.Sum256(msgHashBytesA)
msgDoubleHashBytesA := msgDoubleHashBytes32A[:]

Expand Down
42 changes: 31 additions & 11 deletions x/bridge/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,18 +634,12 @@ func (k Keeper) EVMAddressFromSignatures(ctx context.Context, sigA, sigB []byte,
msgA := fmt.Sprintf("TellorLayer: Initial bridge signature A for operator %s", operatorAddress)
msgB := fmt.Sprintf("TellorLayer: Initial bridge signature B for operator %s", operatorAddress)

// convert messages to bytes
msgBytesA := []byte(msgA)
msgBytesB := []byte(msgB)
// hash messages with Keccak256 (Ethereum standard convention)
msgHashBytesA := crypto.Keccak256([]byte(msgA))
msgHashBytesB := crypto.Keccak256([]byte(msgB))

// hash messages
msgHashBytes32A := sha256.Sum256(msgBytesA)
msgHashBytesA := msgHashBytes32A[:]

msgHashBytes32B := sha256.Sum256(msgBytesB)
msgHashBytesB := msgHashBytes32B[:]

// hash the hash, since the keyring signer automatically hashes the message
// hash the hash, since the keyring signer automatically hashes the message with SHA256,
// producing the signed content as SHA256(Keccak256(message))
msgDoubleHashBytes32A := sha256.Sum256(msgHashBytesA)
msgDoubleHashBytesA := msgDoubleHashBytes32A[:]

Expand Down Expand Up @@ -816,6 +810,32 @@ func (k Keeper) SetOracleAttestation(ctx context.Context, operatorAddress string
k.Logger(ctx).Info("Error getting EVM address from operator address", "error", err)
return err
}

// verify the signature: the keyring auto-hashes the snapshot with SHA256 before signing,
// so the signed content is SHA256(snapshot). recover the signer's EVM address and
// compare against the registered address.
if len(sig) != 64 {
return fmt.Errorf("invalid signature length: expected 64, got %d", len(sig))
}
snapshotHash := sha256.Sum256(snapshot)
sigMatches := false
for _, id := range []byte{0, 1} {
sigWithID := append(sig[:64], id)
pubKey, err := crypto.SigToPub(snapshotHash[:], sigWithID)
if err != nil {
continue
}
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
if bytes.Equal(recoveredAddr.Bytes(), ethAddress.EVMAddress) {
sigMatches = true
break
}
}
if !sigMatches {
k.Logger(ctx).Info("Oracle attestation signature does not match validator's EVM address")
return fmt.Errorf("oracle attestation signature verification failed for operator %s", operatorAddress)
}

// get the last saved bridge validator set
lastSavedBridgeValidators, err := k.BridgeValset.Get(ctx)
if err != nil {
Expand Down
26 changes: 8 additions & 18 deletions x/bridge/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,17 +708,12 @@ func TestEVMAddressFromSignatures(t *testing.T) {

msgA := fmt.Sprintf("TellorLayer: Initial bridge signature A for operator %s", operatorAddr)
msgB := fmt.Sprintf("TellorLayer: Initial bridge signature B for operator %s", operatorAddr)
msgBytesA := []byte(msgA)
msgBytesB := []byte(msgB)

// hash messages
msgHashBytes32A := sha256.Sum256(msgBytesA)
msgHashBytesA := msgHashBytes32A[:]
// hash messages with Keccak256 (matching updated EVMAddressFromSignatures)
msgHashBytesA := crypto.Keccak256([]byte(msgA))
msgHashBytesB := crypto.Keccak256([]byte(msgB))

msgHashBytes32B := sha256.Sum256(msgBytesB)
msgHashBytesB := msgHashBytes32B[:]

// hash the hash, since the keyring signer automatically hashes the message
// hash the hash to simulate keyring auto-hash with SHA256
msgDoubleHashBytes32A := sha256.Sum256(msgHashBytesA)
msgDoubleHashBytesA := msgDoubleHashBytes32A[:]

Expand Down Expand Up @@ -768,17 +763,12 @@ func TestTryRecoverAddressWithBothIDs(t *testing.T) {

msgA := "TellorLayer: Initial bridge signature A"
msgB := "TellorLayer: Initial bridge signature B"
msgBytesA := []byte(msgA)
msgBytesB := []byte(msgB)

// hash messages
msgHashBytes32A := sha256.Sum256(msgBytesA)
msgHashBytesA := msgHashBytes32A[:]

msgHashBytes32B := sha256.Sum256(msgBytesB)
msgHashBytesB := msgHashBytes32B[:]
// hash messages with Keccak256 (matching updated TryRecoverAddressWithBothIDs usage)
msgHashBytesA := crypto.Keccak256([]byte(msgA))
msgHashBytesB := crypto.Keccak256([]byte(msgB))

// hash the hash, since the keyring signer automatically hashes the message
// hash the hash to simulate keyring auto-hash with SHA256
msgDoubleHashBytes32A := sha256.Sum256(msgHashBytesA)
msgDoubleHashBytesA := msgDoubleHashBytes32A[:]

Expand Down
2 changes: 1 addition & 1 deletion x/dispute/keeper/dispute.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func (k Keeper) AddDisputeRound(ctx sdk.Context, sender sdk.AccAddress, dispute
dispute.DisputeEndTime = ctx.BlockTime().Add(THREE_DAYS)
dispute.DisputeStartBlock = uint64(ctx.BlockHeight())
dispute.DisputeRound++
dispute.PrevDisputeIds = append(dispute.PrevDisputeIds, disputeId)
dispute.PrevDisputeIds = append(dispute.PrevDisputeIds, prevDisputeId)

err := k.Disputes.Set(ctx, dispute.DisputeId, dispute)
if err != nil {
Expand Down