diff --git a/core/types/suave_structs.go b/core/types/suave_structs.go index eaba115e6c..8bd62201f4 100755 --- a/core/types/suave_structs.go +++ b/core/types/suave_structs.go @@ -1,5 +1,5 @@ // Code generated by suave/gen. DO NOT EDIT. -// Hash: aca9d97ce0be5bb3637b3f1bab2aeda459891800e3d1071a469b8ea4309b5531 +// Hash: 40fc861438d8634a16c81f5a373c54f4e760944ed185a10b66a7bc7e6424645d package types import "github.com/ethereum/go-ethereum/common" diff --git a/core/vm/contracts_suave.go b/core/vm/contracts_suave.go index 5f82b2e98a..ca9449d265 100644 --- a/core/vm/contracts_suave.go +++ b/core/vm/contracts_suave.go @@ -1,12 +1,15 @@ package vm import ( + "crypto/rand" "fmt" + "math/big" "strings" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" suave "github.com/ethereum/go-ethereum/suave/core" @@ -29,13 +32,13 @@ func (b *suaveRuntime) confidentialInputs() ([]byte, error) { /* Confidential store precompiles */ -func (b *suaveRuntime) confidentialStore(bidId types.BidId, key string, data []byte) error { - bid, err := b.suaveContext.Backend.ConfidentialStore.FetchBidById(bidId) +func (b *suaveRuntime) confidentialStore(bidID types.BidId, key string, data []byte) error { + bid, err := b.suaveContext.Backend.ConfidentialStore.FetchBidById(bidID) if err != nil { return suave.ErrBidNotFound } - log.Info("confStore", "bidId", bidId, "key", key) + log.Info("confStore", "bidId", bidID, "key", key) caller, err := checkIsPrecompileCallAllowed(b.suaveContext, confidentialStoreAddr, bid) if err != nil { @@ -46,7 +49,7 @@ func (b *suaveRuntime) confidentialStore(bidId types.BidId, key string, data []b confStorePrecompileStoreMeter.Mark(int64(len(data))) } - _, err = b.suaveContext.Backend.ConfidentialStore.Store(bidId, caller, key, data) + _, err = b.suaveContext.Backend.ConfidentialStore.Store(bidID, caller, key, data) if err != nil { return err } @@ -54,8 +57,8 @@ func (b *suaveRuntime) confidentialStore(bidId types.BidId, key string, data []b return nil } -func (b *suaveRuntime) confidentialRetrieve(bidId types.BidId, key string) ([]byte, error) { - bid, err := b.suaveContext.Backend.ConfidentialStore.FetchBidById(bidId) +func (b *suaveRuntime) confidentialRetrieve(bidID types.BidId, key string) ([]byte, error) { + bid, err := b.suaveContext.Backend.ConfidentialStore.FetchBidById(bidID) if err != nil { return nil, suave.ErrBidNotFound } @@ -65,7 +68,7 @@ func (b *suaveRuntime) confidentialRetrieve(bidId types.BidId, key string) ([]by return nil, err } - data, err := b.suaveContext.Backend.ConfidentialStore.Retrieve(bidId, caller, key) + data, err := b.suaveContext.Backend.ConfidentialStore.Retrieve(bidID, caller, key) if err != nil { return []byte(err.Error()), err } @@ -109,6 +112,28 @@ func (b *suaveRuntime) fetchBids(targetBlock uint64, namespace string) ([]types. return bids, nil } +func (b *suaveRuntime) randomUint() (*big.Int, error) { + maxU256 := new(big.Int) + maxU256.SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) + num, err := rand.Int(rand.Reader, maxU256) + if err != nil { + return nil, err + } + return num, nil +} + +func (b *suaveRuntime) secp256k1Sign(msg, key []byte) ([]byte, error) { + return secp256k1.Sign(msg, key) +} + +func (b *suaveRuntime) secp256k1RecoverPubkey(msg, sig []byte) ([]byte, error) { + return secp256k1.RecoverPubkey(msg, sig) +} + +func (b *suaveRuntime) secp256k1VerifySignature(pubkey, msg, sig []byte) (bool, error) { + return secp256k1.VerifySignature(pubkey, msg, sig), nil +} + func mustParseAbi(data string) abi.ABI { inoutAbi, err := abi.JSON(strings.NewReader(data)) if err != nil { diff --git a/core/vm/contracts_suave_runtime_adapter.go b/core/vm/contracts_suave_runtime_adapter.go index 0f63519a78..54ba6c7153 100644 --- a/core/vm/contracts_suave_runtime_adapter.go +++ b/core/vm/contracts_suave_runtime_adapter.go @@ -1,5 +1,5 @@ // Code generated by suave/gen. DO NOT EDIT. -// Hash: aca9d97ce0be5bb3637b3f1bab2aeda459891800e3d1071a469b8ea4309b5531 +// Hash: 40fc861438d8634a16c81f5a373c54f4e760944ed185a10b66a7bc7e6424645d package vm import ( @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/suave/artifacts" "github.com/mitchellh/mapstructure" + "math/big" ) var ( @@ -26,6 +27,10 @@ type SuaveRuntime interface { fetchBids(cond uint64, namespace string) ([]types.Bid, error) fillMevShareBundle(bidId types.BidId) ([]byte, error) newBid(decryptionCondition uint64, allowedPeekers []common.Address, allowedStores []common.Address, bidType string) (types.Bid, error) + randomUint() (*big.Int, error) + secp256k1RecoverPubkey(_msg []byte, _sig []byte) ([]byte, error) + secp256k1Sign(_prvkey []byte, _hash []byte) ([]byte, error) + secp256k1VerifySignature(_pubkey []byte, _msg []byte, signature []byte) (bool, error) signEthTransaction(txn []byte, chainId string, signingKey string) ([]byte, error) simulateBundle(bundleData []byte) (uint64, error) submitBundleJsonRPC(url string, method string, params []byte) ([]byte, error) @@ -42,6 +47,10 @@ var ( fetchBidsAddr = common.HexToAddress("0x0000000000000000000000000000000042030001") fillMevShareBundleAddr = common.HexToAddress("0x0000000000000000000000000000000043200001") newBidAddr = common.HexToAddress("0x0000000000000000000000000000000042030000") + randomUintAddr = common.HexToAddress("0x00000000000000000000000000000000F00bA777") + secp256k1RecoverPubkeyAddr = common.HexToAddress("0x9000000000000000000000000000000000000002") + secp256k1SignAddr = common.HexToAddress("0x9000000000000000000000000000000000000001") + secp256k1VerifySignatureAddr = common.HexToAddress("0x9000000000000000000000000000000000000003") signEthTransactionAddr = common.HexToAddress("0x0000000000000000000000000000000040100001") simulateBundleAddr = common.HexToAddress("0x0000000000000000000000000000000042100000") submitBundleJsonRPCAddr = common.HexToAddress("0x0000000000000000000000000000000043000001") @@ -49,7 +58,7 @@ var ( ) var addrList = []common.Address{ - buildEthBlockAddr, confidentialInputsAddr, confidentialRetrieveAddr, confidentialStoreAddr, ethcallAddr, extractHintAddr, fetchBidsAddr, fillMevShareBundleAddr, newBidAddr, signEthTransactionAddr, simulateBundleAddr, submitBundleJsonRPCAddr, submitEthBlockBidToRelayAddr, + buildEthBlockAddr, confidentialInputsAddr, confidentialRetrieveAddr, confidentialStoreAddr, ethcallAddr, extractHintAddr, fetchBidsAddr, fillMevShareBundleAddr, newBidAddr, randomUintAddr, secp256k1RecoverPubkeyAddr, secp256k1SignAddr, secp256k1VerifySignatureAddr, signEthTransactionAddr, simulateBundleAddr, submitBundleJsonRPCAddr, submitEthBlockBidToRelayAddr, } type SuaveRuntimeAdapter struct { @@ -85,6 +94,18 @@ func (b *SuaveRuntimeAdapter) run(addr common.Address, input []byte) ([]byte, er case newBidAddr: return b.newBid(input) + case randomUintAddr: + return b.randomUint(input) + + case secp256k1RecoverPubkeyAddr: + return b.secp256k1RecoverPubkey(input) + + case secp256k1SignAddr: + return b.secp256k1Sign(input) + + case secp256k1VerifySignatureAddr: + return b.secp256k1VerifySignature(input) + case signEthTransactionAddr: return b.signEthTransaction(input) @@ -457,6 +478,162 @@ func (b *SuaveRuntimeAdapter) newBid(input []byte) (res []byte, err error) { } +func (b *SuaveRuntimeAdapter) randomUint(input []byte) (res []byte, err error) { + var ( + unpacked []interface{} + result []byte + ) + + _ = unpacked + _ = result + + unpacked, err = artifacts.SuaveAbi.Methods["randomUint"].Inputs.Unpack(input) + if err != nil { + err = errFailedToUnpackInput + return + } + + var () + + var ( + num *big.Int + ) + + if num, err = b.impl.randomUint(); err != nil { + return + } + + result, err = artifacts.SuaveAbi.Methods["randomUint"].Outputs.Pack(num) + if err != nil { + err = errFailedToPackOutput + return + } + return result, nil + +} + +func (b *SuaveRuntimeAdapter) secp256k1RecoverPubkey(input []byte) (res []byte, err error) { + var ( + unpacked []interface{} + result []byte + ) + + _ = unpacked + _ = result + + unpacked, err = artifacts.SuaveAbi.Methods["secp256k1RecoverPubkey"].Inputs.Unpack(input) + if err != nil { + err = errFailedToUnpackInput + return + } + + var ( + _msg []byte + _sig []byte + ) + + _msg = unpacked[0].([]byte) + _sig = unpacked[1].([]byte) + + var ( + pubkey []byte + ) + + if pubkey, err = b.impl.secp256k1RecoverPubkey(_msg, _sig); err != nil { + return + } + + result, err = artifacts.SuaveAbi.Methods["secp256k1RecoverPubkey"].Outputs.Pack(pubkey) + if err != nil { + err = errFailedToPackOutput + return + } + return result, nil + +} + +func (b *SuaveRuntimeAdapter) secp256k1Sign(input []byte) (res []byte, err error) { + var ( + unpacked []interface{} + result []byte + ) + + _ = unpacked + _ = result + + unpacked, err = artifacts.SuaveAbi.Methods["secp256k1Sign"].Inputs.Unpack(input) + if err != nil { + err = errFailedToUnpackInput + return + } + + var ( + _prvkey []byte + _hash []byte + ) + + _prvkey = unpacked[0].([]byte) + _hash = unpacked[1].([]byte) + + var ( + signature []byte + ) + + if signature, err = b.impl.secp256k1Sign(_prvkey, _hash); err != nil { + return + } + + result, err = artifacts.SuaveAbi.Methods["secp256k1Sign"].Outputs.Pack(signature) + if err != nil { + err = errFailedToPackOutput + return + } + return result, nil + +} + +func (b *SuaveRuntimeAdapter) secp256k1VerifySignature(input []byte) (res []byte, err error) { + var ( + unpacked []interface{} + result []byte + ) + + _ = unpacked + _ = result + + unpacked, err = artifacts.SuaveAbi.Methods["secp256k1VerifySignature"].Inputs.Unpack(input) + if err != nil { + err = errFailedToUnpackInput + return + } + + var ( + _pubkey []byte + _msg []byte + signature []byte + ) + + _pubkey = unpacked[0].([]byte) + _msg = unpacked[1].([]byte) + signature = unpacked[2].([]byte) + + var ( + valid bool + ) + + if valid, err = b.impl.secp256k1VerifySignature(_pubkey, _msg, signature); err != nil { + return + } + + result, err = artifacts.SuaveAbi.Methods["secp256k1VerifySignature"].Outputs.Pack(valid) + if err != nil { + err = errFailedToPackOutput + return + } + return result, nil + +} + func (b *SuaveRuntimeAdapter) signEthTransaction(input []byte) (res []byte, err error) { var ( unpacked []interface{} diff --git a/core/vm/contracts_suave_runtime_adapter_test.go b/core/vm/contracts_suave_runtime_adapter_test.go index 78c17a65c5..f448c3e7d2 100644 --- a/core/vm/contracts_suave_runtime_adapter_test.go +++ b/core/vm/contracts_suave_runtime_adapter_test.go @@ -1,6 +1,7 @@ package vm import ( + "math/big" "testing" "github.com/ethereum/go-ethereum/accounts/abi" @@ -67,6 +68,22 @@ func (m *mockRuntime) submitEthBlockBidToRelay(relayUrl string, builderBid []byt return []byte{0x1}, nil } +func (m *mockRuntime) randomUint() (*big.Int, error) { + return big.NewInt(0x9001), nil +} + +func (m *mockRuntime) secp256k1RecoverPubkey(_msg []byte, _sig []byte) ([]byte, error) { + return []byte{0x1}, nil +} + +func (m *mockRuntime) secp256k1VerifySignature(_msg []byte, _sig []byte, _pubkey []byte) (bool, error) { + return true, nil +} + +func (m *mockRuntime) secp256k1Sign(_msg []byte, _key []byte) ([]byte, error) { + return []byte{0x1}, nil +} + func TestRuntimeAdapter(t *testing.T) { adapter := &SuaveRuntimeAdapter{ impl: &mockRuntime{}, diff --git a/core/vm/contracts_suave_test.go b/core/vm/contracts_suave_test.go index 439c082d64..6255404153 100644 --- a/core/vm/contracts_suave_test.go +++ b/core/vm/contracts_suave_test.go @@ -2,11 +2,14 @@ package vm import ( "context" + "encoding/hex" "testing" "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/suave/artifacts" suave "github.com/ethereum/go-ethereum/suave/core" "github.com/ethereum/go-ethereum/suave/cstore" "github.com/stretchr/testify/require" @@ -151,3 +154,67 @@ func TestSuave_ConfStoreWorkflow(t *testing.T) { _, err = b.confidentialRetrieve(bid.Id, "key") require.Error(t, err) } + +func TestSuave_secp256k1Methods(t *testing.T) { + b := newTestBackend(t) + + // private key to sign message + privateKey, err := hex.DecodeString("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") + require.NoError(t, err) + + // message to sign + rawMsg, err := hex.DecodeString("5c783139457468657265756d205369676e6564204d6573736167653a74686520726176656e20686173206c616e6465642e") + require.NoError(t, err) + msgHash := crypto.Keccak256Hash(rawMsg) + + // sign the message hash + sig, err := b.secp256k1Sign(msgHash.Bytes(), privateKey) + require.NoError(t, err) + + // test signature + expectedSig, err := hex.DecodeString("a8ffb6c2309a59937caf7ceb5b2c2f8e37c9095099f1128e6e130f2ee762c4d5157febcd0ed6a73fa02dce2330b9d69703675ce667c1d00bf0578864193fdee200") + require.NoError(t, err) + require.Equal(t, sig, expectedSig) + + // recover public key from signature + pubkey, err := b.secp256k1RecoverPubkey(msgHash.Bytes(), sig) + require.NoError(t, err) + + // convert pubkey to address + parsedPubkey, err := crypto.UnmarshalPubkey(pubkey) + require.NoError(t, err) + address := crypto.PubkeyToAddress(*parsedPubkey) + + // test address + expectedAddr := common.HexToAddress("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266") + require.Equal(t, expectedAddr, address) + + // recovery param (v) must be removed from the signature + sig = sig[:64] + // verify that `sig` is signature of the message hash signed by pubkey + valid, err := b.secp256k1VerifySignature(pubkey, msgHash.Bytes(), sig) + require.NoError(t, err) + require.True(t, valid) +} + +func TestSuave_secp256k1Artifacts(t *testing.T) { + // test that the secp256k1 method artifacts are available + _, ok := artifacts.SuaveMethods["secp256k1Sign"] + require.True(t, ok) + + _, ok = artifacts.SuaveMethods["secp256k1RecoverPubkey"] + require.True(t, ok) + + _, ok = artifacts.SuaveMethods["secp256k1VerifySignature"] + require.True(t, ok) + + // test that the secp256k1 methods are available in the abi + _, ok = artifacts.SuaveAbi.Methods["secp256k1Sign"] + require.True(t, ok) + + _, ok = artifacts.SuaveAbi.Methods["secp256k1RecoverPubkey"] + require.True(t, ok) + + _, ok = artifacts.SuaveAbi.Methods["secp256k1VerifySignature"] + require.True(t, ok) +} diff --git a/suave/artifacts/SuaveLib.json b/suave/artifacts/SuaveLib.json index ea8b406777..b0acfa9b05 100644 --- a/suave/artifacts/SuaveLib.json +++ b/suave/artifacts/SuaveLib.json @@ -1 +1 @@ -[{"type":"function","name":"buildEthBlock","inputs":[{"name":"blockArgs","type":"tuple","internalType":"struct Suave.BuildBlockArgs","components":[{"name":"slot","type":"uint64","internalType":"uint64"},{"name":"proposerPubkey","type":"bytes","internalType":"bytes"},{"name":"parent","type":"bytes32","internalType":"bytes32"},{"name":"timestamp","type":"uint64","internalType":"uint64"},{"name":"feeRecipient","type":"address","internalType":"address"},{"name":"gasLimit","type":"uint64","internalType":"uint64"},{"name":"random","type":"bytes32","internalType":"bytes32"},{"name":"withdrawals","type":"tuple[]","internalType":"struct Suave.Withdrawal[]","components":[{"name":"index","type":"uint64","internalType":"uint64"},{"name":"validator","type":"uint64","internalType":"uint64"},{"name":"Address","type":"address","internalType":"address"},{"name":"amount","type":"uint64","internalType":"uint64"}]},{"name":"extra","type":"bytes","internalType":"bytes"}]},{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"},{"name":"output2","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialInputs","outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialRetrieve","inputs":[{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"key","type":"string","internalType":"string"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialStore","inputs":[{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"key","type":"string","internalType":"string"},{"name":"data1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"ethcall","inputs":[{"name":"contractAddr","type":"address","internalType":"address"},{"name":"input1","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"extractHint","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"fetchBids","inputs":[{"name":"cond","type":"uint64","internalType":"uint64"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"bid","type":"tuple[]","internalType":"struct Suave.Bid[]","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"version","type":"string","internalType":"string"}]}]},{"type":"function","name":"fillMevShareBundle","inputs":[{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"}],"outputs":[{"name":"encodedBundle","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"newBid","inputs":[{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"bidType","type":"string","internalType":"string"}],"outputs":[{"name":"bid","type":"tuple","internalType":"struct Suave.Bid","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"version","type":"string","internalType":"string"}]}]},{"type":"function","name":"signEthTransaction","inputs":[{"name":"txn","type":"bytes","internalType":"bytes"},{"name":"chainId","type":"string","internalType":"string"},{"name":"signingKey","type":"string","internalType":"string"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"simulateBundle","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"uint64","internalType":"uint64"}]},{"type":"function","name":"submitBundleJsonRPC","inputs":[{"name":"url","type":"string","internalType":"string"},{"name":"method","type":"string","internalType":"string"},{"name":"params","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"submitEthBlockBidToRelay","inputs":[{"name":"relayUrl","type":"string","internalType":"string"},{"name":"builderBid","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]}] \ No newline at end of file +[{"type":"function","name":"buildEthBlock","inputs":[{"name":"blockArgs","type":"tuple","internalType":"struct Suave.BuildBlockArgs","components":[{"name":"slot","type":"uint64","internalType":"uint64"},{"name":"proposerPubkey","type":"bytes","internalType":"bytes"},{"name":"parent","type":"bytes32","internalType":"bytes32"},{"name":"timestamp","type":"uint64","internalType":"uint64"},{"name":"feeRecipient","type":"address","internalType":"address"},{"name":"gasLimit","type":"uint64","internalType":"uint64"},{"name":"random","type":"bytes32","internalType":"bytes32"},{"name":"withdrawals","type":"tuple[]","internalType":"struct Suave.Withdrawal[]","components":[{"name":"index","type":"uint64","internalType":"uint64"},{"name":"validator","type":"uint64","internalType":"uint64"},{"name":"Address","type":"address","internalType":"address"},{"name":"amount","type":"uint64","internalType":"uint64"}]},{"name":"extra","type":"bytes","internalType":"bytes"}]},{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"},{"name":"output2","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialInputs","outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialRetrieve","inputs":[{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"key","type":"string","internalType":"string"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialStore","inputs":[{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"key","type":"string","internalType":"string"},{"name":"data1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"ethcall","inputs":[{"name":"contractAddr","type":"address","internalType":"address"},{"name":"input1","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"extractHint","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"fetchBids","inputs":[{"name":"cond","type":"uint64","internalType":"uint64"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"bid","type":"tuple[]","internalType":"struct Suave.Bid[]","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"version","type":"string","internalType":"string"}]}]},{"type":"function","name":"fillMevShareBundle","inputs":[{"name":"bidId","type":"bytes16","internalType":"struct Suave.BidId"}],"outputs":[{"name":"encodedBundle","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"newBid","inputs":[{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"bidType","type":"string","internalType":"string"}],"outputs":[{"name":"bid","type":"tuple","internalType":"struct Suave.Bid","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.BidId"},{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"version","type":"string","internalType":"string"}]}]},{"type":"function","name":"randomUint","outputs":[{"name":"num","type":"uint256","internalType":"uint256"}]},{"type":"function","name":"secp256k1RecoverPubkey","inputs":[{"name":"_msg","type":"bytes","internalType":"bytes"},{"name":"_sig","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"pubkey","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"secp256k1Sign","inputs":[{"name":"_prvkey","type":"bytes","internalType":"bytes"},{"name":"_hash","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"signature","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"secp256k1VerifySignature","inputs":[{"name":"_pubkey","type":"bytes","internalType":"bytes"},{"name":"_msg","type":"bytes","internalType":"bytes"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"valid","type":"bool","internalType":"bool"}]},{"type":"function","name":"signEthTransaction","inputs":[{"name":"txn","type":"bytes","internalType":"bytes"},{"name":"chainId","type":"string","internalType":"string"},{"name":"signingKey","type":"string","internalType":"string"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"simulateBundle","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"uint64","internalType":"uint64"}]},{"type":"function","name":"submitBundleJsonRPC","inputs":[{"name":"url","type":"string","internalType":"string"},{"name":"method","type":"string","internalType":"string"},{"name":"params","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"submitEthBlockBidToRelay","inputs":[{"name":"relayUrl","type":"string","internalType":"string"},{"name":"builderBid","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"output1","type":"bytes","internalType":"bytes"}]}] \ No newline at end of file diff --git a/suave/artifacts/addresses.go b/suave/artifacts/addresses.go index ead92b194e..a86666dd7d 100644 --- a/suave/artifacts/addresses.go +++ b/suave/artifacts/addresses.go @@ -1,5 +1,5 @@ // Code generated by suave/gen. DO NOT EDIT. -// Hash: aca9d97ce0be5bb3637b3f1bab2aeda459891800e3d1071a469b8ea4309b5531 +// Hash: 40fc861438d8634a16c81f5a373c54f4e760944ed185a10b66a7bc7e6424645d package artifacts import ( @@ -17,6 +17,10 @@ var ( fetchBidsAddr = common.HexToAddress("0x0000000000000000000000000000000042030001") fillMevShareBundleAddr = common.HexToAddress("0x0000000000000000000000000000000043200001") newBidAddr = common.HexToAddress("0x0000000000000000000000000000000042030000") + randomUintAddr = common.HexToAddress("0x00000000000000000000000000000000F00bA777") + secp256k1RecoverPubkeyAddr = common.HexToAddress("0x9000000000000000000000000000000000000002") + secp256k1SignAddr = common.HexToAddress("0x9000000000000000000000000000000000000001") + secp256k1VerifySignatureAddr = common.HexToAddress("0x9000000000000000000000000000000000000003") signEthTransactionAddr = common.HexToAddress("0x0000000000000000000000000000000040100001") simulateBundleAddr = common.HexToAddress("0x0000000000000000000000000000000042100000") submitBundleJsonRPCAddr = common.HexToAddress("0x0000000000000000000000000000000043000001") @@ -33,6 +37,10 @@ var SuaveMethods = map[string]common.Address{ "fetchBids": fetchBidsAddr, "fillMevShareBundle": fillMevShareBundleAddr, "newBid": newBidAddr, + "randomUint": randomUintAddr, + "secp256k1RecoverPubkey": secp256k1RecoverPubkeyAddr, + "secp256k1Sign": secp256k1SignAddr, + "secp256k1VerifySignature": secp256k1VerifySignatureAddr, "signEthTransaction": signEthTransactionAddr, "simulateBundle": simulateBundleAddr, "submitBundleJsonRPC": submitBundleJsonRPCAddr, @@ -59,6 +67,14 @@ func PrecompileAddressToName(addr common.Address) string { return "fillMevShareBundle" case newBidAddr: return "newBid" + case randomUintAddr: + return "randomUint" + case secp256k1RecoverPubkeyAddr: + return "secp256k1RecoverPubkey" + case secp256k1SignAddr: + return "secp256k1Sign" + case secp256k1VerifySignatureAddr: + return "secp256k1VerifySignature" case signEthTransactionAddr: return "signEthTransaction" case simulateBundleAddr: diff --git a/suave/gen/main.go b/suave/gen/main.go index 468bea8904..693d28a799 100644 --- a/suave/gen/main.go +++ b/suave/gen/main.go @@ -8,6 +8,7 @@ import ( "fmt" goformat "go/format" "html/template" + "os" "os/exec" "path/filepath" @@ -229,6 +230,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/suave/artifacts" "github.com/mitchellh/mapstructure" + "math/big" ) var ( diff --git a/suave/gen/suave_spec.yaml b/suave/gen/suave_spec.yaml index 99abd10dee..44054fb349 100644 --- a/suave/gen/suave_spec.yaml +++ b/suave/gen/suave_spec.yaml @@ -199,3 +199,53 @@ functions: fields: - name: encodedBundle type: bytes + - name: randomUint + address: "0x00000000000000000000000000000000F00bA777" + isConfidential: true + input: + output: + packed: false + fields: + - name: num + type: uint256 + - name: secp256k1Sign + address: "0x9000000000000000000000000000000000000001" + isConfidential: true + input: + - name: _prvkey + type: bytes + - name: _hash + type: bytes + output: + packed: false + fields: + - name: signature + type: bytes + - name: secp256k1RecoverPubkey + address: "0x9000000000000000000000000000000000000002" + isConfidential: true + input: + - name: _msg + type: bytes + - name: _sig + type: bytes + output: + packed: false + fields: + - name: pubkey + type: bytes + - name: secp256k1VerifySignature + address: "0x9000000000000000000000000000000000000003" + isConfidential: true + input: + - name: _pubkey + type: bytes + - name: _msg + type: bytes + - name: signature + type: bytes + output: + packed: false + fields: + - name: valid + type: bool diff --git a/suave/sol/libraries/Suave.sol b/suave/sol/libraries/Suave.sol index 3522bbc948..ed343defab 100644 --- a/suave/sol/libraries/Suave.sol +++ b/suave/sol/libraries/Suave.sol @@ -56,6 +56,14 @@ library Suave { address public constant NEW_BID = 0x0000000000000000000000000000000042030000; + address public constant RANDOM_UINT = 0x00000000000000000000000000000000F00bA777; + + address public constant SECP256K1_RECOVER_PUBKEY = 0x9000000000000000000000000000000000000002; + + address public constant SECP256K1_SIGN = 0x9000000000000000000000000000000000000001; + + address public constant SECP256K1_VERIFY_SIGNATURE = 0x9000000000000000000000000000000000000003; + address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001; address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000; @@ -169,6 +177,50 @@ library Suave { return abi.decode(data, (Bid)); } + function randomUint() internal view returns (uint256) { + require(isConfidential()); + (bool success, bytes memory data) = RANDOM_UINT.staticcall(abi.encode()); + if (!success) { + revert PeekerReverted(RANDOM_UINT, data); + } + + return abi.decode(data, (uint256)); + } + + function secp256k1RecoverPubkey(bytes memory _msg, bytes memory _sig) internal view returns (bytes memory) { + require(isConfidential()); + (bool success, bytes memory data) = SECP256K1_RECOVER_PUBKEY.staticcall(abi.encode(_msg, _sig)); + if (!success) { + revert PeekerReverted(SECP256K1_RECOVER_PUBKEY, data); + } + + return abi.decode(data, (bytes)); + } + + function secp256k1Sign(bytes memory _prvkey, bytes memory _hash) internal view returns (bytes memory) { + require(isConfidential()); + (bool success, bytes memory data) = SECP256K1_SIGN.staticcall(abi.encode(_prvkey, _hash)); + if (!success) { + revert PeekerReverted(SECP256K1_SIGN, data); + } + + return abi.decode(data, (bytes)); + } + + function secp256k1VerifySignature(bytes memory _pubkey, bytes memory _msg, bytes memory signature) + internal + view + returns (bool) + { + require(isConfidential()); + (bool success, bytes memory data) = SECP256K1_VERIFY_SIGNATURE.staticcall(abi.encode(_pubkey, _msg, signature)); + if (!success) { + revert PeekerReverted(SECP256K1_VERIFY_SIGNATURE, data); + } + + return abi.decode(data, (bool)); + } + function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey) internal view diff --git a/suave/sol/libraries/SuaveForge.sol b/suave/sol/libraries/SuaveForge.sol index 54019706d1..e1b9b84051 100644 --- a/suave/sol/libraries/SuaveForge.sol +++ b/suave/sol/libraries/SuaveForge.sol @@ -101,6 +101,34 @@ library SuaveForge { return abi.decode(data, (Suave.Bid)); } + function randomUint() internal view returns (uint256) { + bytes memory data = forgeIt("0x00000000000000000000000000000000F00bA777", abi.encode()); + + return abi.decode(data, (uint256)); + } + + function secp256k1RecoverPubkey(bytes memory _msg, bytes memory _sig) internal view returns (bytes memory) { + bytes memory data = forgeIt("0x9000000000000000000000000000000000000002", abi.encode(_msg, _sig)); + + return abi.decode(data, (bytes)); + } + + function secp256k1Sign(bytes memory _prvkey, bytes memory _hash) internal view returns (bytes memory) { + bytes memory data = forgeIt("0x9000000000000000000000000000000000000001", abi.encode(_prvkey, _hash)); + + return abi.decode(data, (bytes)); + } + + function secp256k1VerifySignature(bytes memory _pubkey, bytes memory _msg, bytes memory signature) + internal + view + returns (bool) + { + bytes memory data = forgeIt("0x9000000000000000000000000000000000000003", abi.encode(_pubkey, _msg, signature)); + + return abi.decode(data, (bool)); + } + function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey) internal view