From b56818c4a00ddbe978fd8a3394bd0962a98761e4 Mon Sep 17 00:00:00 2001 From: connorwstein Date: Mon, 23 Sep 2024 18:09:30 -0400 Subject: [PATCH] Separate module for ledger signing --- go.mod | 2 +- go.sum | 1 + tools/proposal/mcms/proposal.go | 9 +++ tools/proposal/mcms/utils.go | 71 ++++++++++++++++++++ tools/proposal/timelock/mcm_with_timelock.go | 9 +++ tools/signing/go.mod | 28 ++++++++ tools/signing/go.sum | 34 ++++++++++ tools/signing/sign_ledger.go | 4 -- tools/signing/sign_plain_key.go | 48 ------------- 9 files changed, 153 insertions(+), 53 deletions(-) create mode 100644 tools/signing/go.mod create mode 100644 tools/signing/go.sum delete mode 100644 tools/signing/sign_plain_key.go diff --git a/go.mod b/go.mod index cc501c3..d0f2661 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/smartcontractkit/ccip-owner-contracts go 1.22 require ( - github.com/ethereum/go-ethereum v1.14.7 + github.com/ethereum/go-ethereum v1.13.8 github.com/joho/godotenv v1.5.1 github.com/smartcontractkit/chain-selectors v1.0.23 github.com/spf13/cobra v1.5.0 diff --git a/go.sum b/go.sum index b6b3c68..24b5969 100644 --- a/go.sum +++ b/go.sum @@ -111,6 +111,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/ethereum/go-ethereum v1.14.7 h1:EHpv3dE8evQmpVEQ/Ne2ahB06n2mQptdwqaMNhAT29g= github.com/ethereum/go-ethereum v1.14.7/go.mod h1:Mq0biU2jbdmKSZoqOj29017ygFrMnB5/Rifwp980W4o= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= diff --git a/tools/proposal/mcms/proposal.go b/tools/proposal/mcms/proposal.go index a76bcc7..82d8dad 100644 --- a/tools/proposal/mcms/proposal.go +++ b/tools/proposal/mcms/proposal.go @@ -60,6 +60,15 @@ func NewProposal( return &proposal, nil } +func NewProposalFromFile(filePath string) (*MCMSProposal, error) { + var out MCMSProposal + err := FromFile(filePath, &out) + if err != nil { + return nil, err + } + return &out, nil +} + func (m *MCMSProposal) Validate() error { if m.Version == "" { return &errors.ErrInvalidVersion{ diff --git a/tools/proposal/mcms/utils.go b/tools/proposal/mcms/utils.go index 8b56809..acd7fc9 100644 --- a/tools/proposal/mcms/utils.go +++ b/tools/proposal/mcms/utils.go @@ -1,12 +1,16 @@ package mcms import ( + "crypto/ecdsa" + "encoding/json" "fmt" + "os" "strings" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/smartcontractkit/ccip-owner-contracts/tools/configwrappers" "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" ) @@ -78,3 +82,70 @@ func ABIDecode(abiStr string, data []byte) ([]interface{}, error) { } return inAbi.Unpack("method", data) } + +// Generic function to read a file and unmarshal its contents into the provided struct +func FromFile(filePath string, out interface{}) error { + // Load file from path + fileBytes, err := os.ReadFile(filePath) + if err != nil { + return err + } + + // Unmarshal JSON into the provided struct + err = json.Unmarshal(fileBytes, out) + if err != nil { + return err + } + + return nil +} + +func WriteProposalToFile(proposal interface{}, filePath string) error { + proposalBytes, err := json.Marshal(proposal) + if err != nil { + return err + } + + err = os.WriteFile(filePath, proposalBytes, 0644) + if err != nil { + return err + } + + return nil +} + +// Just run this locally to sign from the ledger. +func SignPlainKey(privateKey *ecdsa.PrivateKey, proposal MCMSProposal) error { + // Validate proposal + err := proposal.Validate() + if err != nil { + return err + } + + executor, err := proposal.ToExecutor(false) // TODO: pass in a real backend + if err != nil { + return err + } + + // Get the signing hash + payload, err := executor.SigningHash() + if err != nil { + return err + } + + // Sign the payload + sig, err := crypto.Sign(payload.Bytes(), privateKey) + if err != nil { + return err + } + + // Unmarshal signature + sigObj, err := NewSignatureFromBytes(sig) + if err != nil { + return err + } + + // Add signature to proposal + proposal.AddSignature(sigObj) + return nil +} diff --git a/tools/proposal/timelock/mcm_with_timelock.go b/tools/proposal/timelock/mcm_with_timelock.go index e1b2aa6..adc8af8 100644 --- a/tools/proposal/timelock/mcm_with_timelock.go +++ b/tools/proposal/timelock/mcm_with_timelock.go @@ -70,6 +70,15 @@ func NewMCMSWithTimelockProposal( return &proposal, nil } +func NewMCMSWithTimelockProposalFromFile(filePath string) (*MCMSWithTimelockProposal, error) { + var out MCMSWithTimelockProposal + err := mcms.FromFile(filePath, &out) + if err != nil { + return nil, err + } + return &out, nil +} + func (m *MCMSWithTimelockProposal) Validate() error { if m.Version == "" { return &errors.ErrInvalidVersion{ diff --git a/tools/signing/go.mod b/tools/signing/go.mod new file mode 100644 index 0000000..c3a9ffc --- /dev/null +++ b/tools/signing/go.mod @@ -0,0 +1,28 @@ +module github.com/smartcontractkit/ccip-owner-contracts/tools/signing + +go 1.22.2 + +// Required for ledger library. +// NOTE MUST BE > 1.14 for this fix +// https://github.com/ethereum/go-ethereum/pull/28945 +require ( + github.com/ethereum/go-ethereum v1.14.7 + github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240919155713-f4bf4ae0b9c6 +) + +require ( + github.com/bits-and-blooms/bitset v1.10.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/ethereum/c-kzg-4844 v1.0.0 // indirect + github.com/holiman/uint256 v1.3.0 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/supranational/blst v0.3.11 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.20.0 // indirect + rsc.io/tmplfunc v0.0.3 // indirect +) diff --git a/tools/signing/go.sum b/tools/signing/go.sum new file mode 100644 index 0000000..06127a7 --- /dev/null +++ b/tools/signing/go.sum @@ -0,0 +1,34 @@ +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= +github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.14.7 h1:EHpv3dE8evQmpVEQ/Ne2ahB06n2mQptdwqaMNhAT29g= +github.com/ethereum/go-ethereum v1.14.7/go.mod h1:Mq0biU2jbdmKSZoqOj29017ygFrMnB5/Rifwp980W4o= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= +github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240919155713-f4bf4ae0b9c6/go.mod h1:nlRI0m23HFMAHf7cKYdE58mPbXsTyY1y3ZLJxnuuoCM= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/tools/signing/sign_ledger.go b/tools/signing/sign_ledger.go index a676418..c3f3c10 100644 --- a/tools/signing/sign_ledger.go +++ b/tools/signing/sign_ledger.go @@ -1,10 +1,6 @@ package signing import ( - - // NOTE MUST BE > 1.14 for this fix - // https://github.com/ethereum/go-ethereum/pull/28945 - "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal" "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/mcms" diff --git a/tools/signing/sign_plain_key.go b/tools/signing/sign_plain_key.go deleted file mode 100644 index 56ba684..0000000 --- a/tools/signing/sign_plain_key.go +++ /dev/null @@ -1,48 +0,0 @@ -package signing - -import ( - "crypto/ecdsa" - - // NOTE MUST BE > 1.14 for this fix - // https://github.com/ethereum/go-ethereum/pull/28945 - - "github.com/ethereum/go-ethereum/crypto" - "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal" - "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/mcms" -) - -// Just run this locally to sign from the ledger. -func SignPlainKey(privateKey *ecdsa.PrivateKey, proposal proposal.Proposal) error { - // Validate proposal - err := proposal.Validate() - if err != nil { - return err - } - - executor, err := proposal.ToExecutor(false) // TODO: pass in a real backend - if err != nil { - return err - } - - // Get the signing hash - payload, err := executor.SigningHash() - if err != nil { - return err - } - - // Sign the payload - sig, err := crypto.Sign(payload.Bytes(), privateKey) - if err != nil { - return err - } - - // Unmarshal signature - sigObj, err := mcms.NewSignatureFromBytes(sig) - if err != nil { - return err - } - - // Add signature to proposal - proposal.AddSignature(sigObj) - return nil -}