diff --git a/core/types/suave_structs.go b/core/types/suave_structs.go index 70728aac8..d3d8aefcb 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: 58abede869b35f32efbb95ee4b2c2eff30631ae4ecb4f2732cd972174fe95ced +// Hash: 0433c95fed95ac0160125de152961adbf87bb072eb288b07cc35512c45cbd9ad package types import "github.com/ethereum/go-ethereum/common" diff --git a/core/vm/contracts_suave.go b/core/vm/contracts_suave.go index 3c4992374..7ee92a80c 100644 --- a/core/vm/contracts_suave.go +++ b/core/vm/contracts_suave.go @@ -3,6 +3,8 @@ package vm import ( "bytes" "context" + "crypto/aes" + "crypto/cipher" "crypto/rand" "fmt" "io" @@ -347,3 +349,46 @@ func (s *suaveRuntime) contextGet(key string) ([]byte, error) { } return val, nil } + +func (s *suaveRuntime) aesEncrypt(key []byte, message []byte) ([]byte, error) { + // force 32-byte key for best security + keyBytes := make([]byte, 32) + copy(keyBytes[:], key[:]) + c, err := aes.NewCipher(keyBytes) + if err != nil { + return nil, err + } + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + buf := gcm.Seal(nonce, nonce, message, nil) + return buf, nil +} + +func (s *suaveRuntime) aesDecrypt(key []byte, ciphertext []byte) ([]byte, error) { + keyBytes := make([]byte, 32) + copy(keyBytes[:], key[:]) + c, err := aes.NewCipher(keyBytes) + if err != nil { + return nil, err + } + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + nonceSize := gcm.NonceSize() + if len(ciphertext) < nonceSize { + return nil, fmt.Errorf("ciphertext too short") + } + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + return plaintext, nil +} diff --git a/core/vm/contracts_suave_runtime_adapter.go b/core/vm/contracts_suave_runtime_adapter.go index c8ced1850..0de431366 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: 58abede869b35f32efbb95ee4b2c2eff30631ae4ecb4f2732cd972174fe95ced +// Hash: 0433c95fed95ac0160125de152961adbf87bb072eb288b07cc35512c45cbd9ad package vm import ( @@ -17,6 +17,8 @@ var ( ) type SuaveRuntime interface { + aesDecrypt(key []byte, ciphertext []byte) ([]byte, error) + aesEncrypt(key []byte, message []byte) ([]byte, error) buildEthBlock(blockArgs types.BuildBlockArgs, dataId types.DataId, relayUrl string) ([]byte, []byte, error) buildEthBlockTo(executionNodeURL string, blockArgs types.BuildBlockArgs, dataId types.DataId, relayUrl string) ([]byte, []byte, error) confidentialInputs() ([]byte, error) @@ -41,6 +43,8 @@ type SuaveRuntime interface { } var ( + aesDecryptAddr = common.HexToAddress("0x000000000000000000000000000000005670000d") + aesEncryptAddr = common.HexToAddress("0x000000000000000000000000000000005670000e") buildEthBlockAddr = common.HexToAddress("0x0000000000000000000000000000000042100001") buildEthBlockToAddr = common.HexToAddress("0x0000000000000000000000000000000042100006") confidentialInputsAddr = common.HexToAddress("0x0000000000000000000000000000000042010001") @@ -65,7 +69,7 @@ var ( ) var addrList = []common.Address{ - buildEthBlockAddr, buildEthBlockToAddr, confidentialInputsAddr, confidentialRetrieveAddr, confidentialStoreAddr, contextGetAddr, doHTTPRequestAddr, ethcallAddr, extractHintAddr, fetchDataRecordsAddr, fillMevShareBundleAddr, newBuilderAddr, newDataRecordAddr, privateKeyGenAddr, randomBytesAddr, signEthTransactionAddr, signMessageAddr, simulateBundleAddr, simulateTransactionAddr, submitBundleJsonRPCAddr, submitEthBlockToRelayAddr, + aesDecryptAddr, aesEncryptAddr, buildEthBlockAddr, buildEthBlockToAddr, confidentialInputsAddr, confidentialRetrieveAddr, confidentialStoreAddr, contextGetAddr, doHTTPRequestAddr, ethcallAddr, extractHintAddr, fetchDataRecordsAddr, fillMevShareBundleAddr, newBuilderAddr, newDataRecordAddr, privateKeyGenAddr, randomBytesAddr, signEthTransactionAddr, signMessageAddr, simulateBundleAddr, simulateTransactionAddr, submitBundleJsonRPCAddr, submitEthBlockToRelayAddr, } type SuaveRuntimeAdapter struct { @@ -74,6 +78,12 @@ type SuaveRuntimeAdapter struct { func (b *SuaveRuntimeAdapter) run(addr common.Address, input []byte) ([]byte, error) { switch addr { + case aesDecryptAddr: + return b.aesDecrypt(input) + + case aesEncryptAddr: + return b.aesEncrypt(input) + case buildEthBlockAddr: return b.buildEthBlock(input) @@ -142,6 +152,86 @@ func (b *SuaveRuntimeAdapter) run(addr common.Address, input []byte) ([]byte, er } } +func (b *SuaveRuntimeAdapter) aesDecrypt(input []byte) (res []byte, err error) { + var ( + unpacked []interface{} + result []byte + ) + + _ = unpacked + _ = result + + unpacked, err = artifacts.SuaveAbi.Methods["aesDecrypt"].Inputs.Unpack(input) + if err != nil { + err = errFailedToUnpackInput + return + } + + var ( + key []byte + ciphertext []byte + ) + + key = unpacked[0].([]byte) + ciphertext = unpacked[1].([]byte) + + var ( + message []byte + ) + + if message, err = b.impl.aesDecrypt(key, ciphertext); err != nil { + return + } + + result, err = artifacts.SuaveAbi.Methods["aesDecrypt"].Outputs.Pack(message) + if err != nil { + err = errFailedToPackOutput + return + } + return result, nil + +} + +func (b *SuaveRuntimeAdapter) aesEncrypt(input []byte) (res []byte, err error) { + var ( + unpacked []interface{} + result []byte + ) + + _ = unpacked + _ = result + + unpacked, err = artifacts.SuaveAbi.Methods["aesEncrypt"].Inputs.Unpack(input) + if err != nil { + err = errFailedToUnpackInput + return + } + + var ( + key []byte + message []byte + ) + + key = unpacked[0].([]byte) + message = unpacked[1].([]byte) + + var ( + ciphertext []byte + ) + + if ciphertext, err = b.impl.aesEncrypt(key, message); err != nil { + return + } + + result, err = artifacts.SuaveAbi.Methods["aesEncrypt"].Outputs.Pack(ciphertext) + if err != nil { + err = errFailedToPackOutput + return + } + return result, nil + +} + func (b *SuaveRuntimeAdapter) buildEthBlock(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 f7fb31124..4133a3b53 100644 --- a/core/vm/contracts_suave_runtime_adapter_test.go +++ b/core/vm/contracts_suave_runtime_adapter_test.go @@ -103,6 +103,14 @@ func (m *mockRuntime) randomBytes(length uint8) ([]byte, error) { return bytes, nil } +func (m *mockRuntime) aesEncrypt(key []byte, message []byte) ([]byte, error) { + return []byte{0x1}, nil +} + +func (m *mockRuntime) aesDecrypt(key []byte, ciphertext []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 3702b0fa5..e7dda446b 100644 --- a/core/vm/contracts_suave_test.go +++ b/core/vm/contracts_suave_test.go @@ -2,6 +2,7 @@ package vm import ( "context" + "crypto/rand" "math/big" "net/http" "net/http/httptest" @@ -16,6 +17,7 @@ import ( suave "github.com/ethereum/go-ethereum/suave/core" "github.com/ethereum/go-ethereum/suave/cstore" "github.com/stretchr/testify/require" + "golang.org/x/crypto/scrypt" ) type mockSuaveBackend struct { @@ -137,6 +139,28 @@ func TestSuave_DataRecordWorkflow(t *testing.T) { } } +func TestSuave_AESPrecompiles(t *testing.T) { + b := newTestBackend(t) + + message := []byte("hello world") + + // safely generate a 32-byte secret + salt := make([]byte, 32) + _, err := rand.Read(salt) + require.NoError(t, err) + pk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) + require.NoError(t, err) + + // note: any 32-byte value will do for pk + // if your secret is not 32 bytes long, it's right-padded with 0s + ciphertext, err := b.aesEncrypt(pk, message) + require.NoError(t, err) + + decrypted, err := b.aesDecrypt(pk, ciphertext) + require.NoError(t, err) + require.Equal(t, message, decrypted) +} + func TestSuave_ConfStoreWorkflow(t *testing.T) { b := newTestBackend(t) diff --git a/suave/artifacts/SuaveLib.json b/suave/artifacts/SuaveLib.json index 9dfc12a26..8f1893949 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":"beaconRoot","type":"bytes32","internalType":"bytes32"},{"name":"fillPending","type":"bool","internalType":"bool"}]},{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"relayUrl","type":"string","internalType":"string"}],"outputs":[{"name":"blockBid","type":"bytes","internalType":"bytes"},{"name":"executionPayload","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"buildEthBlockTo","inputs":[{"name":"executionNodeURL","type":"string","internalType":"string"},{"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":"beaconRoot","type":"bytes32","internalType":"bytes32"},{"name":"fillPending","type":"bool","internalType":"bool"}]},{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"relayUrl","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":"contextGet","inputs":[{"name":"key","type":"string","internalType":"string"}],"outputs":[{"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"},{"name":"timeout","type":"uint64","internalType":"uint64"}]}],"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","inputs":[{"name":"crypto","type":"uint8","internalType":"struct Suave.CryptoSignature"}],"outputs":[{"name":"privateKey","type":"string","internalType":"string"}]},{"type":"function","name":"randomBytes","inputs":[{"name":"numBytes","type":"uint8","internalType":"uint8"}],"outputs":[{"name":"value","type":"bytes","internalType":"bytes"}]},{"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":"crypto","type":"uint8","internalType":"struct Suave.CryptoSignature"},{"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":"aesDecrypt","inputs":[{"name":"key","type":"bytes","internalType":"bytes"},{"name":"ciphertext","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"message","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"aesEncrypt","inputs":[{"name":"key","type":"bytes","internalType":"bytes"},{"name":"message","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"ciphertext","type":"bytes","internalType":"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":"beaconRoot","type":"bytes32","internalType":"bytes32"},{"name":"fillPending","type":"bool","internalType":"bool"}]},{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"relayUrl","type":"string","internalType":"string"}],"outputs":[{"name":"blockBid","type":"bytes","internalType":"bytes"},{"name":"executionPayload","type":"bytes","internalType":"bytes"}]},{"type":"function","name":"buildEthBlockTo","inputs":[{"name":"executionNodeURL","type":"string","internalType":"string"},{"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":"beaconRoot","type":"bytes32","internalType":"bytes32"},{"name":"fillPending","type":"bool","internalType":"bool"}]},{"name":"dataId","type":"bytes16","internalType":"struct Suave.DataId"},{"name":"relayUrl","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":"contextGet","inputs":[{"name":"key","type":"string","internalType":"string"}],"outputs":[{"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"},{"name":"timeout","type":"uint64","internalType":"uint64"}]}],"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","inputs":[{"name":"crypto","type":"uint8","internalType":"struct Suave.CryptoSignature"}],"outputs":[{"name":"privateKey","type":"string","internalType":"string"}]},{"type":"function","name":"randomBytes","inputs":[{"name":"numBytes","type":"uint8","internalType":"uint8"}],"outputs":[{"name":"value","type":"bytes","internalType":"bytes"}]},{"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":"crypto","type":"uint8","internalType":"struct Suave.CryptoSignature"},{"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 a2c83e423..3eed122d5 100644 --- a/suave/artifacts/addresses.go +++ b/suave/artifacts/addresses.go @@ -1,5 +1,5 @@ // Code generated by suave/gen. DO NOT EDIT. -// Hash: 58abede869b35f32efbb95ee4b2c2eff30631ae4ecb4f2732cd972174fe95ced +// Hash: 0433c95fed95ac0160125de152961adbf87bb072eb288b07cc35512c45cbd9ad package artifacts import ( @@ -8,6 +8,8 @@ import ( // List of suave precompile addresses var ( + aesDecryptAddr = common.HexToAddress("0x000000000000000000000000000000005670000d") + aesEncryptAddr = common.HexToAddress("0x000000000000000000000000000000005670000e") buildEthBlockAddr = common.HexToAddress("0x0000000000000000000000000000000042100001") buildEthBlockToAddr = common.HexToAddress("0x0000000000000000000000000000000042100006") confidentialInputsAddr = common.HexToAddress("0x0000000000000000000000000000000042010001") @@ -32,6 +34,8 @@ var ( ) var SuaveMethods = map[string]common.Address{ + "aesDecrypt": aesDecryptAddr, + "aesEncrypt": aesEncryptAddr, "buildEthBlock": buildEthBlockAddr, "buildEthBlockTo": buildEthBlockToAddr, "confidentialInputs": confidentialInputsAddr, @@ -57,6 +61,10 @@ var SuaveMethods = map[string]common.Address{ func PrecompileAddressToName(addr common.Address) string { switch addr { + case aesDecryptAddr: + return "aesDecrypt" + case aesEncryptAddr: + return "aesEncrypt" case buildEthBlockAddr: return "buildEthBlock" case buildEthBlockToAddr: diff --git a/suave/gen/suave_spec.yaml b/suave/gen/suave_spec.yaml index e9abe3b70..20fe2fd59 100644 --- a/suave/gen/suave_spec.yaml +++ b/suave/gen/suave_spec.yaml @@ -445,3 +445,33 @@ functions: - name: value type: bytes description: "Randomly-generated bytes" + - name: aesEncrypt + address: "0x000000000000000000000000000000005670000e" + description: "Encrypts a message using given bytes as a cipher." + input: + - name: key + type: bytes + description: "Private key used to encrypt the message" + - name: message + type: bytes + description: "Message to encrypt" + output: + fields: + - name: ciphertext + type: bytes + description: "Encrypted message" + - name: aesDecrypt + address: "0x000000000000000000000000000000005670000d" + description: "Decrypts a message using given bytes as a cipher." + input: + - name: key + type: bytes + description: "Private key used to decrypt the ciphertext" + - name: ciphertext + type: bytes + description: "Message to decrypt" + output: + fields: + - name: message + type: bytes + description: "Decrypted message" diff --git a/suave/sol/libraries/Suave.sol b/suave/sol/libraries/Suave.sol index 4a6977798..3c85c3d1c 100644 --- a/suave/sol/libraries/Suave.sol +++ b/suave/sol/libraries/Suave.sol @@ -108,6 +108,10 @@ library Suave { address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000; + address public constant AES_DECRYPT = 0x000000000000000000000000000000005670000D; + + address public constant AES_ENCRYPT = 0x000000000000000000000000000000005670000e; + address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001; address public constant BUILD_ETH_BLOCK_TO = 0x0000000000000000000000000000000042100006; @@ -165,6 +169,32 @@ library Suave { } } + /// @notice Decrypts a message using given bytes as a cipher. + /// @param key Private key used to decrypt the ciphertext + /// @param ciphertext Message to decrypt + /// @return message Decrypted message + function aesDecrypt(bytes memory key, bytes memory ciphertext) internal returns (bytes memory) { + (bool success, bytes memory data) = AES_DECRYPT.call(abi.encode(key, ciphertext)); + if (!success) { + revert PeekerReverted(AES_DECRYPT, data); + } + + return abi.decode(data, (bytes)); + } + + /// @notice Encrypts a message using given bytes as a cipher. + /// @param key Private key used to encrypt the message + /// @param message Message to encrypt + /// @return ciphertext Encrypted message + function aesEncrypt(bytes memory key, bytes memory message) internal returns (bytes memory) { + (bool success, bytes memory data) = AES_ENCRYPT.call(abi.encode(key, message)); + if (!success) { + revert PeekerReverted(AES_ENCRYPT, data); + } + + return abi.decode(data, (bytes)); + } + /// @notice Constructs an Ethereum block based on the provided data records. No blobs are returned. /// @param blockArgs Arguments to build the block /// @param dataId ID of the data record with mev-share bundle data