Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AES en/decryption precompiles #274

Merged
merged 8 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/types/suave_structs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions core/vm/contracts_suave.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package vm
import (
"bytes"
"context"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
Expand Down Expand Up @@ -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
}
94 changes: 92 additions & 2 deletions core/vm/contracts_suave_runtime_adapter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions core/vm/contracts_suave_runtime_adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{},
Expand Down
24 changes: 24 additions & 0 deletions core/vm/contracts_suave_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package vm

import (
"context"
"crypto/rand"
"math/big"
"net/http"
"net/http/httptest"
Expand All @@ -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 {
Expand Down Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion suave/artifacts/SuaveLib.json

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion suave/artifacts/addresses.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions suave/gen/suave_spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
30 changes: 30 additions & 0 deletions suave/sol/libraries/Suave.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading