Skip to content

Commit

Permalink
Change message hash to align with Gnosis SDK for multisig (#144)
Browse files Browse the repository at this point in the history
* change message hash to align with Gnosis SDK for multisig

* add one more Metamask sig example

* finalize Metamask example

* update react example

* update react

* add log of message hash to operator

* fix tests

* critic
  • Loading branch information
pavelkrolevets authored Oct 18, 2024
1 parent c55878f commit 9ca6c05
Show file tree
Hide file tree
Showing 64 changed files with 29,984 additions and 218 deletions.
14 changes: 6 additions & 8 deletions cli/initiator/reshare.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package initiator

import (
"encoding/hex"
"fmt"
"log"
"os"

e2m_core "github.com/bloxapp/eth2-key-manager/core"
"github.com/spf13/cobra"
"go.uber.org/zap"

spec "github.com/ssvlabs/dkg-spec"
cli_utils "github.com/ssvlabs/ssv-dkg/cli/utils"
"github.com/ssvlabs/ssv-dkg/pkgs/initiator"
"github.com/ssvlabs/ssv-dkg/pkgs/utils"
"github.com/ssvlabs/ssv-dkg/pkgs/wire"
"go.uber.org/zap"

spec "github.com/ssvlabs/dkg-spec"
)

func init() {
Expand Down Expand Up @@ -96,14 +95,13 @@ var GenerateReshareMsg = &cobra.Command{
}
rMsgs = append(rMsgs, rMsg)
}
// write bulk reshare message to file
hash, err := utils.GetMessageHash(rMsgs)
// write bulk reshare message hex to file
msgHex, err := utils.GetMessageString(rMsgs)
if err != nil {
logger.Fatal("😥 Failed to marshal reshare message hash:", zap.Error(err))
}
data := fmt.Sprintf("0x%s", hex.EncodeToString(hash[:]))
finalPath := fmt.Sprintf("%s/reshare.txt", cli_utils.OutputPath)
err = os.WriteFile(finalPath, []byte(data), 0o600)
err = os.WriteFile(finalPath, []byte(msgHex), 0o600)
if err != nil {
logger.Fatal("😥 Failed to save reshare message hash:", zap.Error(err))
}
Expand Down
12 changes: 5 additions & 7 deletions cli/initiator/resigning.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package initiator

import (
"encoding/hex"
"fmt"
"log"
"os"

e2m_core "github.com/bloxapp/eth2-key-manager/core"
"github.com/spf13/cobra"
"go.uber.org/zap"

spec "github.com/ssvlabs/dkg-spec"
cli_utils "github.com/ssvlabs/ssv-dkg/cli/utils"
"github.com/ssvlabs/ssv-dkg/pkgs/initiator"
"github.com/ssvlabs/ssv-dkg/pkgs/utils"
"github.com/ssvlabs/ssv-dkg/pkgs/wire"
"go.uber.org/zap"

spec "github.com/ssvlabs/dkg-spec"
)

func init() {
Expand Down Expand Up @@ -92,13 +91,12 @@ var GenerateResignMsg = &cobra.Command{
rMsgs = append(rMsgs, rMsg)
}
// Save the resign messages
hash, err := utils.GetMessageHash(rMsgs)
msgHex, err := utils.GetMessageString(rMsgs)
if err != nil {
logger.Fatal("😥 Failed to marshal resign message hash:", zap.Error(err))
}
data := fmt.Sprintf("0x%s", hex.EncodeToString(hash[:]))
finalPath := fmt.Sprintf("%s/resign.txt", cli_utils.OutputPath)
err = os.WriteFile(finalPath, []byte(data), 0o600)
err = os.WriteFile(finalPath, []byte(msgHex), 0o600)
if err != nil {
logger.Fatal("😥 Failed to save resign message hash:", zap.Error(err))
}
Expand Down
2 changes: 1 addition & 1 deletion cli/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"os"

"github.com/spf13/cobra"

"github.com/aquasecurity/table"

cli_utils "github.com/ssvlabs/ssv-dkg/cli/utils"
"github.com/ssvlabs/ssv-dkg/pkgs/validator"
)
Expand Down
147 changes: 77 additions & 70 deletions integration_test/multisig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strconv"
"testing"

"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
eth_crypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
Expand Down Expand Up @@ -121,73 +122,79 @@ func TestVerifyMultisigSignedOnChain(t *testing.T) {
})
}

// func TestVerifyMultisigSignedBulkReshareOffChain(t *testing.T) {
// t.Run("valid Gnosis 2/3 miltisig offchain signatures", func(t *testing.T) {
// gnosisAddress := common.HexToAddress("0xC4D860871fb983d17eC665a305e98F1B3035a817")
// ethBackend, err := ethclient.Dial(EthRPC)
// require.NoError(t, err)

// reshareBytes, err := os.ReadFile(filepath.Clean("./stubs/reshare/bulk_reshare_msgs.json"))
// require.NoError(t, err)
// var signedBulkReshare wire.SignedBulkReshare
// err = json.Unmarshal(reshareBytes, &signedBulkReshare)
// require.NoError(t, err)

// bulkReshareMsgs, err := signedBulkReshare.MarshalReshareMessagesJSON()
// require.NoError(t, err)

// var finalMsg []byte
// prefix := []byte("\x19Ethereum Signed Message:\n")
// msgLen := []byte(strconv.Itoa(len(bulkReshareMsgs)))

// finalMsg = append(finalMsg, prefix...)
// finalMsg = append(finalMsg, msgLen...)
// finalMsg = append(finalMsg, bulkReshareMsgs...)
// var hash [32]byte
// keccak256 := eth_crypto.Keccak256(finalMsg)
// copy(hash[:], keccak256)
// t.Log("Hash", hex.EncodeToString(hash[:]))
// require.NoError(t, err)
// t.Log("Signature", hex.EncodeToString(signedBulkReshare.Signature))
// require.NoError(t, spec_crypto.VerifySignedMessageByOwner(ethBackend,
// gnosisAddress,
// hash,
// signedBulkReshare.Signature))
// })
// }

// func TestVerifyMultisigSignedBulkResignOffChain(t *testing.T) {
// t.Run("valid Gnosis 2/3 miltisig offchain signatures", func(t *testing.T) {
// gnosisAddress := common.HexToAddress("0xC4D860871fb983d17eC665a305e98F1B3035a817")
// ethBackend, err := ethclient.Dial(EthRPC)
// require.NoError(t, err)

// bulkResignBytes, err := os.ReadFile(filepath.Clean("./stubs/resign/bulk_resign_msgs.json"))
// require.NoError(t, err)
// var signedBulkResign wire.SignedBulkResign
// err = json.Unmarshal(bulkResignBytes, &signedBulkResign)
// require.NoError(t, err)

// bulkReshareMsgs, err := signedBulkResign.MarshalResignMessagesJSON()
// require.NoError(t, err)
// t.Log("Marshaled resign messages", string(bulkReshareMsgs))

// var finalMsg []byte
// prefix := []byte("\x19Ethereum Signed Message:\n")
// msgLen := []byte(strconv.Itoa(len(bulkReshareMsgs)))

// finalMsg = append(finalMsg, prefix...)
// finalMsg = append(finalMsg, msgLen...)
// finalMsg = append(finalMsg, bulkReshareMsgs...)
// var hash [32]byte
// keccak256 := eth_crypto.Keccak256(finalMsg)
// copy(hash[:], keccak256)
// t.Log("Hash", hex.EncodeToString(hash[:]))
// require.NoError(t, err)
// t.Log("Signature", hex.EncodeToString(signedBulkResign.Signature))
// require.NoError(t, spec_crypto.VerifySignedMessageByOwner(ethBackend,
// gnosisAddress,
// hash,
// signedBulkResign.Signature))
// })
// }
func TestVerifyMultisigSignedOffChain(t *testing.T) {
t.Run("valid Gnosis 2/3 miltisig offchain signatures", func(t *testing.T) {
gnosisAddress := common.HexToAddress("0x43908b5794da9A8f714f001567D8dA1523e68bDb")
ethBackend, err := ethclient.Dial(EthRPC)
require.NoError(t, err)

msg := "932ab87aee23606dd0c085cab46322ffed345a3aa028673c25f72b5d486e14e2"

var finalMsg []byte
prefix := []byte("\x19Ethereum Signed Message:\n")
msgLen := []byte(strconv.Itoa(len(msg)))

finalMsg = append(finalMsg, prefix...)
finalMsg = append(finalMsg, msgLen...)
finalMsg = append(finalMsg, msg...)
var hash [32]byte
keccak256 := eth_crypto.Keccak256(finalMsg)
copy(hash[:], keccak256)
// signed with TS script here utils/gnosis_multisig_examples/safe_off_chain
sig, err := hex.DecodeString("5b931ab4702f3712cfc791cf9bb88ce5b888ac6e3d9037e9867d926d696dd5d61831d98008f0a0b7d990ad8f049fe964e44ac5b8b800dd924354699d27ef6fa61ce5ce47d802cecc1e4158cb6a32159c60d2cbcdd29f5c811a5c389fc5e8b36fba3fb5c5284fb4ea3625b79e5f11396ad21a047d8c60ffc4076bf0e0f65e9ec6951c")
require.NoError(t, err)
require.NoError(t, spec_crypto.VerifySignedMessageByOwner(ethBackend,
gnosisAddress,
hash,
sig))
})
}

func TestVerifyEOASigned(t *testing.T) {
t.Run("valid EOA signatures", func(t *testing.T) {
gnosisAddress := common.HexToAddress("0xDCc846fA10C7CfCE9e6Eb37e06eD93b666cFC5E9")
ethBackend, err := ethclient.Dial(EthRPC)
require.NoError(t, err)

msg := "a3703ef95414e008f95e9d0adb6e0122e70ea2a71459eeafe3382dd24ae03706"

var finalMsg []byte
prefix := []byte("\x19Ethereum Signed Message:\n")
msgLen := []byte(strconv.Itoa(len(msg)))

finalMsg = append(finalMsg, prefix...)
finalMsg = append(finalMsg, msgLen...)
finalMsg = append(finalMsg, msg...)
var hash [32]byte
keccak256 := eth_crypto.Keccak256([]byte(finalMsg))
copy(hash[:], keccak256)

t.Log("Hash :", hex.EncodeToString(hash[:]))

sk_path := "../examples/initiator/UTC--2024-06-14T14-05-12.366668334Z--dcc846fa10c7cfce9e6eb37e06ed93b666cfc5e9"
password_path := "../examples/initiator/password"

jsonBytes, err := os.ReadFile(sk_path)
require.NoError(t, err)
keyStorePassword, err := os.ReadFile(filepath.Clean(password_path))
require.NoError(t, err)
sk, err := keystore.DecryptKey(jsonBytes, string(keyStorePassword))
require.NoError(t, err)

ownerSigBytes, err := eth_crypto.Sign(hash[:], sk.PrivateKey)
require.NoError(t, err)

t.Log("Sig :", hex.EncodeToString(ownerSigBytes))

require.NoError(t, spec_crypto.VerifySignedMessageByOwner(ethBackend,
gnosisAddress,
hash,
ownerSigBytes))
sigFromMetamask, err := hex.DecodeString("ccb1866d30562f25cfb3d7001008667eba5fd76de2270cc32dc037ff7cd204f67c9f4fbfd47834bedb69a5907d8ef428dbb6fc706938866a01fe96763052758200")
require.NoError(t, err)
require.NoError(t, spec_crypto.VerifySignedMessageByOwner(ethBackend,
gnosisAddress,
hash,
sigFromMetamask))
})
}
42 changes: 4 additions & 38 deletions integration_test/reshare_bulk_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package integration_test

import (
"encoding/hex"
"encoding/json"
"os"
"path/filepath"
"strconv"
"strings"
"testing"

"github.com/bloxapp/ssv/logging"
Expand Down Expand Up @@ -136,8 +134,6 @@ func TestBulkReshareHappyFlows4Ops(t *testing.T) {
// load reshare message
reshareMsgBytes, err := os.ReadFile("./output/reshare.txt")
require.NoError(t, err)
hash, err := hex.DecodeString(strings.TrimPrefix(string(reshareMsgBytes), "0x"))
require.NoError(t, err)

// sign reshare message
jsonBytes, err := os.ReadFile("./stubs/UTC--2024-06-14T14-05-12.366668334Z--dcc846fa10c7cfce9e6eb37e06ed93b666cfc5e9")
Expand All @@ -146,7 +142,7 @@ func TestBulkReshareHappyFlows4Ops(t *testing.T) {
require.NoError(t, err)
sk, err := keystore.DecryptKey(jsonBytes, string(keyStorePassword))
require.NoError(t, err)
signature, err := SignHash(hash, sk.PrivateKey)
signature, err := SignHash(string(reshareMsgBytes), sk.PrivateKey)
require.NoError(t, err)

args := []string{"reshare",
Expand Down Expand Up @@ -313,8 +309,6 @@ func TestBulkReshareHappyFlows7Ops(t *testing.T) {
// load reshare message
reshareMsgBytes, err := os.ReadFile("./output/reshare.txt")
require.NoError(t, err)
hash, err := hex.DecodeString(strings.TrimPrefix(string(reshareMsgBytes), "0x"))
require.NoError(t, err)

// sign reshare message
jsonBytes, err := os.ReadFile("./stubs/UTC--2024-06-14T14-05-12.366668334Z--dcc846fa10c7cfce9e6eb37e06ed93b666cfc5e9")
Expand All @@ -323,7 +317,7 @@ func TestBulkReshareHappyFlows7Ops(t *testing.T) {
require.NoError(t, err)
sk, err := keystore.DecryptKey(jsonBytes, string(keyStorePassword))
require.NoError(t, err)
signature, err := SignHash(hash, sk.PrivateKey)
signature, err := SignHash(string(reshareMsgBytes), sk.PrivateKey)
require.NoError(t, err)

args := []string{"reshare",
Expand Down Expand Up @@ -490,8 +484,6 @@ func TestBulkReshareHappyFlows10Ops(t *testing.T) {
// load reshare message
reshareMsgBytes, err := os.ReadFile("./output/reshare.txt")
require.NoError(t, err)
hash, err := hex.DecodeString(strings.TrimPrefix(string(reshareMsgBytes), "0x"))
require.NoError(t, err)

// sign reshare message
jsonBytes, err := os.ReadFile("./stubs/UTC--2024-06-14T14-05-12.366668334Z--dcc846fa10c7cfce9e6eb37e06ed93b666cfc5e9")
Expand All @@ -500,7 +492,7 @@ func TestBulkReshareHappyFlows10Ops(t *testing.T) {
require.NoError(t, err)
sk, err := keystore.DecryptKey(jsonBytes, string(keyStorePassword))
require.NoError(t, err)
signature, err := SignHash(hash, sk.PrivateKey)
signature, err := SignHash(string(reshareMsgBytes), sk.PrivateKey)
require.NoError(t, err)

args := []string{"reshare",
Expand Down Expand Up @@ -667,8 +659,6 @@ func TestBulkReshareHappyFlows13Ops(t *testing.T) {
// load reshare message
reshareMsgBytes, err := os.ReadFile("./output/reshare.txt")
require.NoError(t, err)
hash, err := hex.DecodeString(strings.TrimPrefix(string(reshareMsgBytes), "0x"))
require.NoError(t, err)

// sign reshare message
jsonBytes, err := os.ReadFile("./stubs/UTC--2024-06-14T14-05-12.366668334Z--dcc846fa10c7cfce9e6eb37e06ed93b666cfc5e9")
Expand All @@ -677,7 +667,7 @@ func TestBulkReshareHappyFlows13Ops(t *testing.T) {
require.NoError(t, err)
sk, err := keystore.DecryptKey(jsonBytes, string(keyStorePassword))
require.NoError(t, err)
signature, err := SignHash(hash, sk.PrivateKey)
signature, err := SignHash(string(reshareMsgBytes), sk.PrivateKey)
require.NoError(t, err)

args := []string{"reshare",
Expand Down Expand Up @@ -726,27 +716,3 @@ func TestBulkReshareHappyFlows13Ops(t *testing.T) {
srv.HttpSrv.Close()
}
}

// NOTE: Example below how to generate EOA signature

// func TestSignReshare(t *testing.T) {
// msg_path := "../examples/initiator/output/reshare.txt"
// sk_path := "../examples/initiator/UTC--2024-06-14T14-05-12.366668334Z--dcc846fa10c7cfce9e6eb37e06ed93b666cfc5e9"
// password_path := "../examples/initiator/password"

// msgBytes, err := os.ReadFile(msg_path)
// require.NoError(t, err)
// reshareMsg := make([]*wire.ReshareMessage, 0)
// err = json.Unmarshal(msgBytes, &reshareMsg)
// require.NoError(t, err)

// jsonBytes, err := os.ReadFile(sk_path)
// require.NoError(t, err)
// keyStorePassword, err := os.ReadFile(filepath.Clean(password_path))
// require.NoError(t, err)
// sk, err := keystore.DecryptKey(jsonBytes, string(keyStorePassword))
// require.NoError(t, err)
// signature, err := SignReshare(reshareMsg, sk.PrivateKey)
// require.NoError(t, err)
// t.Log(signature)
// }
Loading

0 comments on commit 9ca6c05

Please sign in to comment.