From fef4a56ee9153102da27077aef4840af4b3d37c6 Mon Sep 17 00:00:00 2001 From: Nil Medvedev Date: Mon, 5 Feb 2024 10:10:12 +0100 Subject: [PATCH] Feat: private key gen precompile (#182) * add privateKeyGen precompile * add a simple test for privateKeyGen precompile * fix interface --- core/types/suave_structs.go | 2 +- core/vm/contracts_suave_eth.go | 10 +++++ core/vm/contracts_suave_runtime_adapter.go | 43 ++++++++++++++++++- .../contracts_suave_runtime_adapter_test.go | 4 ++ suave/artifacts/SuaveLib.json | 2 +- suave/artifacts/addresses.go | 6 ++- suave/e2e/workflow_test.go | 40 ++++++++++++++++- suave/gen/suave_spec.yaml | 8 ++++ suave/sol/libraries/Suave.sol | 11 +++++ 9 files changed, 119 insertions(+), 7 deletions(-) diff --git a/core/types/suave_structs.go b/core/types/suave_structs.go index c40fea7da..a6fd3923e 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: c60f303834fbdbbd940aae7cb3679cf3755a25f7384f1052c20bf6c38d9a0451 +// Hash: d9d97c22b26e66933a342049426d92ca36f2271b832551dedcb93417d9798c54 package types import "github.com/ethereum/go-ethereum/common" diff --git a/core/vm/contracts_suave_eth.go b/core/vm/contracts_suave_eth.go index 90e9d3d17..1c9a5d650 100644 --- a/core/vm/contracts_suave_eth.go +++ b/core/vm/contracts_suave_eth.go @@ -2,6 +2,7 @@ package vm import ( "context" + "encoding/hex" "encoding/json" "fmt" "math/big" @@ -277,6 +278,15 @@ func (b *suaveRuntime) buildEthBlock(blockArgs types.BuildBlockArgs, dataID type return bidBytes, envelopeBytes, nil } +func (b *suaveRuntime) privateKeyGen() (string, error) { + sk, err := crypto.GenerateKey() + if err != nil { + return "", fmt.Errorf("could not generate new a private key: %w", err) + } + + return hex.EncodeToString(crypto.FromECDSA(sk)), nil +} + func (b *suaveRuntime) submitEthBlockToRelay(relayUrl string, builderDataRecordJson []byte) ([]byte, error) { endpoint := relayUrl + "/relay/v1/builder/blocks" diff --git a/core/vm/contracts_suave_runtime_adapter.go b/core/vm/contracts_suave_runtime_adapter.go index 3463fd6bc..5aa80dba9 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: c60f303834fbdbbd940aae7cb3679cf3755a25f7384f1052c20bf6c38d9a0451 +// Hash: d9d97c22b26e66933a342049426d92ca36f2271b832551dedcb93417d9798c54 package vm import ( @@ -28,6 +28,7 @@ type SuaveRuntime interface { fillMevShareBundle(dataId types.DataId) ([]byte, error) newBuilder() (string, error) newDataRecord(decryptionCondition uint64, allowedPeekers []common.Address, allowedStores []common.Address, dataType string) (types.DataRecord, error) + privateKeyGen() (string, error) signEthTransaction(txn []byte, chainId string, signingKey string) ([]byte, error) signMessage(digest []byte, signingKey string) ([]byte, error) simulateBundle(bundleData []byte) (uint64, error) @@ -48,6 +49,7 @@ var ( fillMevShareBundleAddr = common.HexToAddress("0x0000000000000000000000000000000043200001") newBuilderAddr = common.HexToAddress("0x0000000000000000000000000000000053200001") newDataRecordAddr = common.HexToAddress("0x0000000000000000000000000000000042030000") + privateKeyGenAddr = common.HexToAddress("0x0000000000000000000000000000000053200003") signEthTransactionAddr = common.HexToAddress("0x0000000000000000000000000000000040100001") signMessageAddr = common.HexToAddress("0x0000000000000000000000000000000040100003") simulateBundleAddr = common.HexToAddress("0x0000000000000000000000000000000042100000") @@ -57,7 +59,7 @@ var ( ) var addrList = []common.Address{ - buildEthBlockAddr, confidentialInputsAddr, confidentialRetrieveAddr, confidentialStoreAddr, doHTTPRequestAddr, ethcallAddr, extractHintAddr, fetchDataRecordsAddr, fillMevShareBundleAddr, newBuilderAddr, newDataRecordAddr, signEthTransactionAddr, signMessageAddr, simulateBundleAddr, simulateTransactionAddr, submitBundleJsonRPCAddr, submitEthBlockToRelayAddr, + buildEthBlockAddr, confidentialInputsAddr, confidentialRetrieveAddr, confidentialStoreAddr, doHTTPRequestAddr, ethcallAddr, extractHintAddr, fetchDataRecordsAddr, fillMevShareBundleAddr, newBuilderAddr, newDataRecordAddr, privateKeyGenAddr, signEthTransactionAddr, signMessageAddr, simulateBundleAddr, simulateTransactionAddr, submitBundleJsonRPCAddr, submitEthBlockToRelayAddr, } type SuaveRuntimeAdapter struct { @@ -99,6 +101,9 @@ func (b *SuaveRuntimeAdapter) run(addr common.Address, input []byte) ([]byte, er case newDataRecordAddr: return b.newDataRecord(input) + case privateKeyGenAddr: + return b.privateKeyGen(input) + case signEthTransactionAddr: return b.signEthTransaction(input) @@ -552,6 +557,40 @@ func (b *SuaveRuntimeAdapter) newDataRecord(input []byte) (res []byte, err error } +func (b *SuaveRuntimeAdapter) privateKeyGen(input []byte) (res []byte, err error) { + var ( + unpacked []interface{} + result []byte + ) + + _ = unpacked + _ = result + + unpacked, err = artifacts.SuaveAbi.Methods["privateKeyGen"].Inputs.Unpack(input) + if err != nil { + err = errFailedToUnpackInput + return + } + + var () + + var ( + privateKey string + ) + + if privateKey, err = b.impl.privateKeyGen(); err != nil { + return + } + + result, err = artifacts.SuaveAbi.Methods["privateKeyGen"].Outputs.Pack(privateKey) + 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 9ed29c880..e8d7b06d2 100644 --- a/core/vm/contracts_suave_runtime_adapter_test.go +++ b/core/vm/contracts_suave_runtime_adapter_test.go @@ -83,6 +83,10 @@ func (m *mockRuntime) simulateTransaction(session string, txn []byte) (types.Sim return types.SimulateTransactionResult{}, nil } +func (m *mockRuntime) privateKeyGen() (string, error) { + return "", nil +} + func TestRuntimeAdapter(t *testing.T) { adapter := &SuaveRuntimeAdapter{ impl: &mockRuntime{}, diff --git a/suave/artifacts/SuaveLib.json b/suave/artifacts/SuaveLib.json index 577e67478..b61dceb40 100644 --- a/suave/artifacts/SuaveLib.json +++ b/suave/artifacts/SuaveLib.json @@ -1 +1 @@ -[{"type":"error","name":"PeekerReverted","inputs":[{"name":"addr","type":"address"},{"name":"err","type":"bytes"}]},{"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":"fillPending","type":"bool","internalType":"bool"}]},{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"blockBid","type":"bytes","internalType":"bytes"},{"name":"executionPayload","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialInputs","outputs":[{"name":"confindentialData","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialRetrieve","inputs":[{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"key","type":"string","internalType":"string"}],"outputs":[{"name":"value","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialStore","inputs":[{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"key","type":"string","internalType":"string"},{"name":"value","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"doHTTPRequest","inputs":[{"name":"request","type":"tuple","internalType":"struct Suave.HttpRequest","components":[{"name":"url","type":"string","internalType":"string"},{"name":"method","type":"string","internalType":"string"},{"name":"headers","type":"string[]","internalType":"string[]"},{"name":"body","type":"bytes","internalType":"bytes"},{"name":"withFlashbotsSignature","type":"bool","internalType":"bool"}]}],"outputs":[{"name":"httpResponse","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"ethcall","inputs":[{"name":"contractAddr","type":"address","internalType":"address"},{"name":"input1","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"callOutput","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"extractHint","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"hints","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"fetchDataRecords","inputs":[{"name":"cond","type":"uint64","internalType":"uint64"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"dataRecords","type":"tuple[]","internalType":"struct Suave.DataRecord[]","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.DataId"},{"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":"dataId","type":"bytes16","internalType":"struct Suave.DataId"}],"outputs":[{"name":"encodedBundle","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"newBuilder","outputs":[{"name":"sessionid","type":"string","internalType":"string"}]},{"type":"function","name":"newDataRecord","inputs":[{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"dataType","type":"string","internalType":"string"}],"outputs":[{"name":"dataRecord","type":"tuple","internalType":"struct Suave.DataRecord","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.DataId"},{"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":"signedTxn","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"signMessage","inputs":[{"name":"digest","type":"bytes","internalType":"bytes"},{"name":"signingKey","type":"string","internalType":"string"}],"outputs":[{"name":"signature","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"simulateBundle","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"effectiveGasPrice","type":"uint64","internalType":"uint64"}]},{"type":"function","name":"simulateTransaction","inputs":[{"name":"sessionid","type":"string","internalType":"string"},{"name":"txn","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"simulationResult","type":"tuple","internalType":"struct Suave.SimulateTransactionResult","components":[{"name":"egp","type":"uint64","internalType":"uint64"},{"name":"logs","type":"tuple[]","internalType":"struct Suave.SimulatedLog[]","components":[{"name":"data","type":"bytes","internalType":"bytes"},{"name":"addr","type":"address","internalType":"address"},{"name":"topics","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"success","type":"bool","internalType":"bool"},{"name":"error","type":"string","internalType":"string"}]}]},{"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":"errorMessage","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"submitEthBlockToRelay","inputs":[{"name":"relayUrl","type":"string","internalType":"string"},{"name":"builderBid","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"blockBid","type":"bytes","internalType":"bytes"}]}] \ No newline at end of file +[{"type":"error","name":"PeekerReverted","inputs":[{"name":"addr","type":"address"},{"name":"err","type":"bytes"}]},{"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":"fillPending","type":"bool","internalType":"bool"}]},{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"blockBid","type":"bytes","internalType":"bytes"},{"name":"executionPayload","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialInputs","outputs":[{"name":"confindentialData","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialRetrieve","inputs":[{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"key","type":"string","internalType":"string"}],"outputs":[{"name":"value","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"confidentialStore","inputs":[{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"key","type":"string","internalType":"string"},{"name":"value","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"doHTTPRequest","inputs":[{"name":"request","type":"tuple","internalType":"struct Suave.HttpRequest","components":[{"name":"url","type":"string","internalType":"string"},{"name":"method","type":"string","internalType":"string"},{"name":"headers","type":"string[]","internalType":"string[]"},{"name":"body","type":"bytes","internalType":"bytes"},{"name":"withFlashbotsSignature","type":"bool","internalType":"bool"}]}],"outputs":[{"name":"httpResponse","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"ethcall","inputs":[{"name":"contractAddr","type":"address","internalType":"address"},{"name":"input1","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"callOutput","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"extractHint","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"hints","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"fetchDataRecords","inputs":[{"name":"cond","type":"uint64","internalType":"uint64"},{"name":"namespace","type":"string","internalType":"string"}],"outputs":[{"name":"dataRecords","type":"tuple[]","internalType":"struct Suave.DataRecord[]","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.DataId"},{"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":"dataId","type":"bytes16","internalType":"struct Suave.DataId"}],"outputs":[{"name":"encodedBundle","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"newBuilder","outputs":[{"name":"sessionid","type":"string","internalType":"string"}]},{"type":"function","name":"newDataRecord","inputs":[{"name":"decryptionCondition","type":"uint64","internalType":"uint64"},{"name":"allowedPeekers","type":"address[]","internalType":"address[]"},{"name":"allowedStores","type":"address[]","internalType":"address[]"},{"name":"dataType","type":"string","internalType":"string"}],"outputs":[{"name":"dataRecord","type":"tuple","internalType":"struct Suave.DataRecord","components":[{"name":"id","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"salt","type":"bytes16","internalType":"struct Suave.DataId"},{"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":"privateKeyGen","outputs":[{"name":"privateKey","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":"signedTxn","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"signMessage","inputs":[{"name":"digest","type":"bytes","internalType":"bytes"},{"name":"signingKey","type":"string","internalType":"string"}],"outputs":[{"name":"signature","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"simulateBundle","inputs":[{"name":"bundleData","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"effectiveGasPrice","type":"uint64","internalType":"uint64"}]},{"type":"function","name":"simulateTransaction","inputs":[{"name":"sessionid","type":"string","internalType":"string"},{"name":"txn","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"simulationResult","type":"tuple","internalType":"struct Suave.SimulateTransactionResult","components":[{"name":"egp","type":"uint64","internalType":"uint64"},{"name":"logs","type":"tuple[]","internalType":"struct Suave.SimulatedLog[]","components":[{"name":"data","type":"bytes","internalType":"bytes"},{"name":"addr","type":"address","internalType":"address"},{"name":"topics","type":"bytes32[]","internalType":"bytes32[]"}]},{"name":"success","type":"bool","internalType":"bool"},{"name":"error","type":"string","internalType":"string"}]}]},{"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":"errorMessage","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"submitEthBlockToRelay","inputs":[{"name":"relayUrl","type":"string","internalType":"string"},{"name":"builderBid","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"blockBid","type":"bytes","internalType":"bytes"}]}] \ No newline at end of file diff --git a/suave/artifacts/addresses.go b/suave/artifacts/addresses.go index f07051220..c16eff524 100644 --- a/suave/artifacts/addresses.go +++ b/suave/artifacts/addresses.go @@ -1,5 +1,5 @@ // Code generated by suave/gen. DO NOT EDIT. -// Hash: c60f303834fbdbbd940aae7cb3679cf3755a25f7384f1052c20bf6c38d9a0451 +// Hash: d9d97c22b26e66933a342049426d92ca36f2271b832551dedcb93417d9798c54 package artifacts import ( @@ -19,6 +19,7 @@ var ( fillMevShareBundleAddr = common.HexToAddress("0x0000000000000000000000000000000043200001") newBuilderAddr = common.HexToAddress("0x0000000000000000000000000000000053200001") newDataRecordAddr = common.HexToAddress("0x0000000000000000000000000000000042030000") + privateKeyGenAddr = common.HexToAddress("0x0000000000000000000000000000000053200003") signEthTransactionAddr = common.HexToAddress("0x0000000000000000000000000000000040100001") signMessageAddr = common.HexToAddress("0x0000000000000000000000000000000040100003") simulateBundleAddr = common.HexToAddress("0x0000000000000000000000000000000042100000") @@ -39,6 +40,7 @@ var SuaveMethods = map[string]common.Address{ "fillMevShareBundle": fillMevShareBundleAddr, "newBuilder": newBuilderAddr, "newDataRecord": newDataRecordAddr, + "privateKeyGen": privateKeyGenAddr, "signEthTransaction": signEthTransactionAddr, "signMessage": signMessageAddr, "simulateBundle": simulateBundleAddr, @@ -71,6 +73,8 @@ func PrecompileAddressToName(addr common.Address) string { return "newBuilder" case newDataRecordAddr: return "newDataRecord" + case privateKeyGenAddr: + return "privateKeyGen" case signEthTransactionAddr: return "signEthTransaction" case signMessageAddr: diff --git a/suave/e2e/workflow_test.go b/suave/e2e/workflow_test.go index 1f2b8c963..41f40e9d9 100644 --- a/suave/e2e/workflow_test.go +++ b/suave/e2e/workflow_test.go @@ -315,6 +315,39 @@ func TestSignMessagePrecompile(t *testing.T) { require.Equal(t, crypto.PubkeyToAddress(sk.PublicKey), crypto.PubkeyToAddress(*pubKeyRecovered)) } +func TestPrivateKeyGeneratePrecompile(t *testing.T) { + fr := newFramework(t) + defer fr.Close() + + // function privateKeyGen() string + args, err := artifacts.SuaveAbi.Methods["privateKeyGen"].Inputs.Pack() + require.NoError(t, err) + + gas := hexutil.Uint64(1000000) + var callResult hexutil.Bytes + err = fr.suethSrv.RPCNode().Call(&callResult, "eth_call", setTxArgsDefaults(ethapi.TransactionArgs{ + To: &privateKeyGen, + Gas: &gas, + IsConfidential: true, + Data: (*hexutil.Bytes)(&args), + }), "latest") + requireNoRpcError(t, err) + + // Unpack the call result to get the result of privateKeyGen call + unpackedCallResult, err := artifacts.SuaveAbi.Methods["privateKeyGen"].Outputs.Unpack(callResult) + require.NoError(t, err) + + // Get the generated private key + skGenerated := unpackedCallResult[0].(string) + require.NoError(t, err) + + // Some tests on key validity + skBytes, err := hex.DecodeString(skGenerated) + require.NoError(t, err) + _, err = crypto.ToECDSA(skBytes) + require.NoError(t, err) +} + type HintEvent struct { BidId [16]uint8 `abi:"dataId"` Hint []byte `abi:"hint"` @@ -1479,11 +1512,14 @@ var ( fetchBidsAddress = common.HexToAddress("0x42030001") fillMevShareBundleAddress = common.HexToAddress("0x43200001") - signEthTransaction = common.HexToAddress("0x40100001") - signMessage = common.HexToAddress("0x40100003") + signEthTransaction = common.HexToAddress("0x40100001") + signMessage = common.HexToAddress("0x40100003") + simulateBundleAddress = common.HexToAddress("0x42100000") buildEthBlockAddress = common.HexToAddress("0x42100001") + privateKeyGen = common.HexToAddress("0x53200003") + /* contracts */ newBundleBidAddress = common.HexToAddress("0x642300000") newBlockBidAddress = common.HexToAddress("0x642310000") diff --git a/suave/gen/suave_spec.yaml b/suave/gen/suave_spec.yaml index 44c51247f..a1ab047a0 100644 --- a/suave/gen/suave_spec.yaml +++ b/suave/gen/suave_spec.yaml @@ -335,3 +335,11 @@ functions: - name: simulationResult type: SimulateTransactionResult description: "Result of the simulation" + - name: privateKeyGen + address: '0x0000000000000000000000000000000053200003' + description: "Generates a private key in ECDA secp256k1 format" + output: + fields: + - name: privateKey + type: string + description: "Hex encoded string of the ECDSA private key. Exactly as a signMessage precompile wants." \ No newline at end of file diff --git a/suave/sol/libraries/Suave.sol b/suave/sol/libraries/Suave.sol index bcaf758bb..7109a4295 100644 --- a/suave/sol/libraries/Suave.sol +++ b/suave/sol/libraries/Suave.sol @@ -82,6 +82,8 @@ library Suave { address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000; + address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003; + address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001; address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003; @@ -217,6 +219,15 @@ library Suave { return abi.decode(data, (DataRecord)); } + function privateKeyGen() internal view returns (string memory) { + (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode()); + if (!success) { + revert PeekerReverted(PRIVATE_KEY_GEN, data); + } + + return abi.decode(data, (string)); + } + function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey) internal view