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

precompiles: Optionally use silkpre as implementation #660

Merged
merged 5 commits into from
Jul 28, 2023
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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,20 @@ To build the evmone EVMC module (shared library), test, and benchmark:
build/bin/evmone-bench test/evm-benchmarks/benchmarks
```

### Precompiles

Ethereum Precompiled Contracts (_precompiles_ for short) are not directly supported by evmone.

However, there are options to enable limited precompiles support for testing.

1. The [test/state/precompiles_stub.json](./test/state/precompiles_stub.json) contains
precompiles execution results for inputs commonly used in tests.
You can use the precompiles STUB by setting the environment variable
`EVMONE_PRECOMPILES_STUB=./test/state/precompiles_stub.json`.
2. The CMake option `EVMONE_PRECOMPILES_SILKPRE=1` enables building of
the [silkpre] third party library with the implementation of the precompiles.
This library also requires [GMP] (e.g. libgmp-dev) library for building and execution.

### Tools

#### evm-test
Expand Down Expand Up @@ -138,10 +152,12 @@ Licensed under the [Apache License, Version 2.0].
[EVMC]: https://github.com/ethereum/evmc
[Ipsilon]: https://github.com/ipsilon
[Ewasm]: https://github.com/ewasm
[GMP]: https://gmplib.org
[intx]: https://github.com/chfast/intx
[ethash]: https://github.com/chfast/ethash
[Releases]: https://github.com/ethereum/evmone/releases
[standard readme]: https://github.com/RichardLitt/standard-readme
[silkpre]: https://github.com/torquem-ch/silkpre

[appveyor badge]: https://img.shields.io/appveyor/ci/chfast/evmone/master.svg?logo=appveyor
[circleci badge]: https://img.shields.io/circleci/project/github/ethereum/evmone/master.svg?logo=circleci
Expand Down
22 changes: 22 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,27 @@ jobs:
- upload_coverage:
flags: statetests

precompiles-silkpre:
executor: blockchain-tests
environment:
BUILD_TYPE: Coverage
CMAKE_OPTIONS: -DCMAKE_CXX_FLAGS=-Og -DEVMONE_PRECOMPILES_SILKPRE=1
steps:
- run:
name: "Install GMP"
command: sudo apt-get -q update && sudo apt-get -qy install libgmp-dev
- build
- download_execution_tests:
rev: v12.2
- run:
name: "State tests"
working_directory: ~/build
command: |
bin/evmone-statetest ~/tests/GeneralStateTests ~/tests/LegacyTests/Constantinople/GeneralStateTests
- collect_coverage_gcc
- upload_coverage:
flags: statetests-silkpre

gcc-min:
executor: linux-gcc-min
steps:
Expand Down Expand Up @@ -666,6 +687,7 @@ workflows:
tags:
only: /^v[0-9].*/
- state-tests
- precompiles-silkpre
- blockchain-tests
- cmake-min
- gcc-min
Expand Down
30 changes: 30 additions & 0 deletions test/state/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,33 @@ target_sources(
state.hpp
state.cpp
)

option(EVMONE_PRECOMPILES_SILKPRE "Enable precompiles support via silkpre library" OFF)
if(EVMONE_PRECOMPILES_SILKPRE)
include(FetchContent)
FetchContent_Declare(
silkpre
GIT_REPOSITORY https://github.com/torquem-ch/silkpre
GIT_TAG 3322bb898ac9528fc2cf9a8df1e48360420d0c1a
GIT_SHALLOW TRUE
)
set(BUILD_SHARED_LIBS_ORIG ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
FetchContent_MakeAvailable(silkpre)
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_ORIG})

set_target_properties(
silkpre secp256k1 ff
PROPERTIES
COMPILE_OPTIONS -w # Disable warnings.
CXX_CLANG_TIDY ""
)

target_link_libraries(evmone-state PRIVATE silkpre)
target_compile_definitions(evmone-state PRIVATE EVMONE_PRECOMPILES_SILKPRE=1)
target_sources(
evmone-state PRIVATE
precompiles_silkpre.hpp
precompiles_silkpre.cpp
)
endif()
14 changes: 14 additions & 0 deletions test/state/precompiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include <limits>
#include <unordered_map>

#ifdef EVMONE_PRECOMPILES_SILKPRE
#include "precompiles_silkpre.hpp"
#endif

namespace evmone::state
{
using namespace evmc::literals;
Expand Down Expand Up @@ -172,6 +176,16 @@ inline constexpr auto traits = []() noexcept {
{ecpairing_analyze, dummy_execute<PrecompileId::ecpairing>},
{blake2bf_analyze, dummy_execute<PrecompileId::blake2bf>},
}};
#ifdef EVMONE_PRECOMPILES_SILKPRE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not #ifdef with two branches directly in the initialization above ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is structured as optional override. It also allows us quickly change what we override with silkpre.

tbl[static_cast<size_t>(PrecompileId::ecrecover)].execute = silkpre_ecrecover_execute;
tbl[static_cast<size_t>(PrecompileId::sha256)].execute = silkpre_sha256_execute;
tbl[static_cast<size_t>(PrecompileId::ripemd160)].execute = silkpre_ripemd160_execute;
tbl[static_cast<size_t>(PrecompileId::expmod)].execute = silkpre_expmod_execute;
tbl[static_cast<size_t>(PrecompileId::ecadd)].execute = silkpre_ecadd_execute;
tbl[static_cast<size_t>(PrecompileId::ecmul)].execute = silkpre_ecmul_execute;
tbl[static_cast<size_t>(PrecompileId::ecpairing)].execute = silkpre_ecpairing_execute;
tbl[static_cast<size_t>(PrecompileId::blake2bf)].execute = silkpre_blake2bf_execute;
#endif
return tbl;
}();
} // namespace
Expand Down
80 changes: 80 additions & 0 deletions test/state/precompiles_silkpre.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// evmone: Fast Ethereum Virtual Machine implementation
// Copyright 2022 The evmone Authors.
// SPDX-License-Identifier: Apache-2.0

#include "precompiles_silkpre.hpp"
#include <silkpre/precompile.h>
#include <cassert>
#include <cstring>

namespace evmone::state
{
namespace
{
ExecutionResult execute(const uint8_t* input, size_t input_size, uint8_t* output_buf,
[[maybe_unused]] size_t max_output_size, PrecompileId id) noexcept
{
const auto index = stdx::to_underlying(id) - 1;
const auto [output, output_size] = kSilkpreContracts[index].run(input, input_size);
if (output == nullptr)
return {EVMC_PRECOMPILE_FAILURE, 0};

// Check if max_output_size computed by analysis match the computed result.
assert(output_size <= max_output_size);

const auto trimmed_output_size = std::min(output_size, max_output_size);
std::memcpy(output_buf, output, trimmed_output_size);
std::free(output); // Free output allocation (required by silkpre API).
return {EVMC_SUCCESS, trimmed_output_size};
}
} // namespace

ExecutionResult silkpre_ecrecover_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::ecrecover);
}

ExecutionResult silkpre_sha256_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::sha256);
}

ExecutionResult silkpre_ripemd160_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::ripemd160);
}

ExecutionResult silkpre_expmod_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::expmod);
}

ExecutionResult silkpre_ecadd_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::ecadd);
}

ExecutionResult silkpre_ecmul_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::ecmul);
}


ExecutionResult silkpre_ecpairing_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::ecpairing);
}

ExecutionResult silkpre_blake2bf_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept
{
return execute(input, input_size, output_buf, max_output_size, PrecompileId::blake2bf);
}
} // namespace evmone::state
33 changes: 33 additions & 0 deletions test/state/precompiles_silkpre.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// evmone: Fast Ethereum Virtual Machine implementation
// Copyright 2022 The evmone Authors.
// SPDX-License-Identifier: Apache-2.0
#pragma once

#include "precompiles.hpp"

namespace evmone::state
{
ExecutionResult silkpre_ecrecover_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;

ExecutionResult silkpre_sha256_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;

ExecutionResult silkpre_ripemd160_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;

ExecutionResult silkpre_expmod_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;

ExecutionResult silkpre_ecadd_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;

ExecutionResult silkpre_ecmul_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;

ExecutionResult silkpre_ecpairing_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;

ExecutionResult silkpre_blake2bf_execute(
const uint8_t* input, size_t input_size, uint8_t* output_buf, size_t max_output_size) noexcept;
} // namespace evmone::state
1 change: 1 addition & 0 deletions test/state/precompiles_stub.json
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@
},
{
"0537dab8bcfa337395fdfbd203d054ac25c08722e9416a0ac259b779a2c87721": "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923",
"05bd989b8f157e23dbb02b8bc54d344a60558de44a7ee3f804cf1dfc9e82bbda": "fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615",
"13d12ef157bef72bdae72d1981ac6bc16ab74176742f7fb689ecef08d3d6bf0d": "d82c6a670dc90af9d7f77644eacbeddfed91b760c65c927871784abceaab3f813759733a1736254fb1cfc515dbfee467930955af56e27ee435f836fc3e65969f",
"2699f65d0bde17d17b834840e823616c33fb78e1a63f31fb6613bd1b08b888b4": "68790ca7594dd6fc28f0a86b7ddce0a225a8ea8fc2637f910eb71f6e54d9f8fa3e6302691015f11b15b755076d316823e6ce2ee4dd4aef60efc9189f6bd21bfd",
"30e40ece3441a7de9a9451e74fab98b455c4823f2485b2373a43a8b6c928a9fb": null,
Expand Down