├── cmake ├── cable │ ├── .gitignore │ ├── toolchains │ │ ├── default.cmake │ │ ├── cxx14.cmake │ │ ├── cxx17.cmake │ │ ├── cxx11.cmake │ │ ├── cxx14-pic.cmake │ │ ├── cxx17-pic.cmake │ │ ├── cxx11-pic.cmake │ │ ├── cxx14-32bit.cmake │ │ ├── cxx17-32bit.cmake │ │ ├── cxx11-32bit.cmake │ │ ├── cxx11-c99.cmake │ │ ├── cxx11-fpic.cmake │ │ ├── mips64.cmake │ │ └── powerpc64.cmake │ ├── buildinfo │ │ ├── buildinfo.sh.in │ │ ├── buildinfo.ps1.in │ │ ├── buildinfo.json.in │ │ ├── buildinfo.h.in │ │ ├── buildinfo.c.in │ │ ├── gitinfo.cmake │ │ └── buildinfo.cmake │ ├── defaults │ │ ├── HunterCacheServers-passwords.cmake │ │ └── HunterCacheServers.cmake │ ├── CablePackage.cmake │ ├── CableToolchains.cmake │ ├── CableBuildType.cmake │ ├── bootstrap.cmake │ ├── README.md │ ├── CableBuildInfo.cmake │ └── CableCompilerSettings.cmake └── Config.cmake.in ├── MANIFEST.in ├── codecov.yml ├── .gitignore ├── test ├── integration │ ├── CMakeLists.txt │ ├── compilation │ │ ├── ethash_header_test.c │ │ └── CMakeLists.txt │ └── cmake-config │ │ ├── CMakeLists.txt │ │ └── cmake_config_test.cpp ├── daemon │ ├── CMakeLists.txt │ └── kawpow.cpp ├── lightverify │ ├── CMakeLists.txt │ └── lightverify.cpp ├── fuzzing │ ├── CMakeLists.txt │ ├── keccak_fuzzer.cpp │ └── keccak_tiny.c ├── tools │ ├── CMakeLists.txt │ └── kiss99_tester.cpp ├── fakeminer │ ├── CMakeLists.txt │ └── fakeminer.cpp ├── CMakeLists.txt ├── unittests │ ├── test_version.cpp │ ├── CMakeLists.txt │ ├── test_kiss.cpp │ ├── helpers.hpp │ ├── test_bit_manipulation.cpp │ ├── test_cases.hpp │ ├── test_primes.cpp │ ├── progpow_test_vectors.hpp │ ├── test_managed.cpp │ └── test_progpow.cpp └── benchmarks │ ├── threadsync_utils.hpp │ ├── keccak_utils.hpp │ ├── managed_benchmarks.cpp │ ├── CMakeLists.txt │ ├── progpow_benchmarks.cpp │ ├── threadsync_benchmarks.cpp │ ├── threadsync_utils.cpp │ ├── keccak_benchmarks.cpp │ ├── keccak_utils.cpp │ └── ethash_benchmarks.cpp ├── lib ├── CMakeLists.txt ├── ethash │ ├── primes.h │ ├── builtins.h │ ├── primes.c │ ├── CMakeLists.txt │ ├── kiss99.hpp │ ├── bit_manipulation.h │ ├── ethash-internal.hpp │ ├── endianness.hpp │ └── managed.cpp ├── keccak │ ├── CMakeLists.txt │ ├── keccak.c │ ├── keccakf800.c │ └── keccakf1600.c └── support │ └── attributes.h ├── include └── ethash │ ├── hash_types.hpp │ ├── version.h │ ├── keccak.hpp │ ├── hash_types.h │ ├── keccak.h │ ├── progpow.hpp │ ├── ethash.h │ └── ethash.hpp ├── .bumpversion.cfg ├── scripts └── ci │ └── python_build_wheels.sh ├── .clang-format ├── appveyor.yml ├── bindings └── python │ ├── tests │ └── test_ethash.py │ └── ethash │ ├── _build.py │ └── __init__.py ├── CHANGELOG.md ├── README.md ├── CMakeLists.txt ├── setup.py ├── circle.yml └── LICENSE /cmake/cable/.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CMakeLists.txt 2 | recursive-include cmake * 3 | recursive-include include * 4 | recursive-include lib * 5 | -------------------------------------------------------------------------------- /cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/ethashTargets.cmake") 4 | check_required_components(ethash) 5 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "diff" 3 | ignore: 4 | - "test/benchmarks/*" 5 | - "test/fakeminer/*" 6 | - "test/integration/*" 7 | - "test/tools/*" 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /cmake-build-* 3 | /.idea 4 | 5 | /dist 6 | /.eggs 7 | /bindings/python/**/*.egg-info 8 | /bindings/python/**/*.pyc 9 | /bindings/python/**/*.so 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/default.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | -------------------------------------------------------------------------------- /test/integration/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | add_subdirectory(compilation) 6 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.sh.in: -------------------------------------------------------------------------------- 1 | PROJECT_NAME='@PROJECT_NAME@' 2 | PROJECT_VERSION='@PROJECT_VERSION@' 3 | PROJECT_VERSION_IS_PRERELEASE='@PROJECT_VERSION_IS_PRERELEASE@' 4 | SYSTEM_NAME='@SYSTEM_NAME@' 5 | SYSTEM_PROCESSOR='@SYSTEM_PROCESSOR@' 6 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx14.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx17.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.ps1.in: -------------------------------------------------------------------------------- 1 | $env:project_name="@PROJECT_NAME@" 2 | $env:project_version="@PROJECT_VERSION@" 3 | $env:project_version_is_prerelease="@PROJECT_VERSION_IS_PRERELEASE@" 4 | $env:system_name='@SYSTEM_NAME@' 5 | $env:system_processor='@SYSTEM_PROCESSOR@' 6 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | -------------------------------------------------------------------------------- /test/daemon/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(kawpow kawpow.cpp) 2 | 3 | target_link_libraries(kawpow PRIVATE ethash -levent) 4 | target_include_directories(kawpow PRIVATE ${ETHASH_PRIVATE_INCLUDE_DIR}) 5 | set_target_properties(kawpow PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) -------------------------------------------------------------------------------- /test/lightverify/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(lightverify lightverify.cpp) 2 | target_link_libraries(lightverify PRIVATE ethash) 3 | target_include_directories(lightverify PRIVATE ${ETHASH_PRIVATE_INCLUDE_DIR}) 4 | set_target_properties(lightverify PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx14-pic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx17-pic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-pic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx14-32bit.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_FLAGS_INIT -m32) 10 | set(CMAKE_CXX_FLAGS_INIT -m32) 11 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx17-32bit.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_FLAGS_INIT -m32) 10 | set(CMAKE_CXX_FLAGS_INIT -m32) 11 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-32bit.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_FLAGS_INIT -m32) 10 | set(CMAKE_CXX_FLAGS_INIT -m32) 11 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@PROJECT_NAME@", 3 | "version": "@PROJECT_VERSION@", 4 | "is_prerelease": @PROJECT_VERSION_IS_PRERELEASE@, 5 | "commit": "@GIT_COMMIT_HASH@", 6 | "branch": "@GIT_BRANCH@", 7 | "repo": "@GIT_ORIGIN_URL@", 8 | "system_name": "@SYSTEM_NAME@", 9 | "system_processor": "@SYSTEM_PROCESSOR@" 10 | } 11 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-c99.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_C_STANDARD 99) 10 | set(CMAKE_C_EXTENSIONS OFF) 11 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | add_subdirectory(keccak) 6 | add_subdirectory(ethash) 7 | 8 | get_filename_component(ETHASH_PRIVATE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ABSOLUTE) 9 | set(ETHASH_PRIVATE_INCLUDE_DIR ${ETHASH_PRIVATE_INCLUDE_DIR} PARENT_SCOPE) 10 | -------------------------------------------------------------------------------- /test/fuzzing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | string(REPLACE "-fsanitize=fuzzer-no-link" "-fsanitize=fuzzer" CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) 6 | 7 | add_executable(keccak-fuzzer keccak_fuzzer.cpp keccak_tiny.c keccak_rhash.c) 8 | target_link_libraries(keccak-fuzzer PRIVATE ethash) 9 | -------------------------------------------------------------------------------- /test/tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | add_executable(kiss99-tester kiss99_tester.cpp) 6 | target_link_libraries(kiss99-tester PRIVATE ethash) 7 | target_include_directories(kiss99-tester PRIVATE ${ETHASH_PRIVATE_INCLUDE_DIR}) 8 | set_target_properties(kiss99-tester PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..) 9 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/cxx11-fpic.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | 11 | set(CMAKE_CXX_FLAGS_INIT "-fPIC" CACHE STRING "" FORCE) 12 | set(CMAKE_C_FLAGS_INIT "-fPIC" CACHE STRING "" FORCE) 13 | -------------------------------------------------------------------------------- /test/fakeminer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | find_package(Threads) 6 | 7 | add_executable(ethash-fakeminer fakeminer.cpp) 8 | target_link_libraries(ethash-fakeminer PRIVATE ethash Threads::Threads) 9 | set_target_properties(ethash-fakeminer PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 10 | -------------------------------------------------------------------------------- /test/integration/compilation/ethash_header_test.c: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #include 7 | 8 | int test() 9 | { 10 | int sum = 0; 11 | sum += ETHASH_EPOCH_LENGTH; 12 | sum += ETHASH_LIGHT_CACHE_ITEM_SIZE; 13 | sum += ETHASH_FULL_DATASET_ITEM_SIZE; 14 | return sum; 15 | } 16 | -------------------------------------------------------------------------------- /include/ethash/hash_types.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace ethash 10 | { 11 | using hash256 = ethash_hash256; 12 | using hash512 = ethash_hash512; 13 | using hash1024 = ethash_hash1024; 14 | using hash2048 = ethash_hash2048; 15 | } // namespace ethash 16 | -------------------------------------------------------------------------------- /include/ethash/version.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | /** The ethash library version. */ 9 | #define ETHASH_VERSION "0.5.1-alpha.1" 10 | 11 | #ifdef __cplusplus 12 | namespace ethash 13 | { 14 | /// The ethash library version. 15 | constexpr auto version = ETHASH_VERSION; 16 | 17 | } // namespace ethash 18 | #endif 19 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | add_subdirectory(benchmarks) 6 | add_subdirectory(fakeminer) 7 | add_subdirectory(integration) 8 | add_subdirectory(tools) 9 | add_subdirectory(unittests) 10 | add_subdirectory(lightverify) 11 | add_subdirectory(daemon) 12 | 13 | if(ETHASH_FUZZING) 14 | add_subdirectory(fuzzing) 15 | endif() 16 | -------------------------------------------------------------------------------- /test/integration/cmake-config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018-2019 Pawel Bylica. 2 | # Licensed under the Apache License, Version 2.0. 3 | 4 | cmake_minimum_required(VERSION 3.5) 5 | 6 | project(ethash-cmake-config-test) 7 | 8 | find_package(ethash CONFIG REQUIRED) 9 | 10 | add_executable(ethash-cmake-config-test cmake_config_test.cpp) 11 | target_link_libraries(ethash-cmake-config-test ethash::ethash) 12 | set_target_properties(ethash-cmake-config-test PROPERTIES CXX_STANDARD 11 CXX_EXTENSIONS OFF) 13 | -------------------------------------------------------------------------------- /test/unittests/test_version.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | 7 | #include 8 | 9 | TEST(libethash, version) 10 | { 11 | static_assert(ethash::version[0] != 0, "incorrect ethash::version"); 12 | 13 | EXPECT_EQ(ETHASH_VERSION, TEST_PROJECT_VERSION); 14 | EXPECT_EQ(ethash::version, TEST_PROJECT_VERSION); 15 | } 16 | -------------------------------------------------------------------------------- /test/benchmarks/threadsync_utils.hpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | struct fake_cache; 10 | 11 | std::shared_ptr build_fake_cache(int id) noexcept; 12 | 13 | bool verify_fake_cache_nosync(int id, int value) noexcept; 14 | 15 | bool verify_fake_cache_mutex(int id, int value) noexcept; 16 | 17 | bool verify_fake_cache_thread_local(int id, int value) noexcept; 18 | -------------------------------------------------------------------------------- /test/integration/cmake-config/cmake_config_test.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | #include 7 | 8 | int main() 9 | { 10 | static_assert(sizeof(ethash::version) >= 6, "incorrect ethash::version"); 11 | 12 | uint8_t seed_bytes[32] = {0}; 13 | ethash::hash256 seed = ethash::hash256_from_bytes(seed_bytes); 14 | return ethash::find_epoch_number(seed); 15 | } 16 | -------------------------------------------------------------------------------- /test/benchmarks/keccak_utils.hpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | void fake_keccak256_default(uint64_t* out, const uint8_t* data, size_t size) noexcept; 11 | void fake_keccak256_default_aligned(uint64_t* out, const uint8_t* data, size_t size) noexcept; 12 | void fake_keccak256_fastest(uint64_t *out, const uint8_t *data, size_t size) noexcept; 13 | void fake_keccak256_fastest_word4(uint64_t out[4], const uint64_t data[4]) noexcept; 14 | -------------------------------------------------------------------------------- /cmake/cable/defaults/HunterCacheServers-passwords.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | # Hunter passwords file used by HunterCacheServers.cmake. 6 | # Do not include directly. 7 | 8 | hunter_upload_password( 9 | # REPO_OWNER + REPO = https://github.com/ethereum/hunter-cache 10 | REPO_OWNER ethereum 11 | REPO hunter-cache 12 | 13 | # USERNAME = https://github.com/hunter-cache-bot 14 | USERNAME hunter-cache-bot 15 | 16 | # PASSWORD = GitHub token saved as a secure environment variable 17 | PASSWORD "$ENV{HUNTER_CACHE_TOKEN}" 18 | ) 19 | -------------------------------------------------------------------------------- /test/integration/compilation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | file(GLOB c_sources ${PROJECT_SOURCE_DIR}/lib/ethash/*.c) 6 | 7 | foreach(c_std 0 90 99 11) 8 | set(target test-compile-c${c_std}) 9 | add_library(${target} STATIC ethash_header_test.c ${c_sources}) 10 | target_link_libraries(${target} PRIVATE ethash) 11 | if(c_std) 12 | set_target_properties(${target} PROPERTIES C_STANDARD ${c_std}) 13 | endif() 14 | set_target_properties(${target} PROPERTIES C_EXTENSIONS OFF) 15 | endforeach() 16 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.5.1-alpha.1 3 | tag = True 4 | sign_tags = True 5 | tag_message = ethash {new_version} 6 | commit = True 7 | message = ethash {new_version} 8 | 9 | Bump version: {current_version} → {new_version} 10 | parse = (?P\d+)\.(?P\d+)\.(?P\d+)(-(?Prc|alpha)\.(?P\d+))? 11 | serialize = 12 | {major}.{minor}.{patch}-{prerel}.{prerelver} 13 | {major}.{minor}.{patch} 14 | 15 | [bumpversion:part:prerel] 16 | optional_value = rel 17 | values = 18 | alpha 19 | rc 20 | rel 21 | 22 | [bumpversion:file:CMakeLists.txt] 23 | 24 | [bumpversion:file:include/ethash/version.h] 25 | 26 | [bumpversion:file:setup.py] 27 | 28 | -------------------------------------------------------------------------------- /test/benchmarks/managed_benchmarks.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | 7 | #include 8 | 9 | static void get_epoch_context(benchmark::State& state) 10 | { 11 | const auto e = static_cast(state.range(0)); 12 | 13 | ethash::get_global_epoch_context(0); 14 | 15 | for (auto _ : state) 16 | { 17 | auto& ctx = ethash::get_global_epoch_context(e); 18 | benchmark::DoNotOptimize(&ctx); 19 | } 20 | } 21 | BENCHMARK(get_epoch_context)->Arg(0)->ThreadRange(1, 8); 22 | -------------------------------------------------------------------------------- /lib/ethash/primes.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | /** 15 | * Finds the largest prime number not greater than the provided upper bound. 16 | * 17 | * @param upper_bound The upper bound. SHOULD be greater than 1. 18 | * @return The largest prime number `p` such `p <= upper_bound`. 19 | * In case `upper_bound <= 1`, returns 0. 20 | */ 21 | int ethash_find_largest_prime(int upper_bound) NOEXCEPT; 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /lib/keccak/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | include(CMakePackageConfigHelpers) 6 | include(GNUInstallDirs) 7 | 8 | add_library( 9 | keccak 10 | ${include_dir}/ethash/keccak.h 11 | ${include_dir}/ethash/keccak.hpp 12 | keccak.c 13 | keccakf800.c 14 | keccakf1600.c 15 | ) 16 | 17 | target_include_directories(keccak PUBLIC $$) 18 | 19 | install( 20 | TARGETS keccak 21 | EXPORT ethashTargets 22 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 23 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 24 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 25 | ) 26 | -------------------------------------------------------------------------------- /test/benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | hunter_add_package(benchmark) 6 | find_package(benchmark CONFIG REQUIRED) 7 | 8 | add_executable(ethash-bench 9 | ethash_benchmarks.cpp 10 | keccak_benchmarks.cpp 11 | keccak_utils.hpp 12 | keccak_utils.cpp 13 | managed_benchmarks.cpp 14 | progpow_benchmarks.cpp 15 | threadsync_benchmarks.cpp 16 | threadsync_utils.hpp 17 | threadsync_utils.cpp) 18 | target_link_libraries(ethash-bench PRIVATE ethash benchmark::benchmark) 19 | target_include_directories(ethash-bench PRIVATE ${ETHASH_PRIVATE_INCLUDE_DIR}) 20 | set_target_properties(ethash-bench PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..) 21 | -------------------------------------------------------------------------------- /test/benchmarks/progpow_benchmarks.cpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include "../unittests/helpers.hpp" 6 | 7 | #include 8 | 9 | #include 10 | 11 | static void progpow_hash(benchmark::State& state) 12 | { 13 | // Get block number in millions. 14 | int block_number = static_cast(state.range(0)) * 1000000; 15 | uint64_t nonce = 1; 16 | 17 | const auto& ctx = ethash::get_global_epoch_context(ethash::get_epoch_number(block_number)); 18 | 19 | for (auto _ : state) 20 | progpow::hash(ctx, block_number++, {}, nonce++); 21 | } 22 | BENCHMARK(progpow_hash)->Unit(benchmark::kMicrosecond)->Arg(0)->Arg(10); 23 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.h.in: -------------------------------------------------------------------------------- 1 | /* Cable: CMake Bootstrap Library. 2 | * Copyright 2018 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | */ 5 | 6 | /* Generated by Cable Build Info on @TIMESTAMP@. Do not modify directly. */ 7 | 8 | #pragma once 9 | 10 | #ifdef __cplusplus 11 | extern "C" 12 | { 13 | #endif 14 | 15 | struct buildinfo 16 | { 17 | const char* project_name; 18 | const char* project_version; 19 | const char* project_name_with_version; 20 | const char* git_commit_hash; 21 | const char* system_name; 22 | const char* system_processor; 23 | const char* compiler_id; 24 | const char* compiler_version; 25 | const char* build_type; 26 | }; 27 | 28 | const struct buildinfo* @FUNCTION_NAME@(); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /lib/support/attributes.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | /** inline */ 9 | #if _MSC_VER || __STDC_VERSION__ 10 | #define INLINE inline 11 | #else 12 | #define INLINE 13 | #endif 14 | 15 | /** [[always_inline]] */ 16 | #if _MSC_VER 17 | #define ALWAYS_INLINE __forceinline 18 | #elif defined(__has_attribute) && __STDC_VERSION__ 19 | #if __has_attribute(always_inline) 20 | #define ALWAYS_INLINE __attribute__((always_inline)) 21 | #endif 22 | #endif 23 | #if !defined(ALWAYS_INLINE) 24 | #define ALWAYS_INLINE 25 | #endif 26 | 27 | /** [[no_sanitize()]] */ 28 | #if __clang__ 29 | #define NO_SANITIZE(sanitizer) \ 30 | __attribute__((no_sanitize(sanitizer))) 31 | #else 32 | #define NO_SANITIZE(sanitizer) 33 | #endif 34 | -------------------------------------------------------------------------------- /cmake/cable/CablePackage.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | if(cable_package_included) 6 | return() 7 | endif() 8 | set(cable_package_included TRUE) 9 | 10 | # Configures CPack to build the archive package. 11 | macro(cable_add_archive_package) 12 | if(WIN32) 13 | set(CPACK_GENERATOR ZIP) 14 | else() 15 | set(CPACK_GENERATOR TGZ) 16 | endif() 17 | string(TOLOWER ${CMAKE_SYSTEM_NAME} system_name) 18 | string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} system_processor) 19 | set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME}-${PROJECT_VERSION}-${system_name}-${system_processor}) 20 | set(CPACK_PACKAGE_CHECKSUM SHA256) 21 | set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY FALSE) 22 | unset(system_name) 23 | unset(system_processor) 24 | include(CPack) 25 | endmacro() 26 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.c.in: -------------------------------------------------------------------------------- 1 | /* Cable: CMake Bootstrap Library. 2 | * Copyright 2018 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | */ 5 | 6 | /* Generated by Cable Build Info on @TIMESTAMP@. Do not modify directly. */ 7 | 8 | #include "buildinfo.h" 9 | 10 | const struct buildinfo* @FUNCTION_NAME@() 11 | { 12 | static const struct buildinfo buildinfo = { 13 | .project_name = "@PROJECT_NAME@", 14 | .project_version = "@PROJECT_VERSION@", 15 | .project_name_with_version = "@PROJECT_NAME@-@PROJECT_VERSION@", 16 | .git_commit_hash = "@GIT_COMMIT_HASH@", 17 | .system_name = "@SYSTEM_NAME@", 18 | .system_processor = "@SYSTEM_PROCESSOR@", 19 | .compiler_id = "@COMPILER_ID@", 20 | .compiler_version = "@COMPILER_VERSION@", 21 | .build_type = "@BUILD_TYPE@", 22 | }; 23 | return &buildinfo; 24 | } 25 | -------------------------------------------------------------------------------- /test/benchmarks/threadsync_benchmarks.cpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include "threadsync_utils.hpp" 6 | 7 | #include 8 | 9 | 10 | template 11 | static void threadsync_fake_cache(benchmark::State& state) 12 | { 13 | int id = 17; 14 | int value = 500; 15 | verify_fn(id, value); 16 | 17 | for (auto _ : state) 18 | { 19 | auto handle = verify_fn(id, value); 20 | benchmark::DoNotOptimize(handle); 21 | } 22 | } 23 | BENCHMARK_TEMPLATE(threadsync_fake_cache, verify_fake_cache_nosync)->ThreadRange(1, 8); 24 | BENCHMARK_TEMPLATE(threadsync_fake_cache, verify_fake_cache_mutex)->ThreadRange(1, 8); 25 | BENCHMARK_TEMPLATE(threadsync_fake_cache, verify_fake_cache_thread_local)->ThreadRange(1, 8); 26 | -------------------------------------------------------------------------------- /test/unittests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | hunter_add_package(GTest) 6 | find_package(GTest CONFIG REQUIRED) 7 | 8 | add_executable( 9 | ethash-test 10 | helpers.hpp 11 | test_bit_manipulation.cpp 12 | test_cases.hpp 13 | test_ethash.cpp 14 | test_keccak.cpp 15 | test_kiss.cpp 16 | test_managed.cpp 17 | test_primes.cpp 18 | test_progpow.cpp 19 | test_version.cpp 20 | ) 21 | 22 | set_source_files_properties(test_version.cpp PROPERTIES COMPILE_DEFINITIONS TEST_PROJECT_VERSION="${PROJECT_VERSION}") 23 | 24 | target_link_libraries(ethash-test PRIVATE ethash GTest::gtest_main) 25 | target_include_directories(ethash-test PRIVATE ${ETHASH_PRIVATE_INCLUDE_DIR}) 26 | set_target_properties(ethash-test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..) 27 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/mips64.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_SYSTEM_PROCESSOR mips64) 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_C_COMPILER mips64-linux-gnuabi64-gcc) 8 | set(CMAKE_CXX_COMPILER mips64-linux-gnuabi64-g++) 9 | 10 | set(CMAKE_FIND_ROOT_PATH /usr/mips64-linux-gnuabi64) 11 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 12 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 13 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 14 | 15 | set(CMAKE_CXX_STANDARD 11) 16 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 17 | set(CMAKE_CXX_EXTENSIONS Off) 18 | 19 | if(${CMAKE_VERSION} VERSION_LESS 3.10.0) 20 | # Until CMake 3.10 the FindThreads uses try_run() check of -pthread flag, 21 | # what causes CMake error in crosscompiling mode. Avoid the try_run() check 22 | # by specifying the result up front. 23 | set(THREADS_PTHREAD_ARG TRUE) 24 | endif() 25 | -------------------------------------------------------------------------------- /cmake/cable/toolchains/powerpc64.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(CMAKE_SYSTEM_PROCESSOR powerpc64) 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_C_COMPILER powerpc64-linux-gnu-gcc) 8 | set(CMAKE_CXX_COMPILER powerpc64-linux-gnu-g++) 9 | 10 | set(CMAKE_FIND_ROOT_PATH /usr/powerpc64-linux-gnu) 11 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 12 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 13 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 14 | 15 | set(CMAKE_CXX_STANDARD 11) 16 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 17 | set(CMAKE_CXX_EXTENSIONS OFF) 18 | 19 | if(${CMAKE_VERSION} VERSION_LESS 3.10.0) 20 | # Until CMake 3.10 the FindThreads uses try_run() check of -pthread flag, 21 | # what causes CMake error in crosscompiling mode. Avoid the try_run() check 22 | # by specifying the result up front. 23 | set(THREADS_PTHREAD_ARG TRUE) 24 | endif() 25 | -------------------------------------------------------------------------------- /include/ethash/keccak.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace ethash 11 | { 12 | inline hash256 keccak256(const uint8_t* data, size_t size) noexcept 13 | { 14 | return ethash_keccak256(data, size); 15 | } 16 | 17 | inline hash256 keccak256(const hash256& input) noexcept 18 | { 19 | return ethash_keccak256_32(input.bytes); 20 | } 21 | 22 | inline hash512 keccak512(const uint8_t* data, size_t size) noexcept 23 | { 24 | return ethash_keccak512(data, size); 25 | } 26 | 27 | inline hash512 keccak512(const hash512& input) noexcept 28 | { 29 | return ethash_keccak512_64(input.bytes); 30 | } 31 | 32 | static constexpr auto keccak256_32 = ethash_keccak256_32; 33 | static constexpr auto keccak512_64 = ethash_keccak512_64; 34 | 35 | } // namespace ethash 36 | -------------------------------------------------------------------------------- /lib/ethash/builtins.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | /** 7 | * @file 8 | * Implementation of GCC/clang builtins for MSVC compiler. 9 | */ 10 | 11 | #pragma once 12 | 13 | #ifdef _MSC_VER 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | /** 21 | * Returns the number of leading 0-bits in `x`, starting at the most significant bit position. 22 | * If `x` is 0, the result is undefined. 23 | */ 24 | static inline int __builtin_clz(unsigned int x) 25 | { 26 | unsigned long most_significant_bit; 27 | _BitScanReverse(&most_significant_bit, x); 28 | return 31 - (int)most_significant_bit; 29 | } 30 | 31 | /** 32 | * Returns the number of 1-bits in `x`. 33 | */ 34 | static inline int __builtin_popcount(unsigned int x) 35 | { 36 | return (int)__popcnt(x); 37 | } 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/ethash/hash_types.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | union ethash_hash256 15 | { 16 | uint64_t word64s[4]; 17 | uint32_t word32s[8]; 18 | uint8_t bytes[32]; 19 | char str[32]; 20 | }; 21 | 22 | union ethash_hash512 23 | { 24 | uint64_t word64s[8]; 25 | uint32_t word32s[16]; 26 | uint8_t bytes[64]; 27 | char str[64]; 28 | }; 29 | 30 | union ethash_hash1024 31 | { 32 | union ethash_hash512 hash512s[2]; 33 | uint64_t word64s[16]; 34 | uint32_t word32s[32]; 35 | uint8_t bytes[128]; 36 | char str[128]; 37 | }; 38 | 39 | union ethash_hash2048 40 | { 41 | union ethash_hash512 hash512s[4]; 42 | uint64_t word64s[32]; 43 | uint32_t word32s[64]; 44 | uint8_t bytes[256]; 45 | char str[256]; 46 | }; 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | -------------------------------------------------------------------------------- /lib/ethash/primes.c: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #include "primes.h" 7 | 8 | /** Checks if the number is prime. Requires the number to be > 2 and odd. */ 9 | static int is_odd_prime(int number) 10 | { 11 | int d; 12 | 13 | /* Check factors up to sqrt(number). 14 | To avoid computing sqrt, compare d*d <= number with 64-bit precision. */ 15 | for (d = 3; (int64_t)d * (int64_t)d <= (int64_t)number; d += 2) 16 | { 17 | if (number % d == 0) 18 | return 0; 19 | } 20 | 21 | return 1; 22 | } 23 | 24 | int ethash_find_largest_prime(int upper_bound) 25 | { 26 | int n = upper_bound; 27 | 28 | if (n < 2) 29 | return 0; 30 | 31 | if (n == 2) 32 | return 2; 33 | 34 | /* If even number, skip it. */ 35 | if (n % 2 == 0) 36 | --n; 37 | 38 | /* Test descending odd numbers. */ 39 | while (!is_odd_prime(n)) 40 | n -= 2; 41 | 42 | return n; 43 | } 44 | -------------------------------------------------------------------------------- /scripts/ci/python_build_wheels.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- coding: utf-8 -*- 3 | 4 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 5 | # Copyright 2019 Pawel Bylica. 6 | # Licensed under the Apache License, Version 2.0. 7 | 8 | set -eo pipefail 9 | 10 | if [ -n "$APPVEYOR" ]; then 11 | PYTHON_PATHS="/c/Python37-x64 /c/Python36-x64 /c/Python35-x64" 12 | elif [ -n "$CIRCLECI" ]; then 13 | if [ "$OSTYPE" = "linux-gnu" ]; then 14 | PYTHON_PATHS="/opt/python/cp37-cp37m/bin /opt/python/cp36-cp36m/bin /opt/python/cp35-cp35m/bin" 15 | else 16 | ln -s /usr/local/Cellar/python/3.7.3/bin/python3 /usr/local/Cellar/python/3.7.3/bin/python 17 | PYTHON_PATHS="/usr/local/Cellar/python/3.7.3/bin" 18 | fi 19 | fi 20 | 21 | PATH_ORIG=$PATH 22 | for p in $PYTHON_PATHS 23 | do 24 | PATH="$p:$PATH_ORIG" 25 | echo '***' 26 | python --version 27 | which python 28 | python -m pip --version 29 | echo '***' 30 | python -m pip install wheel 31 | python setup.py build_ext --skip-cmake-build 32 | python setup.py bdist_wheel --skip-build 33 | done 34 | -------------------------------------------------------------------------------- /test/lightverify/lightverify.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | int main(int argc, const char* argv[]) 6 | { 7 | std::string str_header_hash; 8 | std::string str_mix_hash; 9 | std::string str_nonce; 10 | std::string str_boundary; 11 | 12 | for (int i = 0; i < argc; ++i) 13 | { 14 | const std::string arg{argv[i]}; 15 | 16 | if (arg == "-h" && i + 1 < argc) 17 | str_header_hash = std::string(argv[++i]); 18 | else if (arg == "-m" && i + 1 < argc) 19 | str_mix_hash = std::string(argv[++i]); 20 | else if (arg == "-n" && i + 1 < argc) 21 | str_nonce = std::string(argv[++i]); 22 | else if (arg == "-b" && i + 1 < argc) 23 | str_boundary = std::string(argv[++i]); 24 | } 25 | 26 | // char final_hash[64]; 27 | 28 | // if (progpow::light_verify(str_header_hash.c_str(), str_mix_hash.c_str(), str_nonce.c_str(), str_boundary.c_str(), final_hash)) 29 | // printf("%.*s\n", 64, final_hash); 30 | // else { 31 | // printf("Not found\n"); 32 | // } 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /lib/ethash/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | include(GNUInstallDirs) 6 | 7 | add_library( 8 | ethash 9 | bit_manipulation.h 10 | builtins.h 11 | endianness.hpp 12 | ${include_dir}/ethash/ethash.h 13 | ${include_dir}/ethash/ethash.hpp 14 | ethash-internal.hpp 15 | ethash.cpp 16 | ${include_dir}/ethash/hash_types.h 17 | managed.cpp 18 | kiss99.hpp 19 | primes.h 20 | primes.c 21 | ${include_dir}/ethash/progpow.hpp 22 | progpow.cpp 23 | ) 24 | 25 | target_link_libraries(ethash PRIVATE keccak) 26 | target_include_directories(ethash PUBLIC $$) 27 | if(CABLE_COMPILER_GNULIKE AND NOT SANITIZE MATCHES undefined) 28 | target_compile_options(ethash PRIVATE $<$:-fno-rtti>) 29 | endif() 30 | 31 | install( 32 | TARGETS ethash 33 | EXPORT ethashTargets 34 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 35 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 36 | ) 37 | -------------------------------------------------------------------------------- /cmake/cable/defaults/HunterCacheServers.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | # This module, when included, sets default values for params related to 6 | # Hunter cache servers, including upload options. 7 | 8 | # Default Hunter cache servers. 9 | set(HUNTER_CACHE_SERVERS 10 | "https://github.com/ethereum/hunter-cache;https://github.com/ingenue/hunter-cache" 11 | CACHE STRING "Hunter cache servers") 12 | 13 | # Default path to Hunter passwords file containing information how to access 14 | # Ethereum's cache server. 15 | set(HUNTER_PASSWORDS_PATH 16 | ${CMAKE_CURRENT_LIST_DIR}/HunterCacheServers-passwords.cmake 17 | CACHE STRING "Hunter passwords file") 18 | 19 | # In CI builds upload the binaries if the HUNTER_CACHE_TOKEN was decrypted 20 | # (only for branches and internal PRs). 21 | if("$ENV{CI}" AND NOT "$ENV{HUNTER_CACHE_TOKEN}" STREQUAL "") 22 | set(run_upload YES) 23 | else() 24 | set(run_upload NO) 25 | endif() 26 | option(HUNTER_RUN_UPLOAD "Upload binaries to the Hunter cache server" ${run_upload}) 27 | unset(run_upload) 28 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Chromium 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: DontAlign 6 | BinPackParameters: true 7 | BraceWrapping: 8 | AfterClass: true 9 | AfterControlStatement: true 10 | AfterEnum: true 11 | AfterFunction: true 12 | AfterNamespace: true 13 | AfterObjCDeclaration: true 14 | AfterStruct: true 15 | AfterUnion: true 16 | BeforeCatch: true 17 | BeforeElse: true 18 | SplitEmptyFunction: false 19 | BreakBeforeBraces: Custom 20 | BreakBeforeTernaryOperators: false 21 | ColumnLimit: 100 22 | ConstructorInitializerIndentWidth: 2 23 | IncludeCategories: 24 | - Regex: '^".*' 25 | Priority: 1 26 | - Regex: '^' 29 | Priority: 2 30 | - Regex: '^<.*' 31 | Priority: 99 32 | - Regex: '.*' 33 | Priority: 4 34 | IncludeIsMainRegex: '(Test)?$' 35 | IndentCaseLabels: false 36 | IndentWidth: 4 37 | MaxEmptyLinesToKeep: 2 38 | PenaltyBreakAssignment: 1 39 | PenaltyBreakComment: 50 40 | TabWidth: 4 41 | ... 42 | -------------------------------------------------------------------------------- /cmake/cable/CableToolchains.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | set(cable_toolchain_dir ${CMAKE_CURRENT_LIST_DIR}/toolchains) 6 | 7 | function(cable_configure_toolchain) 8 | if(NOT PROJECT_IS_NESTED) 9 | # Do this configuration only in the top project. 10 | 11 | cmake_parse_arguments("" "" "DEFAULT" "" ${ARGN}) 12 | 13 | set(default_toolchain default) 14 | if(_DEFAULT) 15 | set(default_toolchain ${_DEFAULT}) 16 | endif() 17 | 18 | set(TOOLCHAIN ${default_toolchain} CACHE STRING "CMake toolchain") 19 | 20 | set(toolchain_file toolchains/${TOOLCHAIN}.cmake) 21 | foreach(path ${CMAKE_MODULE_PATH}) 22 | if(EXISTS "${path}/${toolchain_file}") 23 | set(toolchain_file "${path}/${toolchain_file}") 24 | break() 25 | endif() 26 | endforeach() 27 | 28 | cable_debug("Toolchain file: ${toolchain_file}") 29 | set(CMAKE_TOOLCHAIN_FILE ${toolchain_file} CACHE FILEPATH "CMake toolchain file") 30 | endif() 31 | endfunction() 32 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | image: Visual Studio 2017 3 | 4 | branches: 5 | only: 6 | - master 7 | - appveyor 8 | - hunter 9 | configuration: 10 | - Release 11 | environment: 12 | HUNTER_CACHE_TOKEN: 13 | secure: agYfiC1OKfHnGOJQolOBorIRovVTgDW3TJ8JOb2+0XZiAnNwbrtPegxaaFM8/VWu 14 | matrix: 15 | - ARCH: amd64 16 | PYTHON: true 17 | - ARCH: amd64 18 | CONFIGURATION: Debug 19 | - ARCH: x86 20 | 21 | install: 22 | # Set default Python version. 23 | - set PATH=C:\Python37-x64;C:\Python37-x64\Scripts;%PATH% 24 | - pip install requests 25 | 26 | before_build: 27 | - call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\vsdevcmd" -arch=%ARCH% 28 | - cmake -S . -B build -G Ninja .. -Wno-dev -DCMAKE_INSTALL_PREFIX=./dist -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DHUNTER_CONFIGURATION_TYPES=%CONFIGURATION% 29 | 30 | build_script: 31 | - cmake --build build --target install 32 | - if defined PYTHON bash scripts/ci/python_build_wheels.sh 33 | 34 | test_script: 35 | - if %CONFIGURATION%==Release C:\projects\ethash\build\test\ethash-test.exe 36 | - if defined PYTHON (set ETHASH_PYTHON_SKIP_BUILD=1 && python setup.py test) 37 | 38 | artifacts: 39 | - path: dist 40 | name: dist 41 | -------------------------------------------------------------------------------- /test/tools/kiss99_tester.cpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | constexpr uint32_t mod = 11; 12 | uint64_t histogram[mod] = {}; 13 | kiss99 rng; 14 | 15 | constexpr uint64_t output_interval = 1000000000; 16 | uint64_t output_point = output_interval; 17 | 18 | constexpr double expected = double(1) / mod; 19 | 20 | for (uint64_t i = 0; i <= uint64_t(-1); ++i) 21 | { 22 | auto x = rng() % mod; 23 | ++histogram[x]; 24 | 25 | if (i == output_point) 26 | { 27 | std::cout << std::right << std::setw(4) << (i / output_interval) 28 | << "G:" << std::fixed; 29 | 30 | // // Probabilities: 31 | // for (auto h : histogram) 32 | // std::cout << ' ' << std::setw(9) << (double(h) / double(i)); 33 | // std::cout << '\n'; 34 | 35 | // Errors: 36 | for (auto h : histogram) 37 | std::cout << ' ' << std::setw(10) << std::setprecision(6) 38 | << (double(h) / double(i) - expected) / expected * 10 << '%'; 39 | std::cout << '\n'; 40 | 41 | output_point += output_interval; 42 | } 43 | } 44 | 45 | return 0; 46 | } -------------------------------------------------------------------------------- /test/unittests/test_kiss.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | 11 | // The KISS99 reference implementation from http://www.cse.yorku.ca/~oz/marsaglia-rng.html. 12 | #define znew (z = 36969 * (z & 65535) + (z >> 16)) 13 | #define wnew (w = 18000 * (w & 65535) + (w >> 16)) 14 | #define MWC ((znew << 16) + wnew) 15 | #define SHR3 (jsr ^= (jsr << 17), jsr ^= (jsr >> 13), jsr ^= (jsr << 5)) 16 | #define CONG (jcong = 69069 * jcong + 1234567) 17 | #define KISS ((MWC ^ CONG) + SHR3) 18 | static unsigned z = 362436069, w = 521288629, jsr = 123456789, jcong = 380116160; 19 | 20 | NO_SANITIZE("unsigned-integer-overflow") 21 | static unsigned kiss_reference() 22 | { 23 | return KISS; 24 | } 25 | 26 | 27 | TEST(kiss99, generate) 28 | { 29 | kiss99 rng; 30 | 31 | EXPECT_EQ(rng(), 769445856); 32 | EXPECT_EQ(rng(), 742012328); 33 | EXPECT_EQ(rng(), 2121196314); 34 | EXPECT_EQ(rng(), 2805620942); 35 | 36 | for (int i = 0; i < 100000 - 5; ++i) 37 | rng(); 38 | 39 | // The 100000th number. 40 | EXPECT_EQ(rng(), 941074834); 41 | } 42 | 43 | TEST(kiss99, compare_with_reference) 44 | { 45 | kiss99 rng; 46 | 47 | for (int i = 0; i < 100000; ++i) 48 | EXPECT_EQ(rng(), kiss_reference()); 49 | } -------------------------------------------------------------------------------- /include/ethash/keccak.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | 12 | #ifdef __cplusplus 13 | #define NOEXCEPT noexcept 14 | #else 15 | #define NOEXCEPT 16 | #endif 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /** 23 | * The Keccak-f[1600] function. 24 | * 25 | * The implementation of the Keccak-f function with 1600-bit width of the permutation (b). 26 | * The size of the state is also 1600 bit what gives 25 64-bit words. 27 | * 28 | * @param state The state of 25 64-bit words on which the permutation is to be performed. 29 | */ 30 | void ethash_keccakf1600(uint64_t state[25]) NOEXCEPT; 31 | 32 | /** 33 | * The Keccak-f[800] function. 34 | * 35 | * The implementation of the Keccak-f function with 800-bit width of the permutation (b). 36 | * The size of the state is also 800 bit what gives 25 32-bit words. 37 | * 38 | * @param state The state of 25 32-bit words on which the permutation is to be performed. 39 | */ 40 | void ethash_keccakf800(uint32_t state[25]) NOEXCEPT; 41 | 42 | union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) NOEXCEPT; 43 | union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) NOEXCEPT; 44 | union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) NOEXCEPT; 45 | union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) NOEXCEPT; 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /cmake/cable/CableBuildType.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | if(cable_build_type_included) 6 | return() 7 | endif() 8 | set(cable_build_type_included TRUE) 9 | 10 | macro(cable_set_build_type) 11 | if(NOT PROJECT_IS_NESTED) 12 | # Do this configuration only in the top project. 13 | if(PROJECT_SOURCE_DIR) 14 | message(FATAL_ERROR "cable_set_build_type() can be used before project()") 15 | endif() 16 | 17 | cmake_parse_arguments(build_type "" DEFAULT CONFIGURATION_TYPES ${ARGN}) 18 | 19 | if(CMAKE_CONFIGURATION_TYPES) 20 | if(build_type_CONFIGURATION_TYPES) 21 | set( 22 | CMAKE_CONFIGURATION_TYPES 23 | ${build_type_CONFIGURATION_TYPES} 24 | CACHE 25 | STRING 26 | "Available configurations for multi-configuration generators" 27 | FORCE 28 | ) 29 | endif() 30 | cable_log("Configurations: ${CMAKE_CONFIGURATION_TYPES}") 31 | else() 32 | if(build_type_DEFAULT AND NOT CMAKE_BUILD_TYPE) 33 | set( 34 | CMAKE_BUILD_TYPE 35 | ${build_type_DEFAULT} 36 | CACHE STRING 37 | "Build type for single-configuration generators" 38 | FORCE 39 | ) 40 | endif() 41 | cable_log("Build type: ${CMAKE_BUILD_TYPE}") 42 | endif() 43 | endif() 44 | endmacro() 45 | -------------------------------------------------------------------------------- /bindings/python/tests/test_ethash.py: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | import unittest 6 | 7 | import ethash 8 | 9 | 10 | class TestEthash(unittest.TestCase): 11 | epoch_number = 0 12 | nonce = 0x4242424242424242 13 | header_hash = bytes.fromhex( 14 | '2a8de2adf89af77358250bf908bf04ba94a6e8c3ba87775564a41d269a05e4ce') 15 | mix_hash = bytes.fromhex( 16 | '58f759ede17a706c93f13030328bcea40c1d1341fb26f2facd21ceb0dae57017') 17 | final_hash = bytes.fromhex( 18 | 'dd47fd2d98db51078356852d7c4014e6a5d6c387c35f40e2875b74a256ed7906') 19 | 20 | def test_keccak(self): 21 | h256 = ('c5d2460186f7233c927e7db2dcc703c0' 22 | 'e500b653ca82273b7bfad8045d85a470') 23 | h512 = ('0eab42de4c3ceb9235fc91acffe746b2' 24 | '9c29a8c366b7c60e4e67c466f36a4304' 25 | 'c00fa9caf9d87976ba469bcbe06713b4' 26 | '35f091ef2769fb160cdab33d3670680e') 27 | 28 | self.assertEqual(ethash.keccak_256(b'').hex(), h256) 29 | self.assertEqual(ethash.keccak_512(b'').hex(), h512) 30 | 31 | def test_hash(self): 32 | f, m = ethash.hash(0, self.header_hash, self.nonce) 33 | self.assertEqual(m, self.mix_hash) 34 | self.assertEqual(f, self.final_hash) 35 | 36 | def test_verify(self): 37 | t = ethash.verify(0, self.header_hash, self.mix_hash, self.nonce, 38 | self.final_hash) 39 | self.assertTrue(t) 40 | self.assertEqual(type(t), bool) 41 | 42 | 43 | if __name__ == '__main__': 44 | unittest.main() 45 | -------------------------------------------------------------------------------- /test/unittests/helpers.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | #include 10 | 11 | template 12 | inline std::string to_hex(const Hash& h) 13 | { 14 | static const auto hex_chars = "0123456789abcdef"; 15 | std::string str; 16 | str.reserve(sizeof(h) * 2); 17 | for (auto b : h.bytes) 18 | { 19 | str.push_back(hex_chars[uint8_t(b) >> 4]); 20 | str.push_back(hex_chars[uint8_t(b) & 0xf]); 21 | } 22 | return str; 23 | } 24 | 25 | inline ethash::hash256 to_hash256(const std::string& hex) 26 | { 27 | auto parse_digit = [](char d) -> int { return d <= '9' ? (d - '0') : (d - 'a' + 10); }; 28 | 29 | ethash::hash256 hash = {}; 30 | for (size_t i = 1; i < hex.size(); i += 2) 31 | { 32 | int h = parse_digit(hex[i - 1]); 33 | int l = parse_digit(hex[i]); 34 | hash.bytes[i / 2] = uint8_t((h << 4) | l); 35 | } 36 | return hash; 37 | } 38 | 39 | /// Comparison operator for hash256 to be used in unit tests. 40 | inline bool operator==(const ethash::hash256& a, const ethash::hash256& b) noexcept 41 | { 42 | return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0; 43 | } 44 | 45 | inline bool operator!=(const ethash::hash256& a, const ethash::hash256& b) noexcept 46 | { 47 | return !(a == b); 48 | } 49 | 50 | inline const ethash::epoch_context& get_ethash_epoch_context_0() noexcept 51 | { 52 | static ethash::epoch_context_ptr context = ethash::create_epoch_context(0); 53 | return *context; 54 | } 55 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.5.0] - 2019-06-07 4 | 5 | - Changed: [#[131](https://github.com/chfast/ethash/pull/131)] 6 | The Keccak implementation has been moved to separate library "keccak", 7 | available as ethash::keccak target in the ethash CMake package. 8 | 9 | ## [0.4.4] - 2019-02-26 10 | 11 | - Fixed: [[#125](https://github.com/chfast/ethash/pull/125)] 12 | Fix compilation on PowerPC architectures (-mtune=generic not supported there). 13 | 14 | ## [0.4.3] - 2019-02-19 15 | 16 | - Added: [[#121](https://github.com/chfast/ethash/pull/121)] 17 | The public `version.h` header with information about the ethash library version. 18 | - Added: [[#121](https://github.com/chfast/ethash/pull/121)] 19 | Ethash and ProgPoW revisions exposed as `{ethash,progpow}::revision` constants. 20 | 21 | ## [0.4.2] - 2019-01-24 22 | 23 | - Fixed: The `progpow.cpp` file encoding changed from utf-8 to ascii. 24 | 25 | ## [0.4.1] - 2018-12-14 26 | 27 | - Added: [KISS99 PRNG](https://en.wikipedia.org/wiki/KISS_(algorithm)) distribution tester tool. 28 | - Changed: ProgPoW implementation updated to revision [0.9.2][ProgPoW-changelog]. 29 | - Changed: ProgPoW implementation optimizations. 30 | 31 | ## [0.4.0] - 2018-12-04 32 | 33 | - Added: Experimental support for [ProgPoW] [0.9.1][ProgPoW-changelog]. 34 | 35 | 36 | [0.5.0]: https://github.com/chfast/ethash/releases/tag/v0.5.0 37 | [0.4.4]: https://github.com/chfast/ethash/releases/tag/v0.4.4 38 | [0.4.3]: https://github.com/chfast/ethash/releases/tag/v0.4.3 39 | [0.4.2]: https://github.com/chfast/ethash/releases/tag/v0.4.2 40 | [0.4.1]: https://github.com/chfast/ethash/releases/tag/v0.4.1 41 | [0.4.0]: https://github.com/chfast/ethash/releases/tag/v0.4.0 42 | 43 | [ProgPoW]: https://github.com/ifdefelse/ProgPOW/blob/master/README.md 44 | [ProgPoW-changelog]: https://github.com/ifdefelse/ProgPOW#change-history 45 | -------------------------------------------------------------------------------- /bindings/python/ethash/_build.py: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | # The CFFI build script for ethash library. 6 | # It expects the library is installed in the dist/ directory. 7 | # The installation can be performed by 8 | # 9 | # cmake . -DCMAKE_INSTALL_PREFIX=dist 10 | # make 11 | # make install 12 | 13 | from cffi import FFI 14 | import sys 15 | 16 | ffibuilder = FFI() 17 | 18 | stdlib = [] 19 | if sys.platform == 'linux': 20 | stdlib.append('stdc++') 21 | 22 | ffibuilder.set_source( 23 | "_ethash", 24 | r""" 25 | #include 26 | #include 27 | """, 28 | include_dirs=['include'], 29 | libraries=['ethash', 'keccak'] + stdlib, 30 | ) 31 | 32 | ffibuilder.cdef(""" 33 | 34 | union ethash_hash256 35 | { 36 | ...; 37 | char str[32]; 38 | }; 39 | 40 | union ethash_hash512 41 | { 42 | ...; 43 | char str[64]; 44 | }; 45 | 46 | struct ethash_result 47 | { 48 | union ethash_hash256 final_hash; 49 | union ethash_hash256 mix_hash; 50 | }; 51 | 52 | 53 | union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size); 54 | 55 | union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size); 56 | 57 | const struct ethash_epoch_context* ethash_get_global_epoch_context(int epoch_number); 58 | 59 | struct ethash_result ethash_hash(const struct ethash_epoch_context* context, 60 | const union ethash_hash256* header_hash, uint64_t nonce); 61 | 62 | bool ethash_verify(const struct ethash_epoch_context* context, 63 | const union ethash_hash256* header_hash, const union ethash_hash256* mix_hash, uint64_t nonce, 64 | const union ethash_hash256* boundary); 65 | 66 | """) 67 | 68 | if __name__ == "__main__": 69 | ffibuilder.compile(verbose=True) 70 | -------------------------------------------------------------------------------- /bindings/python/ethash/__init__.py: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | from _ethash import ffi, lib 6 | 7 | 8 | def keccak_256(data): 9 | hash = lib.ethash_keccak256(ffi.from_buffer(data), len(data)) 10 | return ffi.unpack(hash.str, len(hash.str)) 11 | 12 | 13 | def keccak_512(data): 14 | hash = lib.ethash_keccak512(ffi.from_buffer(data), len(data)) 15 | return ffi.unpack(hash.str, len(hash.str)) 16 | 17 | 18 | def hash(epoch_number, header_hash, nonce): 19 | if len(header_hash) != 32: 20 | raise ValueError('header_hash must have length of 32') 21 | 22 | ctx = lib.ethash_get_global_epoch_context(epoch_number) 23 | c_header_hash = ffi.new('union ethash_hash256*') 24 | c_header_hash[0].str = header_hash 25 | result = lib.ethash_hash(ctx, c_header_hash, nonce) 26 | final_hash = ffi.unpack(result.final_hash.str, len(result.final_hash.str)) 27 | mix_hash = ffi.unpack(result.mix_hash.str, len(result.mix_hash.str)) 28 | return final_hash, mix_hash 29 | 30 | 31 | def verify(epoch_number, header_hash, mix_hash, nonce, boundary): 32 | if len(header_hash) != 32: 33 | raise ValueError('header_hash must have length of 32') 34 | if len(mix_hash) != 32: 35 | raise ValueError('mix_hash must have length of 32') 36 | if len(boundary) != 32: 37 | raise ValueError('boundary must have length of 32') 38 | 39 | ctx = lib.ethash_get_global_epoch_context(epoch_number) 40 | c_header_hash = ffi.new('union ethash_hash256*') 41 | c_header_hash[0].str = header_hash 42 | c_mix_hash = ffi.new('union ethash_hash256*') 43 | c_mix_hash[0].str = mix_hash 44 | c_boundary = ffi.new('union ethash_hash256*') 45 | c_boundary[0].str = boundary 46 | 47 | return lib.ethash_verify(ctx, c_header_hash, c_mix_hash, nonce, c_boundary) 48 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/gitinfo.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | # Execute git only if the tool is available. 6 | if(GIT) 7 | execute_process( 8 | COMMAND ${GIT} describe --always --long --tags --first-parent --match=v* --abbrev=40 --dirty 9 | WORKING_DIRECTORY ${SOURCE_DIR} 10 | OUTPUT_VARIABLE gitinfo 11 | OUTPUT_STRIP_TRAILING_WHITESPACE 12 | ERROR_VARIABLE error 13 | ERROR_STRIP_TRAILING_WHITESPACE 14 | ) 15 | if(error) 16 | message(WARNING "Git ${error}") 17 | endif() 18 | 19 | execute_process( 20 | COMMAND ${GIT} rev-parse --abbrev-ref HEAD 21 | WORKING_DIRECTORY ${SOURCE_DIR} 22 | OUTPUT_VARIABLE gitbranch 23 | OUTPUT_STRIP_TRAILING_WHITESPACE 24 | ERROR_VARIABLE error 25 | ERROR_STRIP_TRAILING_WHITESPACE 26 | ) 27 | if(error) 28 | message(WARNING "Git ${error}") 29 | else() 30 | set(gitinfo "${gitinfo}\n${gitbranch}") 31 | endif() 32 | 33 | execute_process( 34 | COMMAND ${GIT} config --get remote.origin.url 35 | WORKING_DIRECTORY ${SOURCE_DIR} 36 | OUTPUT_VARIABLE gitorigin 37 | OUTPUT_STRIP_TRAILING_WHITESPACE 38 | ERROR_VARIABLE error 39 | ERROR_STRIP_TRAILING_WHITESPACE 40 | ) 41 | if(error) 42 | message(WARNING "Git ${error}") 43 | else() 44 | set(gitinfo "${gitinfo}\n${gitorigin}\n") 45 | endif() 46 | endif() 47 | 48 | set(gitinfo_file ${OUTPUT_DIR}/gitinfo.txt) 49 | 50 | if(EXISTS ${gitinfo_file}) 51 | file(READ ${gitinfo_file} prev_gitinfo) 52 | else() 53 | # Create empty file, because other targets expect it to exist. 54 | file(WRITE ${gitinfo_file} "") 55 | endif() 56 | 57 | if(NOT "${gitinfo}" STREQUAL "${prev_gitinfo}") 58 | file(WRITE ${gitinfo_file} ${gitinfo}) 59 | endif() 60 | -------------------------------------------------------------------------------- /lib/ethash/kiss99.hpp: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "../support/attributes.h" 9 | #include 10 | 11 | /** 12 | * KISS PRNG by the spec from 1999. 13 | * 14 | * The implementation of KISS pseudo-random number generator 15 | * by the specification published on 21 Jan 1999 in 16 | * http://www.cse.yorku.ca/~oz/marsaglia-rng.html. 17 | * The KISS is not versioned so here we are using `kiss99` prefix to indicate 18 | * the version from 1999. 19 | * 20 | * The specification uses `unsigned long` type with the intention for 32-bit 21 | * values. Because in GCC/clang for 64-bit architectures `unsigned long` is 22 | * 64-bit size type, here the explicit `uint32_t` type is used. 23 | * 24 | * @defgroup kiss99 KISS99 25 | * @{ 26 | */ 27 | 28 | /** 29 | * The KISS generator. 30 | */ 31 | class kiss99 32 | { 33 | uint32_t z = 362436069; 34 | uint32_t w = 521288629; 35 | uint32_t jsr = 123456789; 36 | uint32_t jcong = 380116160; 37 | 38 | public: 39 | /** Creates KISS generator state with default values provided by the specification. */ 40 | kiss99() noexcept = default; 41 | 42 | /** Creates KISS generator state with provided init values.*/ 43 | kiss99(uint32_t _z, uint32_t _w, uint32_t _jsr, uint32_t _jcong) noexcept 44 | : z{_z}, w{_w}, jsr{_jsr}, jcong{_jcong} 45 | {} 46 | 47 | /** Generates next number from the KISS generator. */ 48 | NO_SANITIZE("unsigned-integer-overflow") 49 | uint32_t operator()() noexcept 50 | { 51 | z = 36969 * (z & 0xffff) + (z >> 16); 52 | w = 18000 * (w & 0xffff) + (w >> 16); 53 | 54 | jcong = 69069 * jcong + 1234567; 55 | 56 | jsr ^= (jsr << 17); 57 | jsr ^= (jsr >> 13); 58 | jsr ^= (jsr << 5); 59 | 60 | return (((z << 16) + w) ^ jcong) + jsr; 61 | } 62 | }; 63 | 64 | /** @} */ 65 | -------------------------------------------------------------------------------- /include/ethash/progpow.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | /// @file 6 | /// 7 | /// ProgPoW API 8 | /// 9 | /// This file provides the public API for ProgPoW as the Ethash API extension. 10 | 11 | #include 12 | 13 | namespace progpow 14 | { 15 | using namespace ethash; // Include ethash namespace. 16 | 17 | 18 | /// The ProgPoW algorithm revision implemented as specified in the spec 19 | /// https://github.com/ifdefelse/ProgPOW#change-history. 20 | constexpr auto revision = "0.9.4"; 21 | 22 | constexpr int period_length = 3; 23 | constexpr uint32_t num_regs = 32; 24 | constexpr size_t num_lanes = 16; 25 | constexpr int num_cache_accesses = 11; 26 | constexpr int num_math_operations = 18; 27 | constexpr size_t l1_cache_size = 16 * 1024; 28 | constexpr size_t l1_cache_num_items = l1_cache_size / sizeof(uint32_t); 29 | 30 | result hash(const epoch_context& context, int block_number, const hash256& header_hash, 31 | uint64_t nonce) noexcept; 32 | 33 | result hash(const epoch_context_full& context, int block_number, const hash256& header_hash, 34 | uint64_t nonce) noexcept; 35 | 36 | bool verify(const epoch_context& context, int block_number, const hash256& header_hash, 37 | const hash256& mix_hash, uint64_t nonce, const hash256& boundary) noexcept; 38 | 39 | //bool light_verify(const char* str_header_hash, 40 | // const char* str_mix_hash, const char* str_nonce, const char* str_boundary, char* str_final) noexcept; 41 | 42 | search_result search_light(const epoch_context& context, int block_number, 43 | const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, 44 | size_t iterations) noexcept; 45 | 46 | search_result search(const epoch_context_full& context, int block_number, 47 | const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, 48 | size_t iterations) noexcept; 49 | 50 | } // namespace progpow 51 | -------------------------------------------------------------------------------- /lib/ethash/bit_manipulation.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "builtins.h" 9 | #include "../support/attributes.h" 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | static inline uint32_t rotl32(uint32_t n, unsigned int c) 18 | { 19 | const unsigned int mask = 31; 20 | 21 | c &= mask; 22 | unsigned int neg_c = (unsigned int)(-(int)c); 23 | return (n << c) | (n >> (neg_c & mask)); 24 | } 25 | 26 | static inline uint32_t rotr32(uint32_t n, unsigned int c) 27 | { 28 | const unsigned int mask = 31; 29 | 30 | c &= mask; 31 | unsigned int neg_c = (unsigned int)(-(int)c); 32 | return (n >> c) | (n << (neg_c & mask)); 33 | } 34 | 35 | static inline uint32_t clz32(uint32_t x) 36 | { 37 | return x ? (uint32_t)__builtin_clz(x) : 32; 38 | } 39 | 40 | static inline uint32_t popcount32(uint32_t x) 41 | { 42 | return (uint32_t)__builtin_popcount(x); 43 | } 44 | 45 | static inline uint32_t mul_hi32(uint32_t x, uint32_t y) 46 | { 47 | return (uint32_t)(((uint64_t)x * (uint64_t)y) >> 32); 48 | } 49 | 50 | 51 | /** FNV 32-bit prime. */ 52 | static const uint32_t fnv_prime = 0x01000193; 53 | 54 | /** FNV 32-bit offset basis. */ 55 | static const uint32_t fnv_offset_basis = 0x811c9dc5; 56 | 57 | /** 58 | * The implementation of FNV-1 hash. 59 | * 60 | * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash. 61 | */ 62 | NO_SANITIZE("unsigned-integer-overflow") 63 | static inline uint32_t fnv1(uint32_t u, uint32_t v) noexcept 64 | { 65 | return (u * fnv_prime) ^ v; 66 | } 67 | 68 | /** 69 | * The implementation of FNV-1a hash. 70 | * 71 | * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash. 72 | */ 73 | NO_SANITIZE("unsigned-integer-overflow") 74 | static inline uint32_t fnv1a(uint32_t u, uint32_t v) noexcept 75 | { 76 | return (u ^ v) * fnv_prime; 77 | } 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | -------------------------------------------------------------------------------- /test/benchmarks/threadsync_utils.cpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include "threadsync_utils.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | struct fake_cache : std::enable_shared_from_this 12 | { 13 | int id = -1; 14 | int payload = 0; 15 | }; 16 | 17 | std::shared_ptr build_fake_cache(int id) noexcept 18 | { 19 | auto handle = std::make_shared(); 20 | handle->id = id; 21 | handle->payload = id * id; 22 | return handle; 23 | } 24 | 25 | std::shared_ptr build_sentinel() noexcept 26 | { 27 | static thread_local fake_cache sentinel; 28 | return std::shared_ptr(&sentinel, [](fake_cache*){}); 29 | } 30 | 31 | std::shared_ptr build_sentinel2() noexcept 32 | { 33 | return std::make_shared(); 34 | } 35 | 36 | namespace 37 | { 38 | std::shared_ptr handle_nosync = build_sentinel(); 39 | } 40 | 41 | bool verify_fake_cache_nosync(int id, int value) noexcept 42 | { 43 | if (handle_nosync->id != id) 44 | handle_nosync = build_fake_cache(id); 45 | return handle_nosync->payload == value; 46 | } 47 | 48 | namespace 49 | { 50 | std::shared_ptr handle_mutex; 51 | std::mutex mutex; 52 | } // namespace 53 | 54 | bool verify_fake_cache_mutex(int id, int value) noexcept 55 | { 56 | std::lock_guard lock{mutex}; 57 | 58 | if (!handle_mutex || handle_mutex->id != id) 59 | handle_mutex = build_fake_cache(id); 60 | return handle_mutex->payload == value; 61 | } 62 | 63 | namespace 64 | { 65 | thread_local std::shared_ptr handle_thread_local = build_sentinel(); 66 | std::mutex build_mutex; 67 | } // namespace 68 | 69 | bool verify_fake_cache_thread_local(int id, int value) noexcept 70 | { 71 | if (handle_thread_local->id != id) 72 | { 73 | std::lock_guard lock{build_mutex}; 74 | handle_thread_local = build_fake_cache(id); 75 | } 76 | return handle_thread_local->payload == value; 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ethash 2 | 3 | [![readme style standard](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) 4 | 5 | > C/C++ implementation of Ethash – the Ethereum Proof of Work algorithm 6 | 7 | 8 | ## Table of Contents 9 | 10 | - [Install](#install) 11 | - [Usage](#usage) 12 | - [Test vectors](#test-vectors) 13 | - [Optimizations](#optimizations) 14 | - [Maintainer](#maintainer) 15 | - [License](#license) 16 | 17 | 18 | ## Install 19 | 20 | Build from source using CMake. 21 | 22 | ```sh 23 | mkdir build 24 | cd build 25 | cmake .. 26 | cmake --build . 27 | ``` 28 | 29 | ## Usage 30 | 31 | See [ethash.hpp] for list of exported function and documentation. 32 | 33 | 34 | ## Test vectors 35 | 36 | - [ProgPoW test vectors](test/unittests/progpow_test_vectors.hpp) 37 | 38 | 39 | ## Optimizations 40 | 41 | This section decscribes the optimizations, modification and tweaks applied 42 | in this library in relation to [Ethash reference implementation]. 43 | 44 | The library contains a set of micro-benchmarks. Build and run `bench` tool. 45 | 46 | ### Seed hash is computed on the fly. 47 | 48 | Seed hash is sequence of keccak256 hashes applied the epoch number of times. 49 | Time needed to compute seed hash is negligible comparing to time needed to build 50 | light cache. Computing seed hash for epoch 10000 takes ~ 5 ms, building light 51 | cache for epoch 1 takes ~ 500 ms. 52 | 53 | ### Dataset size is computed on the fly 54 | 55 | Computing the size of full dataset and light cache requires finding the largest 56 | prime number given an upper bound. For similar reasons as with seed hash, this 57 | is computed on the fly. The procedure used is quite naive and forks well only 58 | up to 40-bit number, so some additional improvement can be done in future. 59 | 60 | 61 | ## Maintainer 62 | 63 | Paweł Bylica [@chfast] 64 | 65 | ## License 66 | 67 | Licensed under the [Apache License, Version 2.0]. 68 | 69 | 70 | [@chfast]: https://github.com/chfast 71 | [Apache License, Version 2.0]: LICENSE 72 | [ethash.hpp]: include/ethash/ethash.hpp 73 | [Ethash reference implementation]: https://github.com/ethereum/wiki/wiki/Ethash 74 | -------------------------------------------------------------------------------- /cmake/cable/bootstrap.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | # Bootstrap the Cable - CMake Bootstrap Library by including this file. 6 | # e.g. include(cmake/cable/bootstrap.cmake). 7 | 8 | 9 | # Cable version. 10 | # 11 | # This is internal variable automatically updated with external tools. 12 | # Use CABLE_VERSION variable if you need this information. 13 | set(version 0.4.1) 14 | 15 | # For convenience, add the project CMake module dir to module path. 16 | set(module_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 17 | if(EXISTS ${module_dir}) 18 | list(APPEND CMAKE_MODULE_PATH ${module_dir}) 19 | endif() 20 | 21 | if(CABLE_VERSION) 22 | # Some other instance of Cable has been initialized in the top project. 23 | 24 | # Mark this project as nested. 25 | set(PROJECT_IS_NESTED TRUE) 26 | 27 | # Compare versions of the top project and this instances. 28 | if(CABLE_VERSION VERSION_LESS version) 29 | set(comment " (version older than ${version})") 30 | elseif(CABLE_VERSION VERSION_GREATER version) 31 | set(comment " (version newer than ${version})") 32 | endif() 33 | 34 | # Log information about initialization in the top project. 35 | file(RELATIVE_PATH subproject_dir ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) 36 | cable_debug("${subproject_dir}: Cable ${CABLE_VERSION}${comment} already initialized in the top project") 37 | cable_debug("Project CMake modules directory: ${module_dir}") 38 | 39 | unset(version) 40 | unset(module_dir) 41 | unset(comment) 42 | return() 43 | endif() 44 | 45 | 46 | option(CABLE_DEBUG "Enable Cable debug logs" OFF) 47 | 48 | function(cable_log) 49 | message(STATUS "[cable ] ${ARGN}") 50 | endfunction() 51 | 52 | function(cable_debug) 53 | if(CABLE_DEBUG) 54 | message(STATUS "[cable*] ${ARGN}") 55 | endif() 56 | endfunction() 57 | 58 | # Export Cable version. 59 | set(CABLE_VERSION ${version}) 60 | 61 | # Mark this project as non-nested. 62 | set(PROJECT_IS_NESTED FALSE) 63 | 64 | # Add Cable modules to the CMake module path. 65 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 66 | 67 | cable_log("Cable ${CABLE_VERSION} initialized") 68 | cable_debug("Project CMake modules directory: ${module_dir}") 69 | 70 | unset(version) 71 | unset(module_dir) 72 | -------------------------------------------------------------------------------- /lib/ethash/ethash-internal.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | /// @file 6 | /// Contains declarations of internal ethash functions to allow them to be 7 | /// unit-tested. 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | #include "endianness.hpp" 14 | 15 | #include 16 | #include 17 | 18 | extern "C" struct ethash_epoch_context_full : ethash_epoch_context 19 | { 20 | ethash_hash1024* full_dataset; 21 | 22 | constexpr ethash_epoch_context_full(int epoch, int light_num_items, 23 | const ethash_hash512* light, const uint32_t* l1, int dataset_num_items, 24 | ethash_hash1024* dataset) noexcept 25 | : ethash_epoch_context{epoch, light_num_items, light, l1, dataset_num_items}, 26 | full_dataset{dataset} 27 | {} 28 | }; 29 | 30 | namespace ethash 31 | { 32 | inline bool is_less_or_equal(const hash256& a, const hash256& b) noexcept 33 | { 34 | for (size_t i = 0; i < (sizeof(a) / sizeof(a.word64s[0])); ++i) 35 | { 36 | if (be::uint64(a.word64s[i]) > be::uint64(b.word64s[i])) 37 | return false; 38 | if (be::uint64(a.word64s[i]) < be::uint64(b.word64s[i])) 39 | return true; 40 | } 41 | return true; 42 | } 43 | 44 | inline bool is_equal(const hash256& a, const hash256& b) noexcept 45 | { 46 | return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0; 47 | } 48 | 49 | void build_light_cache(hash512 cache[], int num_items, const hash256& seed) noexcept; 50 | 51 | hash512 calculate_dataset_item_512(const epoch_context& context, int64_t index) noexcept; 52 | hash1024 calculate_dataset_item_1024(const epoch_context& context, uint32_t index) noexcept; 53 | hash2048 calculate_dataset_item_2048(const epoch_context& context, uint32_t index) noexcept; 54 | 55 | namespace generic 56 | { 57 | using hash_fn_512 = hash512 (*)(const uint8_t* data, size_t size); 58 | using build_light_cache_fn = void (*)(hash512 cache[], int num_items, const hash256& seed); 59 | 60 | void build_light_cache( 61 | hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256& seed) noexcept; 62 | 63 | epoch_context_full* create_epoch_context( 64 | build_light_cache_fn build_fn, int epoch_number, bool full) noexcept; 65 | 66 | } // namespace generic 67 | 68 | } // namespace ethash 69 | -------------------------------------------------------------------------------- /test/fuzzing/keccak_fuzzer.cpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | extern "C" { 13 | 14 | typedef struct sha3_ctx 15 | { 16 | uint64_t hash[25]; 17 | uint64_t message[24]; 18 | unsigned rest; 19 | unsigned block_size; 20 | } sha3_ctx; 21 | 22 | void rhash_sha3_256_init(sha3_ctx* ctx) noexcept; 23 | void rhash_sha3_512_init(sha3_ctx* ctx) noexcept; 24 | void rhash_sha3_update(sha3_ctx* ctx, const unsigned char* msg, size_t size) noexcept; 25 | void rhash_keccak_final(sha3_ctx* ctx, unsigned char* result) noexcept; 26 | 27 | int keccak_tiny_256(uint8_t* out, size_t outlen, const uint8_t* in, size_t inlen) noexcept; 28 | int keccak_tiny_512(uint8_t* out, size_t outlen, const uint8_t* in, size_t inlen) noexcept; 29 | } 30 | 31 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* input, size_t size) 32 | { 33 | // ethash: 34 | 35 | const auto h256_ethash = ethash_keccak256(input, size); 36 | const auto h512_ethash = ethash_keccak512(input, size); 37 | 38 | 39 | // tiny: 40 | 41 | ethash_hash256 h256_tiny; 42 | int r = keccak_tiny_256(h256_tiny.bytes, sizeof(h256_tiny), input, size); 43 | if (r != 0) 44 | __builtin_trap(); 45 | 46 | ethash_hash512 h512_tiny; 47 | r = keccak_tiny_512(h512_tiny.bytes, sizeof(h512_tiny), input, size); 48 | if (r != 0) 49 | __builtin_trap(); 50 | 51 | 52 | // rhash: 53 | 54 | sha3_ctx ctx; 55 | 56 | ethash_hash256 h256_rhash; 57 | rhash_sha3_256_init(&ctx); 58 | rhash_sha3_update(&ctx, input, size); 59 | rhash_keccak_final(&ctx, h256_rhash.bytes); 60 | 61 | ethash_hash512 h512_rhash; 62 | rhash_sha3_512_init(&ctx); 63 | rhash_sha3_update(&ctx, input, size); 64 | rhash_keccak_final(&ctx, h512_rhash.bytes); 65 | 66 | 67 | // Compare. 68 | 69 | if (std::memcmp(&h256_ethash, &h256_tiny, sizeof(h256_ethash)) != 0) 70 | __builtin_trap(); 71 | 72 | if (std::memcmp(&h256_ethash, &h256_rhash, sizeof(h256_ethash)) != 0) 73 | { 74 | std::cerr << "Here!"; 75 | __builtin_trap(); 76 | } 77 | 78 | 79 | if (std::memcmp(&h512_ethash, &h512_tiny, sizeof(h512_ethash)) != 0) 80 | __builtin_trap(); 81 | 82 | if (std::memcmp(&h512_ethash, &h512_rhash, sizeof(h512_ethash)) != 0) 83 | __builtin_trap(); 84 | 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /lib/ethash/endianness.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | /// @file 6 | /// This file contains helper functions to handle big-endian architectures. 7 | /// The Ethash algorithm is naturally defined for little-endian architectures 8 | /// so for those the helpers are just no-op empty functions. 9 | /// For big-endian architectures we need 32-bit and 64-bit byte swapping in 10 | /// some places. 11 | 12 | #pragma once 13 | 14 | #include 15 | 16 | #if _WIN32 17 | 18 | #include 19 | 20 | #define bswap32 _byteswap_ulong 21 | #define bswap64 _byteswap_uint64 22 | 23 | // On Windows assume little endian. 24 | #define __LITTLE_ENDIAN 1234 25 | #define __BIG_ENDIAN 4321 26 | #define __BYTE_ORDER __LITTLE_ENDIAN 27 | 28 | #elif __APPLE__ 29 | 30 | #include 31 | 32 | #define bswap32 __builtin_bswap32 33 | #define bswap64 __builtin_bswap64 34 | 35 | #else 36 | 37 | #include 38 | 39 | #define bswap32 __builtin_bswap32 40 | #define bswap64 __builtin_bswap64 41 | 42 | #endif 43 | 44 | namespace ethash 45 | { 46 | #if __BYTE_ORDER == __LITTLE_ENDIAN 47 | 48 | struct le 49 | { 50 | static uint32_t uint32(uint32_t x) noexcept { return x; } 51 | static uint64_t uint64(uint64_t x) noexcept { return x; } 52 | 53 | static const hash1024& uint32s(const hash1024& h) noexcept { return h; } 54 | static const hash512& uint32s(const hash512& h) noexcept { return h; } 55 | static const hash256& uint32s(const hash256& h) noexcept { return h; } 56 | }; 57 | 58 | struct be 59 | { 60 | static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); } 61 | }; 62 | 63 | 64 | #elif __BYTE_ORDER == __BIG_ENDIAN 65 | 66 | struct le 67 | { 68 | static uint32_t uint32(uint32_t x) noexcept { return bswap32(x); } 69 | static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); } 70 | 71 | static hash1024 uint32s(hash1024 h) noexcept 72 | { 73 | for (auto& w : h.word32s) 74 | w = uint32(w); 75 | return h; 76 | } 77 | 78 | static hash512 uint32s(hash512 h) noexcept 79 | { 80 | for (auto& w : h.word32s) 81 | w = uint32(w); 82 | return h; 83 | } 84 | 85 | static hash256 uint32s(hash256 h) noexcept 86 | { 87 | for (auto& w : h.word32s) 88 | w = uint32(w); 89 | return h; 90 | } 91 | }; 92 | 93 | struct be 94 | { 95 | static uint64_t uint64(uint64_t x) noexcept { return x; } 96 | }; 97 | 98 | #endif 99 | } // namespace ethash -------------------------------------------------------------------------------- /test/unittests/test_bit_manipulation.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | 7 | #include 8 | 9 | TEST(bit_manipulation, rotl32) 10 | { 11 | EXPECT_EQ(rotl32(0, 0), 0); 12 | EXPECT_EQ(rotl32(0, 4321), 0); 13 | 14 | EXPECT_EQ(rotl32(1, 0), 1); 15 | EXPECT_EQ(rotl32(1, 1), 2); 16 | EXPECT_EQ(rotl32(1, 2), 4); 17 | EXPECT_EQ(rotl32(1, 31), 1u << 31); 18 | EXPECT_EQ(rotl32(1, 32), 1); 19 | EXPECT_EQ(rotl32(1, 33), 2); 20 | 21 | EXPECT_EQ(rotl32(3, 0), 3); 22 | EXPECT_EQ(rotl32(3, 1), 6); 23 | EXPECT_EQ(rotl32(3, 30), 3u << 30); 24 | EXPECT_EQ(rotl32(3, 31), (1u << 31) | 1); 25 | EXPECT_EQ(rotl32(3, 32), 3); 26 | EXPECT_EQ(rotl32(3, 33), 6); 27 | } 28 | 29 | TEST(bit_manipulation, rotr32) 30 | { 31 | EXPECT_EQ(rotr32(0, 0), 0); 32 | EXPECT_EQ(rotr32(0, 4321), 0); 33 | 34 | EXPECT_EQ(rotr32(1, 0), 1); 35 | EXPECT_EQ(rotr32(1, 1), 1u << 31); 36 | EXPECT_EQ(rotr32(1, 2), 1u << 30); 37 | EXPECT_EQ(rotr32(1, 30), 1u << 2); 38 | EXPECT_EQ(rotr32(1, 31), 1u << 1); 39 | EXPECT_EQ(rotr32(1, 32), 1); 40 | EXPECT_EQ(rotr32(1, 33), 1u << 31); 41 | 42 | EXPECT_EQ(rotr32(3, 0), 3); 43 | EXPECT_EQ(rotr32(3, 1), (1u << 31) | 1); 44 | EXPECT_EQ(rotr32(3, 2), (3u << 30)); 45 | EXPECT_EQ(rotr32(3, 30), 12); 46 | EXPECT_EQ(rotr32(3, 31), 6); 47 | EXPECT_EQ(rotr32(3, 32), 3); 48 | EXPECT_EQ(rotr32(3, 33), (1u << 31) | 1); 49 | } 50 | 51 | TEST(bit_manipulation, clz32) 52 | { 53 | EXPECT_EQ(clz32(0), 32); 54 | EXPECT_EQ(clz32(1), 31); 55 | EXPECT_EQ(clz32(1 << 1), 30); 56 | EXPECT_EQ(clz32(1 << 2), 29); 57 | EXPECT_EQ(clz32(1 << 30), 1); 58 | EXPECT_EQ(clz32(1u << 31), 0); 59 | EXPECT_EQ(clz32(4321), 19); 60 | } 61 | 62 | TEST(bit_manipulation, popcount32) 63 | { 64 | EXPECT_EQ(popcount32(0), 0); 65 | EXPECT_EQ(popcount32(1), 1); 66 | EXPECT_EQ(popcount32(1 << 16), 1); 67 | EXPECT_EQ(popcount32(3), 2); 68 | EXPECT_EQ(popcount32(3 << 17), 2); 69 | EXPECT_EQ(popcount32(9 << 18), 2); 70 | EXPECT_EQ(popcount32(~0u), 32); 71 | } 72 | 73 | TEST(bit_manipulation, mul_hi32) 74 | { 75 | EXPECT_EQ(mul_hi32(0, 0), 0); 76 | EXPECT_EQ(mul_hi32(0, 1), 0); 77 | EXPECT_EQ(mul_hi32(1, 0), 0); 78 | EXPECT_EQ(mul_hi32(1, 1), 0); 79 | 80 | EXPECT_EQ(mul_hi32(1 << 16, 1 << 16), 1); 81 | EXPECT_EQ(mul_hi32(1 << 16, (1 << 16) + 1), 1); 82 | 83 | EXPECT_EQ(mul_hi32(1 << 30, 1 << 30), 1 << 28); 84 | EXPECT_EQ(mul_hi32(1u << 31, 1u << 31), 1 << 30); 85 | 86 | EXPECT_EQ(mul_hi32(~0u, ~0u), ~0u - 1); 87 | } 88 | -------------------------------------------------------------------------------- /test/unittests/test_cases.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Pawel Bylica. 2 | // Licensed under the Apache License, Version 2.0. 3 | 4 | /// @file 5 | /// Shared test cases. 6 | 7 | #pragma once 8 | 9 | // Put in anonymous namespace to allow be include in multiple files 10 | // but also make iteration over test cases easy with range-based for loop. 11 | namespace 12 | { 13 | struct hash_test_case 14 | { 15 | int block_number; 16 | const char* header_hash_hex; 17 | const char* nonce_hex; 18 | const char* mix_hash_hex; 19 | const char* final_hash_hex; 20 | }; 21 | 22 | hash_test_case hash_test_cases[] = { 23 | { 24 | 0, 25 | "2a8de2adf89af77358250bf908bf04ba94a6e8c3ba87775564a41d269a05e4ce", 26 | "4242424242424242", 27 | "89b6b75f64a89b05393536d14ccea1f8b40d8dffab98d5a812e2f9210d5118d3", 28 | "89b612bfaf68f940af983f44fc22df6dfc2836a8f6d5f9da4ebe483d868761c5", 29 | }, 30 | { 31 | 2, 32 | "100cbec5e5ef82991290d0d93d758f19082e71f234cf479192a8b94df6da6bfe", 33 | "307692cf71b12f6d", 34 | "8cdb6f34b433e7871a672c925a7516c469596739b720112b8513e34843cd811f", 35 | "c6ad74a4ea186a1563bc42606601ab8100712c828394b9eb7f5d37bb5905ca0a", 36 | }, 37 | { 38 | 2683077, 39 | "0313d03c5ed78694c90ecb3d04190b82d5b222c75ba4cab83383dde4d11ed512", 40 | "8c5eaec000788d41", 41 | "052f29b0ea082c24f61fc1c3384de2805fedeccd48d92b10c48ed9c09ae34f7a", 42 | "4fd5a26e463e692ebfd7db5865944fe00c4e4adae189d0fc8155e025e60692f9", 43 | }, 44 | { 45 | 5000000, 46 | "bc544c2baba832600013bd5d1983f592e9557d04b0fb5ef7a100434a5fc8d52a", 47 | "4617a20003ba3f25", 48 | "a25fa04b54699e1db81a58501af4dda06216f7e17713406af0c9a72765a9d9c3", 49 | "00f9ac66c49a290c8befe9db144cf88a9fe5e761fa1564cecf539c13eec8d35b", 50 | }, 51 | { 52 | 5000001, 53 | "2cd14041cfc3bd13064cfd58e26c0bddf1e97a4202c4b8076444a7cd4515f8c3", 54 | "1af47f2007922384", 55 | "fcd2884114f61bc39c34c4f52ee36aaf22b66037c4b523ada29efe71cb79750f", 56 | "c293d1a78b773dd1709f029347a384abc4472fe5d23f703d4757e610ae8f5bae", 57 | }, 58 | { 59 | 5000002, 60 | "9e79bced19062baf7c47e516ad3a1bd779222404d05b4205def30a13c7d87b5b", 61 | "c9a044201dd998f2", 62 | "1d5b97ac3d2c6a7e5cc34d48cb05251db68db2c2d9cfc9c9c6f01146d47f6dd4", 63 | "c6d434f7ce14378855af7b370acf9085f21c0aea5c1b55d90d74968e89accfc5", 64 | }, 65 | { 66 | 5306861, 67 | "53a005f209a4dc013f022a5078c6b38ced76e767a30367ff64725f23ec652a9f", 68 | "d337f82001e992c5", 69 | "e5088e744e78343b155944647ff92c625286841bd1c687a1e778778e078151ca", 70 | "9c48d5ff9744beb63214001acb735bd440ab3e153a56093a223405e32f769543", 71 | }, 72 | }; 73 | } // namespace -------------------------------------------------------------------------------- /cmake/cable/README.md: -------------------------------------------------------------------------------- 1 | # Cable 2 | 3 | [![readme style: standard][readme style standard badge]][standard readme] 4 | 5 | > Cable: CMake Bootstrap Library 6 | 7 | Cable is a set of CMake modules and scripts containing common patterns used 8 | in CMake-based C++ projects. The design goal is to be pragmatic rather than 9 | generic so the number of provided options is minimal. The Cable modules are 10 | independent and it is easy to use them individually. 11 | 12 | 13 | ## Table of Contents 14 | 15 | - [Install](#install) 16 | - [Usage](#usage) 17 | - [Maintainer](#maintainer) 18 | - [License](#license) 19 | 20 | 21 | ## Install 22 | 23 | The suggested Cable location is `cmake/cable` relative to your project root directory. 24 | 25 | ### As git subtree 26 | 27 | Adding a dependency project as a [git subtree] is just a copy of the source code 28 | done in a bit more systematic way. 29 | 30 | If you are not familiar with managing dependencies with git subtree read the 31 | [Git subtree: the alternative to Git submodule][git subtree tutorial]. 32 | 33 | #### To install 34 | 35 | ```sh 36 | git remote add cable https://github.com/ethereum/cable 37 | git subtree add --prefix cmake/cable cable master --squash 38 | ``` 39 | 40 | #### To update 41 | 42 | ```sh 43 | git subtree pull --prefix cmake/cable cable master --squash 44 | ``` 45 | 46 | ### As git submodule 47 | 48 | Include the Cable library as [git submodule] in your project. 49 | 50 | ```sh 51 | git submodule add https://github.com/ethereum/cable cmake/cable 52 | ``` 53 | 54 | ## Usage 55 | 56 | Cable contains the `bootstrap.cmake` file that initializes the library. 57 | Start by including this file in your main `CMakeLists.txt` from the Cable 58 | submodule/subtree or any other location. The `bootstrap.cmake` must be included 59 | before the `project()` command. After that, you can include and use other 60 | Cable modules. 61 | 62 | ### Example 63 | 64 | ```cmake 65 | cmake_minimum_required(VERSION 3.5) 66 | 67 | include(cmake/cable/bootstrap.cmake) 68 | include(CableBuildType) 69 | 70 | project(tothemoon) 71 | 72 | cable_set_build_type(DEFAULT RelWithDebInfo CONFIGURATION_TYPES Debug Release RelWithDebInfo) 73 | ``` 74 | 75 | 76 | ## Maintainer 77 | 78 | Paweł Bylica [@chfast] 79 | 80 | ## License 81 | 82 | Licensed under the [Apache License, Version 2.0]. 83 | 84 | 85 | [@chfast]: https://github.com/chfast 86 | [Apache License, Version 2.0]: LICENSE 87 | [git submodule]: https://git-scm.com/book/en/v2/Git-Tools-Submodules 88 | [git subtree]: https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt 89 | [git subtree tutorial]: https://www.atlassian.com/blog/git/alternatives-to-git-submodule-git-subtree 90 | [standard readme]: https://github.com/RichardLitt/standard-readme 91 | 92 | [readme style standard badge]: https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square 93 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | # Copyright 2018-2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | cmake_minimum_required(VERSION 3.5) 6 | 7 | if(POLICY CMP0069) 8 | cmake_policy(SET CMP0069 NEW) # Allow LTO. 9 | endif() 10 | 11 | include(cmake/cable/bootstrap.cmake) 12 | 13 | include(CableBuildType) 14 | include(CableCompilerSettings) 15 | include(CableToolchains) 16 | include(CMakePackageConfigHelpers) 17 | include(HunterGate) 18 | 19 | include(defaults/HunterCacheServers) 20 | 21 | cable_configure_toolchain(DEFAULT cxx11) 22 | cable_set_build_type(DEFAULT Release CONFIGURATION_TYPES Release RelWithDebInfo Debug) 23 | 24 | if(NOT WIN32) 25 | # Outside of Windows build only Release packages. 26 | set(HUNTER_CONFIGURATION_TYPES Release 27 | CACHE STRING "Build type of the Hunter packages") 28 | endif() 29 | 30 | HunterGate( 31 | URL "https://github.com/cpp-pm/hunter/archive/v0.23.253.tar.gz" 32 | SHA1 "88ea6d37c897a81a080eb9ae0f69d7807bbb3c73" 33 | ) 34 | 35 | project(ethash) 36 | set(PROJECT_VERSION 0.5.1-alpha.1) 37 | 38 | cable_configure_compiler(NO_STACK_PROTECTION) 39 | if(CABLE_COMPILER_GNULIKE) 40 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og") 41 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og") 42 | 43 | option(ETHASH_NATIVE "Build for native CPU" OFF) 44 | if(ETHASH_NATIVE) 45 | add_compile_options(-march=native) 46 | endif() 47 | elseif(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4) 48 | # For Win32 builds allow allocating more than 2 GB of memory. 49 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") 50 | endif() 51 | 52 | option(ETHASH_INSTALL_CMAKE_CONFIG "Install CMake configuration scripts for find_package(CONFIG)" ON) 53 | 54 | option(ETHASH_FUZZING "Build with fuzzer instrumentation" OFF) 55 | if(ETHASH_FUZZING) 56 | set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=fuzzer-no-link ${CMAKE_EXE_LINKER_FLAGS}") 57 | add_compile_options(-fno-omit-frame-pointer -fsanitize=fuzzer,undefined,integer -fno-sanitize-recover=all) 58 | endif() 59 | 60 | set(include_dir ${PROJECT_SOURCE_DIR}/include) 61 | 62 | add_subdirectory(lib) 63 | 64 | option(ETHASH_BUILD_TESTS "Build unit tests" ON) 65 | if(ETHASH_BUILD_TESTS) 66 | add_subdirectory(test) 67 | endif() 68 | 69 | install( 70 | DIRECTORY 71 | ${include_dir}/ 72 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 73 | ) 74 | 75 | if(ETHASH_INSTALL_CMAKE_CONFIG) 76 | write_basic_package_version_file(ethashConfigVersion.cmake COMPATIBILITY SameMajorVersion) 77 | configure_package_config_file(cmake/Config.cmake.in ethashConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ethash) 78 | 79 | install( 80 | EXPORT ethashTargets 81 | NAMESPACE ethash:: 82 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ethash 83 | ) 84 | install( 85 | FILES 86 | ${CMAKE_CURRENT_BINARY_DIR}/ethashConfig.cmake 87 | ${CMAKE_CURRENT_BINARY_DIR}/ethashConfigVersion.cmake 88 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ethash 89 | ) 90 | endif() 91 | -------------------------------------------------------------------------------- /cmake/cable/buildinfo/buildinfo.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | string(TOLOWER "${SYSTEM_NAME}" SYSTEM_NAME) 6 | string(TOLOWER "${SYSTEM_PROCESSOR}" SYSTEM_PROCESSOR) 7 | string(TOLOWER "${COMPILER_ID}" COMPILER_ID) 8 | string(TOLOWER "${BUILD_TYPE}" BUILD_TYPE) 9 | string(TIMESTAMP TIMESTAMP) 10 | 11 | # Read the git info from a file. The gitinfo is suppose to update the file 12 | # only if the information has changed. 13 | file(STRINGS ${OUTPUT_DIR}/gitinfo.txt gitinfo) 14 | list(LENGTH gitinfo gitinfo_len) 15 | if(gitinfo_len LESS 3) 16 | message(WARNING "Git info not available") 17 | else() 18 | list(GET gitinfo 0 describe) 19 | list(GET gitinfo 1 GIT_BRANCH) 20 | list(GET gitinfo 2 GIT_ORIGIN_URL) 21 | endif() 22 | 23 | # The output of `git describe --always --long --tags --match=v*`. 24 | string(REGEX MATCH "(v(.+)-([0-9]+)-g)?([0-9a-f]+)(-dirty)?" match "${describe}") 25 | 26 | if(DEFINED describe AND NOT match) 27 | message(WARNING "Cannot parse git describe: ${describe}") 28 | endif() 29 | 30 | set(GIT_LATEST_PROJECT_VERSION ${CMAKE_MATCH_2}) 31 | set(GIT_LATEST_PROJECT_VERSION_DISTANCE ${CMAKE_MATCH_3}) 32 | set(GIT_COMMIT_HASH ${CMAKE_MATCH_4}) 33 | if(CMAKE_MATCH_5) 34 | set(GIT_DIRTY TRUE) 35 | set(dirty_msg " (dirty)") 36 | else() 37 | set(GIT_DIRTY FALSE) 38 | endif() 39 | 40 | if(GIT_COMMIT_HASH) 41 | string(SUBSTRING ${GIT_COMMIT_HASH} 0 8 abbrev) 42 | set(version_commit "+commit.${abbrev}") 43 | if(GIT_DIRTY) 44 | set(version_commit "${version_commit}.dirty") 45 | endif() 46 | endif() 47 | 48 | if(NOT PROJECT_VERSION) 49 | message(WARNING "PROJECT_VERSION not specified") 50 | endif() 51 | 52 | if(PROJECT_VERSION STREQUAL GIT_LATEST_PROJECT_VERSION) 53 | if(${GIT_LATEST_PROJECT_VERSION_DISTANCE} GREATER 0) 54 | set(PROJECT_VERSION "${PROJECT_VERSION}-${GIT_LATEST_PROJECT_VERSION_DISTANCE}${version_commit}") 55 | endif() 56 | else() 57 | if(GIT_LATEST_PROJECT_VERSION) 58 | message(WARNING "Git project version mismatch: '${GIT_LATEST_PROJECT_VERSION}' vs '${PROJECT_VERSION}'") 59 | endif() 60 | set(PROJECT_VERSION "${PROJECT_VERSION}${version_commit}") 61 | endif() 62 | 63 | if(PROJECT_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$") 64 | set(PROJECT_VERSION_IS_PRERELEASE false) 65 | else() 66 | set(PROJECT_VERSION_IS_PRERELEASE true) 67 | set(prerelease_comment " (prerelease)") 68 | endif() 69 | 70 | message( 71 | " Project Version: ${PROJECT_VERSION}${prerelease_comment}\n" 72 | " System Name: ${SYSTEM_NAME}\n" 73 | " System Processor: ${SYSTEM_PROCESSOR}\n" 74 | " Compiler ID: ${COMPILER_ID}\n" 75 | " Compiler Version: ${COMPILER_VERSION}\n" 76 | " Build Type: ${BUILD_TYPE}\n" 77 | " Git Info: ${GIT_LATEST_PROJECT_VERSION} ${GIT_LATEST_PROJECT_VERSION_DISTANCE} ${GIT_COMMIT_HASH}${dirty_msg}\n" 78 | " Timestamp: ${TIMESTAMP}" 79 | ) 80 | 81 | configure_file(${CMAKE_CURRENT_LIST_DIR}/buildinfo.c.in ${OUTPUT_DIR}/buildinfo.c) 82 | configure_file(${CMAKE_CURRENT_LIST_DIR}/buildinfo.json.in ${OUTPUT_DIR}/buildinfo.json) 83 | configure_file(${CMAKE_CURRENT_LIST_DIR}/buildinfo.sh.in ${OUTPUT_DIR}/buildinfo.sh) 84 | configure_file(${CMAKE_CURRENT_LIST_DIR}/buildinfo.ps1.in ${OUTPUT_DIR}/buildinfo.ps1) 85 | -------------------------------------------------------------------------------- /lib/ethash/managed.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include "ethash-internal.hpp" 6 | 7 | #include 8 | #include 9 | 10 | #if !defined(__has_cpp_attribute) 11 | #define __has_cpp_attribute(x) 0 12 | #endif 13 | 14 | #if __has_cpp_attribute(gnu::noinline) 15 | #define ATTRIBUTE_NOINLINE [[gnu::noinline]] 16 | #elif _MSC_VER 17 | #define ATTRIBUTE_NOINLINE __declspec(noinline) 18 | #else 19 | #define ATTRIBUTE_NOINLINE 20 | #endif 21 | 22 | using namespace ethash; 23 | 24 | namespace 25 | { 26 | std::mutex shared_context_mutex; 27 | std::shared_ptr shared_context; 28 | thread_local std::shared_ptr thread_local_context; 29 | 30 | std::mutex shared_context_full_mutex; 31 | std::shared_ptr shared_context_full; 32 | thread_local std::shared_ptr thread_local_context_full; 33 | 34 | /// Update thread local epoch context. 35 | /// 36 | /// This function is on the slow path. It's separated to allow inlining the fast 37 | /// path. 38 | /// 39 | /// @todo: Redesign to guarantee deallocation before new allocation. 40 | ATTRIBUTE_NOINLINE 41 | void update_local_context(int epoch_number) 42 | { 43 | // Release the shared pointer of the obsoleted context. 44 | thread_local_context.reset(); 45 | 46 | // Local context invalid, check the shared context. 47 | std::lock_guard lock{shared_context_mutex}; 48 | 49 | if (!shared_context || shared_context->epoch_number != epoch_number) 50 | { 51 | // Release the shared pointer of the obsoleted context. 52 | shared_context.reset(); 53 | 54 | // Build new context. 55 | shared_context = create_epoch_context(epoch_number); 56 | } 57 | 58 | thread_local_context = shared_context; 59 | } 60 | 61 | ATTRIBUTE_NOINLINE 62 | void update_local_context_full(int epoch_number) 63 | { 64 | // Release the shared pointer of the obsoleted context. 65 | thread_local_context_full.reset(); 66 | 67 | // Local context invalid, check the shared context. 68 | std::lock_guard lock{shared_context_full_mutex}; 69 | 70 | if (!shared_context_full || shared_context_full->epoch_number != epoch_number) 71 | { 72 | // Release the shared pointer of the obsoleted context. 73 | shared_context_full.reset(); 74 | 75 | // Build new context. 76 | shared_context_full = create_epoch_context_full(epoch_number); 77 | } 78 | 79 | thread_local_context_full = shared_context_full; 80 | } 81 | } // namespace 82 | 83 | const ethash_epoch_context* ethash_get_global_epoch_context(int epoch_number) noexcept 84 | { 85 | // Check if local context matches epoch number. 86 | if (!thread_local_context || thread_local_context->epoch_number != epoch_number) 87 | update_local_context(epoch_number); 88 | 89 | return thread_local_context.get(); 90 | } 91 | 92 | const ethash_epoch_context_full* ethash_get_global_epoch_context_full(int epoch_number) noexcept 93 | { 94 | // Check if local context matches epoch number. 95 | if (!thread_local_context_full || thread_local_context_full->epoch_number != epoch_number) 96 | update_local_context_full(epoch_number); 97 | 98 | return thread_local_context_full.get(); 99 | } 100 | -------------------------------------------------------------------------------- /cmake/cable/CableBuildInfo.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library. 2 | # Copyright 2019 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. 4 | 5 | if(cable_build_info_included) 6 | return() 7 | endif() 8 | set(cable_build_info_included TRUE) 9 | 10 | include(GNUInstallDirs) 11 | 12 | set(cable_buildinfo_template_dir ${CMAKE_CURRENT_LIST_DIR}/buildinfo) 13 | 14 | function(cable_add_buildinfo_library) 15 | 16 | cmake_parse_arguments("" "" PROJECT_NAME;EXPORT "" ${ARGN}) 17 | 18 | if(NOT _PROJECT_NAME) 19 | message(FATAL_ERROR "The PROJECT_NAME argument missing") 20 | endif() 21 | 22 | # Come up with the target and the C function names. 23 | set(name ${_PROJECT_NAME}-buildinfo) 24 | set(FUNCTION_NAME ${_PROJECT_NAME}_get_buildinfo) 25 | 26 | set(output_dir ${CMAKE_CURRENT_BINARY_DIR}/${_PROJECT_NAME}) 27 | set(header_file ${output_dir}/buildinfo.h) 28 | set(source_file ${output_dir}/buildinfo.c) 29 | 30 | if(CMAKE_CONFIGURATION_TYPES) 31 | set(build_type ${CMAKE_CFG_INTDIR}) 32 | else() 33 | set(build_type ${CMAKE_BUILD_TYPE}) 34 | endif() 35 | 36 | # Find git here to allow the user to provide hints. 37 | find_package(Git) 38 | 39 | # Git info target. 40 | # 41 | # This target is named -git and is always built. 42 | # The executed script gitinfo.cmake check git status and updates files 43 | # containing git information if anything has changed. 44 | add_custom_target( 45 | ${name}-git 46 | COMMAND ${CMAKE_COMMAND} 47 | -DGIT=${GIT_EXECUTABLE} 48 | -DSOURCE_DIR=${PROJECT_SOURCE_DIR} 49 | -DOUTPUT_DIR=${output_dir} 50 | -P ${cable_buildinfo_template_dir}/gitinfo.cmake 51 | BYPRODUCTS ${output_dir}/gitinfo.txt 52 | ) 53 | 54 | add_custom_command( 55 | COMMENT "Updating ${name}:" 56 | OUTPUT ${source_file} ${output_dir}/buildinfo.json 57 | COMMAND ${CMAKE_COMMAND} 58 | -DOUTPUT_DIR=${output_dir} 59 | -DPROJECT_NAME=${_PROJECT_NAME} 60 | -DFUNCTION_NAME=${FUNCTION_NAME} 61 | -DPROJECT_VERSION=${PROJECT_VERSION} 62 | -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME} 63 | -DSYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR} 64 | -DCOMPILER_ID=${CMAKE_CXX_COMPILER_ID} 65 | -DCOMPILER_VERSION=${CMAKE_CXX_COMPILER_VERSION} 66 | -DBUILD_TYPE=${build_type} 67 | -P ${cable_buildinfo_template_dir}/buildinfo.cmake 68 | DEPENDS 69 | ${cable_buildinfo_template_dir}/buildinfo.cmake 70 | ${cable_buildinfo_template_dir}/buildinfo.c.in 71 | ${cable_buildinfo_template_dir}/buildinfo.json.in 72 | ${name}-git 73 | ${output_dir}/gitinfo.txt 74 | ) 75 | 76 | string(TIMESTAMP TIMESTAMP) 77 | configure_file(${cable_buildinfo_template_dir}/buildinfo.h.in ${header_file}) 78 | 79 | # Add buildinfo library under given name. 80 | # Make is static and do not build by default until some other target will actually use it. 81 | add_library(${name} STATIC ${source_file} ${header_file}) 82 | 83 | target_include_directories(${name} PUBLIC $) 84 | set_target_properties( 85 | ${name} PROPERTIES 86 | LIBRARY_OUTPUT_DIRECTORY ${output_dir} 87 | ARCHIVE_OUTPUT_DIRECTORY ${output_dir} 88 | ) 89 | 90 | if(_EXPORT) 91 | install(TARGETS ${name} EXPORT ${_EXPORT} 92 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 93 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 94 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 95 | ) 96 | endif() 97 | 98 | endfunction() 99 | -------------------------------------------------------------------------------- /lib/keccak/keccak.c: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #include 7 | 8 | #include "../support/attributes.h" 9 | #include 10 | 11 | #if _WIN32 12 | /* On Windows assume little endian. */ 13 | #define __LITTLE_ENDIAN 1234 14 | #define __BIG_ENDIAN 4321 15 | #define __BYTE_ORDER __LITTLE_ENDIAN 16 | #elif __APPLE__ 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | #if __BYTE_ORDER == __LITTLE_ENDIAN 23 | #define to_le64(X) X 24 | #else 25 | #define to_le64(X) __builtin_bswap64(X) 26 | #endif 27 | 28 | 29 | /** Loads 64-bit integer from given memory location as little-endian number. */ 30 | static INLINE ALWAYS_INLINE uint64_t load_le(const uint8_t* data) 31 | { 32 | /* memcpy is the best way of expressing the intention. Every compiler will 33 | optimize is to single load instruction if the target architecture 34 | supports unaligned memory access (GCC and clang even in O0). 35 | This is great trick because we are violating C/C++ memory alignment 36 | restrictions with no performance penalty. */ 37 | uint64_t word; 38 | memcpy(&word, data, sizeof(word)); 39 | return to_le64(word); 40 | } 41 | 42 | static INLINE ALWAYS_INLINE void keccak( 43 | uint64_t* out, size_t bits, const uint8_t* data, size_t size) 44 | { 45 | static const size_t word_size = sizeof(uint64_t); 46 | const size_t hash_size = bits / 8; 47 | const size_t block_size = (1600 - bits * 2) / 8; 48 | 49 | size_t i; 50 | uint64_t* state_iter; 51 | uint64_t last_word = 0; 52 | uint8_t* last_word_iter = (uint8_t*)&last_word; 53 | 54 | uint64_t state[25] = {0}; 55 | 56 | while (size >= block_size) 57 | { 58 | for (i = 0; i < (block_size / word_size); ++i) 59 | { 60 | state[i] ^= load_le(data); 61 | data += word_size; 62 | } 63 | 64 | ethash_keccakf1600(state); 65 | 66 | size -= block_size; 67 | } 68 | 69 | state_iter = state; 70 | 71 | while (size >= word_size) 72 | { 73 | *state_iter ^= load_le(data); 74 | ++state_iter; 75 | data += word_size; 76 | size -= word_size; 77 | } 78 | 79 | while (size > 0) 80 | { 81 | *last_word_iter = *data; 82 | ++last_word_iter; 83 | ++data; 84 | --size; 85 | } 86 | *last_word_iter = 0x01; 87 | *state_iter ^= to_le64(last_word); 88 | 89 | state[(block_size / word_size) - 1] ^= 0x8000000000000000; 90 | 91 | ethash_keccakf1600(state); 92 | 93 | for (i = 0; i < (hash_size / word_size); ++i) 94 | out[i] = to_le64(state[i]); 95 | } 96 | 97 | union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) 98 | { 99 | union ethash_hash256 hash; 100 | keccak(hash.word64s, 256, data, size); 101 | return hash; 102 | } 103 | 104 | union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) 105 | { 106 | union ethash_hash256 hash; 107 | keccak(hash.word64s, 256, data, 32); 108 | return hash; 109 | } 110 | 111 | union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) 112 | { 113 | union ethash_hash512 hash; 114 | keccak(hash.word64s, 512, data, size); 115 | return hash; 116 | } 117 | 118 | union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) 119 | { 120 | union ethash_hash512 hash; 121 | keccak(hash.word64s, 512, data, 64); 122 | return hash; 123 | } 124 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 4 | # Copyright 2019 Pawel Bylica. 5 | # Licensed under the Apache License, Version 2.0. 6 | 7 | import os 8 | import subprocess 9 | import shutil 10 | from distutils.errors import CCompilerError 11 | from os import path 12 | 13 | from setuptools import setup 14 | from setuptools.command.build_ext import build_ext as setuptools_build_ext 15 | 16 | 17 | class build_ext(setuptools_build_ext): 18 | user_options = setuptools_build_ext.user_options + [ 19 | ('skip-cmake-build', None, 20 | "Skip CMake build assuming the libraries are already installed " + 21 | "to the dist directory") 22 | ] 23 | 24 | def initialize_options(self): 25 | super(build_ext, self).initialize_options() 26 | self.skip_cmake_build = False 27 | 28 | def run(self): 29 | build_dir = self.build_temp 30 | source_dir = path.dirname(path.abspath(__file__)) 31 | install_dir = path.join(source_dir, 'dist') 32 | 33 | cmake_opts = [ 34 | '-DCMAKE_INSTALL_PREFIX={}'.format(install_dir), 35 | '-DCMAKE_INSTALL_LIBDIR=lib', 36 | '-DCMAKE_POSITION_INDEPENDENT_CODE=TRUE', 37 | '-DHUNTER_ENABLED=OFF', 38 | '-DETHASH_BUILD_TESTS=OFF', 39 | '-DETHASH_INSTALL_CMAKE_CONFIG=OFF' 40 | ] 41 | 42 | generator = os.environ.get('GENERATOR') 43 | if generator: 44 | cmake_opts.append('-G{}'.format(generator)) 45 | 46 | if not self.skip_cmake_build and not os.environ.get('ETHASH_PYTHON_SKIP_BUILD'): 47 | cmake_cmd = shutil.which('cmake') 48 | if not cmake_cmd: 49 | raise CCompilerError( 50 | "cmake tool not found but required to build this package") 51 | 52 | r = subprocess.call([cmake_cmd, source_dir] + cmake_opts, 53 | cwd=build_dir) 54 | if r != 0: 55 | raise CCompilerError( 56 | "cmake configuration failed with exit status {}".format(r)) 57 | r = subprocess.call( 58 | [cmake_cmd, '--build', build_dir, '--target', 'install', 59 | '--config', 'Release']) 60 | if r != 0: 61 | raise CCompilerError( 62 | "cmake build failed with exit status {}".format(r)) 63 | 64 | self.library_dirs.append(path.join(install_dir, 'lib')) 65 | 66 | super(build_ext, self).run() 67 | 68 | 69 | setup( 70 | name='ethash', 71 | version='0.5.1-alpha.1', 72 | description= 73 | "C/C++ implementation of Ethash – the Ethereum Proof of Work algorithm", 74 | url='https://github.com/chfast/ethash', 75 | author='Paweł Bylica', 76 | author_email='pawel@ethereum.org', 77 | license='Apache License, Version 2.0', 78 | 79 | package_dir={'': 'bindings/python'}, 80 | packages=['ethash'], 81 | cffi_modules=['bindings/python/ethash/_build.py:ffibuilder'], 82 | 83 | python_requires='>=3.5', 84 | setup_requires=['cffi>=1.12'], 85 | install_requires=['cffi>=1.12'], 86 | 87 | test_suite='tests.test_ethash', 88 | 89 | cmdclass={'build_ext': build_ext}, 90 | 91 | classifiers=[ 92 | 'License :: OSI Approved :: Apache Software License', 93 | 'Programming Language :: C', 94 | 'Programming Language :: C++', 95 | 'Programming Language :: Python :: 3', 96 | 'Programming Language :: Python :: 3.5', 97 | 'Programming Language :: Python :: 3.6', 98 | 'Programming Language :: Python :: 3.7', 99 | ], 100 | ) 101 | -------------------------------------------------------------------------------- /test/benchmarks/keccak_benchmarks.cpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include "keccak_utils.hpp" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | 13 | void fake_keccakf1600(uint64_t* state) noexcept 14 | { 15 | // Do nothing to measure performance of the code outside of keccakf function. 16 | (void)state; 17 | } 18 | 19 | 20 | static void keccakf1600(benchmark::State& state) 21 | { 22 | uint64_t keccak_state[25] = {}; 23 | 24 | for (auto _ : state) 25 | { 26 | ethash_keccakf1600(keccak_state); 27 | benchmark::DoNotOptimize(keccak_state); 28 | } 29 | } 30 | BENCHMARK(keccakf1600); 31 | 32 | 33 | static void keccakf800(benchmark::State& state) 34 | { 35 | uint32_t keccak_state[25] = {}; 36 | 37 | for (auto _ : state) 38 | { 39 | ethash_keccakf800(keccak_state); 40 | benchmark::DoNotOptimize(keccak_state); 41 | } 42 | } 43 | BENCHMARK(keccakf800); 44 | 45 | 46 | static void keccak256(benchmark::State& state) 47 | { 48 | const auto data_size = static_cast(state.range(0)); 49 | std::vector data(data_size, 0xde); 50 | 51 | for (auto _ : state) 52 | { 53 | auto h = ethash_keccak256(data.data(), data.size()); 54 | benchmark::DoNotOptimize(h.bytes); 55 | } 56 | } 57 | BENCHMARK(keccak256)->Arg(32)->Arg(64)->Arg(128)->Arg(135)->Arg(136); 58 | 59 | 60 | static void keccak512(benchmark::State& state) 61 | { 62 | const auto data_size = static_cast(state.range(0)); 63 | std::vector data(data_size, 0xde); 64 | 65 | for (auto _ : state) 66 | { 67 | auto h = ethash_keccak512(data.data(), data.size()); 68 | benchmark::DoNotOptimize(h.bytes); 69 | } 70 | } 71 | BENCHMARK(keccak512)->Arg(32)->Arg(64)->Arg(71)->Arg(72)->Arg(142)->Arg(143)->Arg(144); 72 | 73 | 74 | template 75 | static void fake_keccak256(benchmark::State& state) 76 | { 77 | std::vector data(static_cast(state.range(0)), 0xaa); 78 | 79 | for (auto _ : state) 80 | { 81 | uint64_t out[4]; 82 | keccak_fn(out, data.data(), data.size()); 83 | benchmark::DoNotOptimize(out); 84 | } 85 | } 86 | BENCHMARK_TEMPLATE(fake_keccak256, fake_keccak256_default_aligned)->Arg(128)->Arg(17 * 8)->Arg(4096)->Arg(16 * 1024); 87 | BENCHMARK_TEMPLATE(fake_keccak256, fake_keccak256_default)->Arg(128)->Arg(17 * 8)->Arg(4096)->Arg(16 * 1024); 88 | BENCHMARK_TEMPLATE(fake_keccak256, fake_keccak256_fastest)->Arg(128)->Arg(17 * 8)->Arg(4096)->Arg(16 * 1024); 89 | 90 | 91 | template 92 | static void fake_keccak256_unaligned(benchmark::State& state) 93 | { 94 | const auto size = static_cast(state.range(0)); 95 | std::vector data(size + 1, 0xaa); 96 | 97 | for (auto _ : state) 98 | { 99 | uint64_t out[4]; 100 | keccak_fn(out, data.data() + 1, size); 101 | benchmark::DoNotOptimize(out); 102 | } 103 | } 104 | BENCHMARK_TEMPLATE(fake_keccak256_unaligned, fake_keccak256_default)->Arg(128)->Arg(17 * 8)->Arg(4096)->Arg(16 * 1024); 105 | BENCHMARK_TEMPLATE(fake_keccak256_unaligned, fake_keccak256_fastest)->Arg(128)->Arg(17 * 8)->Arg(4096)->Arg(16 * 1024); 106 | 107 | 108 | static void fake_keccak256_word4(benchmark::State& state) 109 | { 110 | const uint64_t input[4] = {1, 2, 3, 4}; 111 | 112 | for (auto _ : state) 113 | { 114 | uint64_t out[4]; 115 | fake_keccak256_fastest_word4(out, input); 116 | benchmark::DoNotOptimize(out); 117 | } 118 | } 119 | BENCHMARK(fake_keccak256_word4); 120 | -------------------------------------------------------------------------------- /test/unittests/test_primes.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #pragma GCC diagnostic ignored "-Wpedantic" 6 | #pragma clang diagnostic ignored "-Wpedantic" 7 | 8 | #include 9 | 10 | #include 11 | 12 | TEST(primes, find_largest_prime) 13 | { 14 | /// Test pairs for find_largest_prime() are taken from generated ethash 15 | /// light cache and full dataset sizes, picked 50 at random from each collection. 16 | /// See https://github.com/ethereum/wiki/wiki/Ethash#data-sizes. 17 | static std::pair test_pairs[] = {{262144, 262139}, {415744, 415729}, {440320, 440311}, 18 | {505856, 505823}, {593920, 593903}, {667648, 667643}, {970752, 970747}, {972800, 972799}, 19 | {1064960, 1064957}, {1083392, 1083391}, {1112064, 1112057}, {1122304, 1122287}, 20 | {1220608, 1220599}, {1335296, 1335289}, {1464320, 1464299}, {1517568, 1517567}, 21 | {1638400, 1638353}, {1679360, 1679351}, {1873920, 1873889}, {1949696, 1949657}, 22 | {1984512, 1984511}, {1994752, 1994743}, {2131968, 2131951}, {2156544, 2156537}, 23 | {2385920, 2385919}, {2529280, 2529269}, {2535424, 2535413}, {2568192, 2568191}, 24 | {2588672, 2588671}, {2600960, 2600957}, {2650112, 2650093}, {2717696, 2717683}, 25 | {2727936, 2727919}, {2779136, 2779129}, {2828288, 2828281}, {2865152, 2865131}, 26 | {3057664, 3057661}, {3250176, 3250157}, {3299328, 3299323}, {3551232, 3551227}, 27 | {3575808, 3575783}, {3592192, 3592109}, {3719168, 3719167}, {3813376, 3813353}, 28 | {3825664, 3825649}, {3887104, 3887083}, {3942400, 3942397}, {4028416, 4028413}, 29 | {4098048, 4098043}, {4288512, 4288489}, {4345856, 4345849}, {4454400, 4454399}, 30 | {8388608, 8388593}, {9633792, 9633787}, {10027008, 10026979}, {10289152, 10289141}, 31 | {11337728, 11337727}, {20447232, 20447191}, {22216704, 22216673}, {25755648, 25755619}, 32 | {29491200, 29491193}, {33488896, 33488891}, {35717120, 35717111}, {36241408, 36241397}, 33 | {38273024, 38273023}, {39321600, 39321599}, {39452672, 39452671}, {40828928, 40828927}, 34 | {41025536, 41025499}, {41484288, 41484271}, {46530560, 46530557}, {50200576, 50200573}, 35 | {50724864, 50724859}, {52297728, 52297717}, {54394880, 54394877}, {54788096, 54788089}, 36 | {61997056, 61997053}, {63242240, 63242239}, {65470464, 65470453}, {65732608, 65732599}, 37 | {69009408, 69009371}, {70582272, 70582271}, {75104256, 75104243}, {84279296, 84279277}, 38 | {88932352, 88932341}, {90963968, 90963967}, {92930048, 92930039}, {93388800, 93388759}, 39 | {95354880, 95354879}, {96272384, 96272383}, {96534528, 96534523}, {103022592, 103022537}, 40 | {103284736, 103284733}, {108265472, 108265459}, {109772800, 109772797}, 41 | {110297088, 110297069}, {126287872, 126287809}, {129040384, 129040367}, 42 | {129171456, 129171439}, {130482176, 130482173}, {131203072, 131203069}, 43 | {139264000, 139263953}, {140705792, 140705779}, {142540800, 142540787}, 44 | {1974468608, 1974468569}, {2147483646, 2147483629}, {2147483647, 2147483647}}; 45 | 46 | for (const auto& t : test_pairs) 47 | { 48 | int prime = ethash_find_largest_prime(t.first); 49 | EXPECT_EQ(prime, t.second); 50 | } 51 | } 52 | 53 | TEST(primes, find_largest_prime_edge_cases) 54 | { 55 | EXPECT_EQ(ethash_find_largest_prime(-2147483647), 0); 56 | EXPECT_EQ(ethash_find_largest_prime(-100), 0); 57 | EXPECT_EQ(ethash_find_largest_prime(-1), 0); 58 | EXPECT_EQ(ethash_find_largest_prime(0), 0); 59 | EXPECT_EQ(ethash_find_largest_prime(1), 0); 60 | EXPECT_EQ(ethash_find_largest_prime(2), 2); 61 | EXPECT_EQ(ethash_find_largest_prime(3), 3); 62 | EXPECT_EQ(ethash_find_largest_prime(4), 3); 63 | EXPECT_EQ(ethash_find_largest_prime(5), 5); 64 | EXPECT_EQ(ethash_find_largest_prime(6), 5); 65 | EXPECT_EQ(ethash_find_largest_prime(7), 7); 66 | } 67 | -------------------------------------------------------------------------------- /test/unittests/progpow_test_vectors.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | /// @file 6 | /// ProgPoW test vectors. 7 | 8 | #pragma once 9 | 10 | namespace // In anonymous namespace to allow including in multiple compilation units. 11 | { 12 | /// Defines a test case for ProgPoW hash() function. 13 | struct progpow_hash_test_case 14 | { 15 | int block_number; 16 | const char* header_hash_hex; 17 | const char* nonce_hex; 18 | const char* mix_hash_hex; 19 | const char* final_hash_hex; 20 | }; 21 | 22 | progpow_hash_test_case progpow_hash_test_cases[] = { 23 | {0, "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000", 24 | "6e97b47b134fda0c7888802988e1a373affeb28bcd813b6e9a0fc669c935d03a", 25 | "e601a7257a70dc48fccc97a7330d704d776047623b92883d77111fb36870f3d1"}, 26 | {49, "63155f732f2bf556967f906155b510c917e48e99685ead76ea83f4eca03ab12b", "0000000007073c07", 27 | "d36f7e815ee09e74eceb9c96993a3d681edf2bf0921fc7bb710364042db99777", 28 | "e7ced124598fd2500a55ad9f9f48e3569327fe50493c77a4ac9799b96efb9463"}, 29 | {50, "9e7248f20914913a73d80a70174c331b1d34f260535ac3631d770e656b5dd922", "00000000076e482e", 30 | "d6dc634ae837e2785b347648ea515e25e5d8821ae0b95e1c2a9c2d497e0dcfbd", 31 | "ab0ad7ef8d8ee317dd12d10310aceed7321d34fb263791c2de5776a6658d177e"}, 32 | {99, "de37e1824c86d35d154cf65a88de6d9286aec4f7f10c3fc9f0fa1bcc2687188d", "000000003917afab", 33 | "fa706860e5e0e830d5d1d7157e5bea7f5f8a350c7c8612ac1d1fcf2974d64244", 34 | "aa85340690f2e907054324a5021937910e15edfd1ef1577231843e7d32ec3a61"}, 35 | {29950, "ac7b55e801511b77e11d52e9599206101550144525b5679f2dab19386f23dcce", "005d409dbc23a62a", 36 | "5359807b77a74878269c3a3044df8618a576ce8dc52e1c48d927d4a60e7c6b79", 37 | "022019e5408683f7f8326b4e46b42864a3a069f17b6151e434fcaedecaadd918"}, 38 | {29999, "e43d7e0bdc8a4a3f6e291a5ed790b9fa1a0948a2b9e33c844888690847de19f5", "005db5fa4c2a3d03", 39 | "d15de3f9bfedd9b6d0f498273eb3b437115bdc8326c96c6457ac06deb5c9f389", 40 | "4e93630b81198752f876b24380999189b7b9366c08222ac05e4237b87114f305"}, 41 | {30000, "d34519f72c97cae8892c277776259db3320820cb5279a299d0ef1e155e5c6454", "005db8607994ff30", 42 | "de0348b69bf91dfe2c3d3dba6f0132e9048a5284e57b8d9d20adc5f3dc0d3236", 43 | "c7953d848cda6e304f77b4c6d735645c8e8508a5e74c9e9814ef37b19087cd6c"}, 44 | {30049, "8b6ce5da0b06d18db7bd8492d9e5717f8b53e7e098d9fef7886d58a6e913ef64", "005e2e215a8ca2e7", 45 | "975c6a9decc89cba7ace69338d4de8510d9619aef42b1d35d0bef7e0ce0614a9", 46 | "c262d8055e288d04b951a844bfca8ba529f5b4d652b408e3942727d7dd90957a"}, 47 | {30050, "c2c46173481b9ced61123d2e293b42ede5a1b323210eb2a684df0874ffe09047", "005e30899481055e", 48 | "362f2fabdb9699d3634b6499703f939f378ee4eac803396c2b0ed0fe1d154972", 49 | "4cd7e6e79e0b63d42b2b06716a919ccc7834077ec727a9ea94edcdaff2fefab8"}, 50 | {30099, "ea42197eb2ba79c63cb5e655b8b1f612c5f08aae1a49ff236795a3516d87bc71", "005ea6aef136f88b", 51 | "b1196457261bd05ccb387a8ff3fd02687bf496bd7943d89419465289669e27aa", 52 | "39d1ebfa783b61a6fa8e9747d0f9f134efae5cfba284a2c80e8deabae6b98676"}, 53 | {59950, "49e15ba4bf501ce8fe8876101c808e24c69a859be15de554bf85dbc095491bd6", "02ebe0503bd7b1da", 54 | "df3dbb1669fd35dbb0ae96bbea2d498f0c6992cbddd092aeace42dd933505f95", 55 | "b8984cf4021c4433f753654848d721f33a0792b4417241f0cf7c7c2db011a54a"}, 56 | {59999, "f5c50ba5c0d6210ddb16250ec3efda178de857b2b1703d8d5403bd0f848e19cf", "02edb6275bd221e3", 57 | "5017df70e97ca35638cf439cdbe54f30383d335e18eb4a74d6e166736f1038fa", 58 | "4cf1fa62f25b577ac822a6a28d55f8b7e3ae7fe983abd868ae00927e68c41016"}, 59 | {170915, "5b3e8dfa1aafd3924a51f33e2d672d8dae32fa528d8b1d378d6e4db0ec5d665d", "0000000044975727", 60 | "efb29147484c434f1cc59629da90fd0343e3b047407ecd36e9ad973bd51bbac5", 61 | "e7e6bb3b2f9acd3864bc86f72f87237eaf475633ef650c726ac80eb0adf116b6"}, 62 | 63 | }; 64 | } // namespace 65 | -------------------------------------------------------------------------------- /include/ethash/ethash.h: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #ifdef __cplusplus 14 | #define NOEXCEPT noexcept 15 | #else 16 | #define NOEXCEPT 17 | #endif 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** 24 | * The Ethash algorithm revision implemented as specified in the Ethash spec 25 | * https://github.com/ethereum/wiki/wiki/Ethash. 26 | */ 27 | #define ETHASH_REVISION "23" 28 | 29 | #define ETHASH_EPOCH_LENGTH 7500 30 | #define ETHASH_LIGHT_CACHE_ITEM_SIZE 64 31 | #define ETHASH_FULL_DATASET_ITEM_SIZE 128 32 | #define ETHASH_NUM_DATASET_ACCESSES 64 33 | 34 | 35 | struct ethash_epoch_context 36 | { 37 | const int epoch_number; 38 | const int light_cache_num_items; 39 | const union ethash_hash512* const light_cache; 40 | const uint32_t* const l1_cache; 41 | const int full_dataset_num_items; 42 | }; 43 | 44 | 45 | struct ethash_epoch_context_full; 46 | 47 | 48 | struct ethash_result 49 | { 50 | union ethash_hash256 final_hash; 51 | union ethash_hash256 mix_hash; 52 | }; 53 | 54 | 55 | /** 56 | * Calculates the number of items in the light cache for given epoch. 57 | * 58 | * This function will search for a prime number matching the criteria given 59 | * by the Ethash so the execution time is not constant. It takes ~ 0.01 ms. 60 | * 61 | * @param epoch_number The epoch number. 62 | * @return The number items in the light cache. 63 | */ 64 | int ethash_calculate_light_cache_num_items(int epoch_number) NOEXCEPT; 65 | 66 | 67 | /** 68 | * Calculates the number of items in the full dataset for given epoch. 69 | * 70 | * This function will search for a prime number matching the criteria given 71 | * by the Ethash so the execution time is not constant. It takes ~ 0.05 ms. 72 | * 73 | * @param epoch_number The epoch number. 74 | * @return The number items in the full dataset. 75 | */ 76 | int ethash_calculate_full_dataset_num_items(int epoch_number) NOEXCEPT; 77 | 78 | /** 79 | * Calculates the epoch seed hash. 80 | * @param epoch_number The epoch number. 81 | * @return The epoch seed hash. 82 | */ 83 | union ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) NOEXCEPT; 84 | 85 | 86 | struct ethash_epoch_context* ethash_create_epoch_context(int epoch_number) NOEXCEPT; 87 | 88 | /** 89 | * Creates the epoch context with the full dataset initialized. 90 | * 91 | * The memory for the full dataset is only allocated and marked as "not-generated". 92 | * The items of the full dataset are generated on the fly when hit for the first time. 93 | * 94 | * The memory allocated in the context MUST be freed with ethash_destroy_epoch_context_full(). 95 | * 96 | * @param epoch_number The epoch number. 97 | * @return Pointer to the context or null in case of memory allocation failure. 98 | */ 99 | struct ethash_epoch_context_full* ethash_create_epoch_context_full(int epoch_number) NOEXCEPT; 100 | 101 | void ethash_destroy_epoch_context(struct ethash_epoch_context* context) NOEXCEPT; 102 | 103 | void ethash_destroy_epoch_context_full(struct ethash_epoch_context_full* context) NOEXCEPT; 104 | 105 | 106 | /** 107 | * Get global shared epoch context. 108 | */ 109 | const struct ethash_epoch_context* ethash_get_global_epoch_context(int epoch_number) NOEXCEPT; 110 | 111 | /** 112 | * Get global shared epoch context with full dataset initialized. 113 | */ 114 | const struct ethash_epoch_context_full* ethash_get_global_epoch_context_full( 115 | int epoch_number) NOEXCEPT; 116 | 117 | 118 | struct ethash_result ethash_hash(const struct ethash_epoch_context* context, 119 | const union ethash_hash256* header_hash, uint64_t nonce) NOEXCEPT; 120 | 121 | bool ethash_verify(const struct ethash_epoch_context* context, 122 | const union ethash_hash256* header_hash, const union ethash_hash256* mix_hash, uint64_t nonce, 123 | const union ethash_hash256* boundary) NOEXCEPT; 124 | 125 | bool ethash_verify_final_hash(const union ethash_hash256* header_hash, 126 | const union ethash_hash256* mix_hash, uint64_t nonce, 127 | const union ethash_hash256* boundary) NOEXCEPT; 128 | 129 | #ifdef __cplusplus 130 | } 131 | #endif 132 | -------------------------------------------------------------------------------- /test/benchmarks/keccak_utils.cpp: -------------------------------------------------------------------------------- 1 | // Ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | #include 7 | 8 | #define fix_endianness(X) X 9 | #define fix_endianness64(X) X 10 | 11 | 12 | void fake_keccakf1600(uint64_t* state) noexcept; 13 | 14 | 15 | namespace 16 | { 17 | inline void xor_into_state(uint64_t* state, const uint64_t* block, size_t num_words) noexcept 18 | { 19 | for (size_t i = 0; i < num_words; ++i) 20 | state[i] ^= fix_endianness(block[i]); 21 | } 22 | 23 | inline void xor_into_state(uint8_t* state, const uint8_t* block, size_t size) 24 | { 25 | for (size_t i = 0; i < size; ++i) 26 | state[i] ^= block[i]; 27 | } 28 | 29 | template 30 | inline void keccak_default_aligned(uint64_t* out, const uint64_t* data, size_t size) noexcept 31 | { 32 | static constexpr size_t block_size = (1600 - bits * 2) / 8; 33 | static constexpr size_t block_words = block_size / sizeof(uint64_t); 34 | 35 | uint64_t state[25] = {}; 36 | 37 | while (size >= block_words) 38 | { 39 | xor_into_state(state, data, block_words); 40 | fake_keccakf1600(state); 41 | data += block_words; 42 | size -= block_words; 43 | } 44 | 45 | // Final block: 46 | uint64_t block[block_words] = {}; 47 | // Weirdly, GCC and clang are able to optimize memcpy better than for loop. 48 | std::memcpy(block, data, size * sizeof(uint64_t)); 49 | 50 | // Padding: 51 | auto block_bytes = reinterpret_cast(block); 52 | block_bytes[size * sizeof(uint64_t)] = 0x01; 53 | block_bytes[block_size - 1] |= 0x80; 54 | 55 | xor_into_state(state, block, block_words); 56 | fake_keccakf1600(state); 57 | 58 | std::memcpy(out, state, bits / 8); 59 | // return fix_endianness64(hash); 60 | } 61 | 62 | 63 | template 64 | inline void keccak_default(uint64_t* out, const uint8_t* data, size_t size) noexcept 65 | { 66 | static constexpr size_t block_size = (1600 - bits * 2) / 8; 67 | static constexpr size_t block_words = block_size / sizeof(uint64_t); 68 | 69 | bool aligned = (uintptr_t)data % 8 == 0; 70 | 71 | uint64_t state[25] = {}; 72 | 73 | uint64_t block[block_words]; 74 | 75 | uint64_t* p; 76 | 77 | while (size >= block_size) 78 | { 79 | if (!aligned) 80 | { 81 | std::memcpy(block, data, block_size); 82 | p = block; 83 | } 84 | else 85 | p = (uint64_t*)data; 86 | xor_into_state(state, p, block_words); 87 | fake_keccakf1600(state); 88 | data += block_size; 89 | size -= block_size; 90 | } 91 | 92 | 93 | auto state_bytes = reinterpret_cast(state); 94 | xor_into_state(state_bytes, data, size); 95 | 96 | state_bytes[size] ^= 0x01; 97 | state_bytes[block_size - 1] ^= 0x80; 98 | 99 | fake_keccakf1600(state); 100 | 101 | std::memcpy(out, state, bits / 8); 102 | // return fix_endianness64(hash); 103 | } 104 | 105 | /// Loads 64-bit integer from given memory location. 106 | inline uint64_t load_le(const uint8_t *data) noexcept 107 | { 108 | // memcpy is the best way of expressing the intention. Every compiler will 109 | // optimize is to single load instruction if the target architecture 110 | // supports unaligned memory access (GCC and clang even in O0). 111 | // This is great trick because we are violating C/C++ memory alignment 112 | // restrictions with no performance penalty. 113 | uint64_t word; 114 | memcpy(&word, data, sizeof(word)); 115 | return word; 116 | } 117 | 118 | inline void keccak_fastest(uint64_t* out, const uint8_t* data, size_t size) 119 | { 120 | static constexpr size_t block_size = (1600 - 256 * 2) / 8; 121 | 122 | union 123 | { 124 | uint64_t words[25]; 125 | uint8_t bytes[200]; 126 | } state = {{0}}; 127 | 128 | 129 | while (size >= block_size) 130 | { 131 | for (size_t i = 0; i < (block_size / sizeof(uint64_t)); ++i) 132 | state.words[i] ^= fix_endianness(load_le(data + i * sizeof(uint64_t))); 133 | 134 | fake_keccakf1600(state.words); 135 | 136 | data += block_size; 137 | size -= block_size; 138 | } 139 | 140 | uint8_t* p_state_bytes = state.bytes; 141 | 142 | while (size >= sizeof(uint64_t)) 143 | { 144 | uint64_t* p_state_word = (uint64_t*)p_state_bytes; 145 | *p_state_word ^= load_le(data); 146 | data += sizeof(uint64_t); 147 | size -= sizeof(uint64_t); 148 | p_state_bytes += sizeof(uint64_t); 149 | } 150 | 151 | for (size_t i = 0; i < size; ++i) 152 | p_state_bytes[i] ^= data[i]; 153 | 154 | 155 | p_state_bytes[size] ^= 0x01; 156 | state.bytes[block_size - 1] ^= 0x80; 157 | 158 | fake_keccakf1600(state.words); 159 | 160 | for (int i = 0; i < 4; ++i) 161 | out[i] = state.words[i]; 162 | } 163 | } // namespace 164 | 165 | void fake_keccak256_default_aligned(uint64_t* out, const uint8_t* data, size_t size) noexcept 166 | { 167 | keccak_default_aligned<256>(out, (uint64_t*)data, size / 8); 168 | } 169 | 170 | void fake_keccak256_default(uint64_t* out, const uint8_t* data, size_t size) noexcept 171 | { 172 | keccak_default<256>(out, data, size); 173 | } 174 | 175 | void fake_keccak256_fastest(uint64_t* out, const uint8_t* data, size_t size) noexcept 176 | { 177 | keccak_fastest(out, data, size); 178 | } 179 | 180 | void fake_keccak256_fastest_word4(uint64_t out[4], const uint64_t data[4]) noexcept 181 | { 182 | keccak_fastest(out, (const uint8_t*)data, 32); 183 | } 184 | -------------------------------------------------------------------------------- /test/unittests/test_managed.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include "helpers.hpp" 6 | #include "test_cases.hpp" 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | using namespace ethash; 16 | 17 | TEST(managed_multithreaded, hash_all) 18 | { 19 | constexpr size_t num_treads = 8; 20 | 21 | std::array, num_treads> futures; 22 | for (auto& f : futures) 23 | { 24 | f = std::async(std::launch::async, [] { 25 | for (const auto& t : hash_test_cases) 26 | { 27 | const hash256 header_hash = to_hash256(t.header_hash_hex); 28 | const uint64_t nonce = std::stoull(t.nonce_hex, nullptr, 16); 29 | const int epoch_number = get_epoch_number(t.block_number); 30 | auto& context = get_global_epoch_context(epoch_number); 31 | const result res = hash(context, header_hash, nonce); 32 | EXPECT_EQ(to_hex(res.mix_hash), t.mix_hash_hex); 33 | EXPECT_EQ(to_hex(res.final_hash), t.final_hash_hex); 34 | } 35 | }); 36 | } 37 | for (auto& f : futures) 38 | f.wait(); 39 | } 40 | 41 | TEST(managed_multithreaded, hash_parallel) 42 | { 43 | std::vector> futures; 44 | 45 | for (const auto& t : hash_test_cases) 46 | { 47 | futures.emplace_back(std::async(std::launch::async, [&t] { 48 | const hash256 header_hash = to_hash256(t.header_hash_hex); 49 | const uint64_t nonce = std::stoull(t.nonce_hex, nullptr, 16); 50 | const int epoch_number = get_epoch_number(t.block_number); 51 | auto& context = get_global_epoch_context(epoch_number); 52 | const result res = hash(context, header_hash, nonce); 53 | return (to_hex(res.mix_hash) == t.mix_hash_hex) && 54 | (to_hex(res.final_hash) == t.final_hash_hex); 55 | })); 56 | } 57 | 58 | for (auto& f : futures) 59 | EXPECT_TRUE(f.get()); 60 | } 61 | 62 | TEST(managed_multithreaded, verify_all) 63 | { 64 | constexpr size_t num_treads = 8; 65 | 66 | std::array, num_treads> futures; 67 | for (auto& f : futures) 68 | { 69 | f = std::async(std::launch::async, [] { 70 | for (const auto& t : hash_test_cases) 71 | { 72 | const hash256 header_hash = to_hash256(t.header_hash_hex); 73 | const hash256 mix_hash = to_hash256(t.mix_hash_hex); 74 | const hash256 final_hash = to_hash256(t.final_hash_hex); 75 | const uint64_t nonce = std::stoull(t.nonce_hex, nullptr, 16); 76 | const hash256 boundary = final_hash; 77 | const int epoch_number = get_epoch_number(t.block_number); 78 | auto& context = get_global_epoch_context(epoch_number); 79 | const bool valid = verify(context, header_hash, mix_hash, nonce, boundary); 80 | EXPECT_TRUE(valid); 81 | } 82 | }); 83 | } 84 | for (auto& f : futures) 85 | f.wait(); 86 | } 87 | 88 | TEST(managed_multithreaded, verify_parallel) 89 | { 90 | std::vector> futures; 91 | 92 | for (const auto& t : hash_test_cases) 93 | { 94 | futures.emplace_back(std::async(std::launch::async, [&t] { 95 | const hash256 header_hash = to_hash256(t.header_hash_hex); 96 | const hash256 mix_hash = to_hash256(t.mix_hash_hex); 97 | const hash256 final_hash = to_hash256(t.final_hash_hex); 98 | const uint64_t nonce = std::stoull(t.nonce_hex, nullptr, 16); 99 | const hash256 boundary = final_hash; 100 | const int epoch_number = get_epoch_number(t.block_number); 101 | auto& context = get_global_epoch_context(epoch_number); 102 | return verify(context, header_hash, mix_hash, nonce, boundary); 103 | })); 104 | } 105 | 106 | for (auto& f : futures) 107 | EXPECT_TRUE(f.get()); 108 | } 109 | 110 | TEST(managed_multithreaded, get_epoch_context_random) 111 | { 112 | static constexpr int num_threads = 4; 113 | 114 | std::vector> futures; 115 | 116 | for (int i = 0; i < num_threads; ++i) 117 | { 118 | futures.emplace_back(std::async(std::launch::async, [] { 119 | int sum = 0; 120 | for (int j = 0; j < 10; ++j) 121 | { 122 | // Epoch number sequence: 0, 0, 1, 1, 0, 0, 1, 1, ... 123 | int epoch_number = (j / 2) % 2; 124 | get_global_epoch_context(epoch_number); 125 | sum += epoch_number; 126 | 127 | // Add sleep, otherwise this thread will starve others by quickly 128 | // reacquiring the mutex in get_epoch_number(). 129 | std::this_thread::sleep_for(std::chrono::nanoseconds(1)); 130 | } 131 | return sum; 132 | })); 133 | } 134 | 135 | for (auto& f : futures) 136 | EXPECT_GT(f.get(), 0); 137 | } 138 | 139 | TEST(managed_multithreaded, get_epoch_context_full) 140 | { 141 | static constexpr int num_threads = 4; 142 | 143 | std::vector> futures; 144 | 145 | for (int i = 0; i < num_threads; ++i) 146 | { 147 | futures.emplace_back(std::async(std::launch::async, [] { 148 | hash1024* full_dataset1 = get_global_epoch_context_full(7).full_dataset; 149 | hash1024* full_dataset2 = get_global_epoch_context_full(7).full_dataset; 150 | return (full_dataset1 == full_dataset2) && (full_dataset1 != nullptr); 151 | })); 152 | } 153 | 154 | for (auto& f : futures) 155 | EXPECT_TRUE(f.get()); 156 | } 157 | -------------------------------------------------------------------------------- /test/fuzzing/keccak_tiny.c: -------------------------------------------------------------------------------- 1 | /** libkeccak-tiny 2 | * 3 | * A single-file implementation of SHA-3 and SHAKE. 4 | * 5 | * Implementor: David Leon Gil 6 | * License: CC0, attribution kindly requested. Blame taken too, 7 | * but not liability. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | /******** The Keccak-f[1600] permutation ********/ 14 | 15 | /*** Constants. ***/ 16 | static const uint8_t rho[24] = \ 17 | { 1, 3, 6, 10, 15, 21, 18 | 28, 36, 45, 55, 2, 14, 19 | 27, 41, 56, 8, 25, 43, 20 | 62, 18, 39, 61, 20, 44}; 21 | static const uint8_t pi[24] = \ 22 | {10, 7, 11, 17, 18, 3, 23 | 5, 16, 8, 21, 24, 4, 24 | 15, 23, 19, 13, 12, 2, 25 | 20, 14, 22, 9, 6, 1}; 26 | static const uint64_t RC[24] = \ 27 | {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 28 | 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 29 | 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, 30 | 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 31 | 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, 32 | 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; 33 | 34 | /*** Helper macros to unroll the permutation. ***/ 35 | #define rol(x, s) (((x) << s) | ((x) >> (64 - s))) 36 | #define REPEAT6(e) e e e e e e 37 | #define REPEAT24(e) REPEAT6(e e e e) 38 | #define REPEAT5(e) e e e e e 39 | #define FOR5(v, s, e) \ 40 | v = 0; \ 41 | REPEAT5(e; v += s;) 42 | 43 | /*** Keccak-f[1600] ***/ 44 | static inline void keccakf(void* state) { 45 | uint64_t* a = (uint64_t*)state; 46 | uint64_t b[5] = {0}; 47 | uint64_t t = 0; 48 | uint8_t x, y; 49 | 50 | for (int i = 0; i < 24; i++) { 51 | // Theta 52 | FOR5(x, 1, 53 | b[x] = 0; 54 | FOR5(y, 5, 55 | b[x] ^= a[x + y]; )) 56 | FOR5(x, 1, 57 | FOR5(y, 5, 58 | a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) 59 | // Rho and pi 60 | t = a[1]; 61 | x = 0; 62 | REPEAT24(b[0] = a[pi[x]]; 63 | a[pi[x]] = rol(t, rho[x]); 64 | t = b[0]; 65 | x++; ) 66 | // Chi 67 | FOR5(y, 68 | 5, 69 | FOR5(x, 1, 70 | b[x] = a[y + x];) 71 | FOR5(x, 1, 72 | a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) 73 | // Iota 74 | a[0] ^= RC[i]; 75 | } 76 | } 77 | 78 | /******** The FIPS202-defined functions. ********/ 79 | 80 | /*** Some helper macros. ***/ 81 | 82 | #define _(S) do { S } while (0) 83 | #define FOR(i, ST, L, S) \ 84 | _(for (size_t i = 0; i < L; i += ST) { S; }) 85 | #define mkapply_ds(NAME, S) \ 86 | static inline void NAME(uint8_t* dst, \ 87 | const uint8_t* src, \ 88 | size_t len) { \ 89 | FOR(i, 1, len, S); \ 90 | } 91 | #define mkapply_sd(NAME, S) \ 92 | static inline void NAME(const uint8_t* src, \ 93 | uint8_t* dst, \ 94 | size_t len) { \ 95 | FOR(i, 1, len, S); \ 96 | } 97 | 98 | mkapply_ds(xorin, dst[i] ^= src[i]) // xorin 99 | mkapply_sd(setout, dst[i] = src[i]) // setout 100 | 101 | #define P keccakf 102 | #define Plen 200 103 | 104 | // Fold P*F over the full blocks of an input. 105 | #define foldP(I, L, F) \ 106 | while (L >= rate) { \ 107 | F(a, I, rate); \ 108 | P(a); \ 109 | I += rate; \ 110 | L -= rate; \ 111 | } 112 | 113 | /** The sponge-based hash construction. **/ 114 | static inline int hash(uint8_t* out, size_t outlen, 115 | const uint8_t* in, size_t inlen, 116 | size_t rate, uint8_t delim) { 117 | if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { 118 | return -1; 119 | } 120 | uint8_t a[Plen] = {0}; 121 | // Absorb input. 122 | foldP(in, inlen, xorin); 123 | // Xor in the DS and pad frame. 124 | a[inlen] ^= delim; 125 | a[rate - 1] ^= 0x80; 126 | // Xor in the last block. 127 | xorin(a, in, inlen); 128 | // Apply P 129 | P(a); 130 | // Squeeze output. 131 | foldP(out, outlen, setout); 132 | setout(a, out, outlen); 133 | return 0; 134 | } 135 | 136 | /*** Helper macros to define SHA3 and SHAKE instances. ***/ 137 | #define defshake(bits) \ 138 | int shake##bits(uint8_t* out, size_t outlen, \ 139 | const uint8_t* in, size_t inlen) { \ 140 | return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ 141 | } 142 | #define defsha3(bits) \ 143 | int sha3_##bits(uint8_t* out, size_t outlen, \ 144 | const uint8_t* in, size_t inlen) { \ 145 | if (outlen > (bits/8)) { \ 146 | return -1; \ 147 | } \ 148 | return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x06); \ 149 | } 150 | 151 | #define defkeccak(bits) \ 152 | int keccak_tiny_##bits(uint8_t* out, size_t outlen, \ 153 | const uint8_t* in, size_t inlen) { \ 154 | if (outlen > (bits/8)) { \ 155 | return -1; \ 156 | } \ 157 | return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ 158 | } 159 | 160 | defkeccak(256) 161 | defkeccak(512) 162 | -------------------------------------------------------------------------------- /include/ethash/ethash.hpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | /// @file 6 | /// 7 | /// API design decisions: 8 | /// 9 | /// 1. Signed integer type is used whenever the size of the type is not 10 | /// restricted by the Ethash specification. 11 | /// See http://www.aristeia.com/Papers/C++ReportColumns/sep95.pdf. 12 | /// See https://stackoverflow.com/questions/10168079/why-is-size-t-unsigned/. 13 | /// See https://github.com/Microsoft/GSL/issues/171. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace ethash 25 | { 26 | constexpr auto revision = ETHASH_REVISION; 27 | 28 | static constexpr int epoch_length = ETHASH_EPOCH_LENGTH; 29 | static constexpr int light_cache_item_size = ETHASH_LIGHT_CACHE_ITEM_SIZE; 30 | static constexpr int full_dataset_item_size = ETHASH_FULL_DATASET_ITEM_SIZE; 31 | static constexpr int num_dataset_accesses = ETHASH_NUM_DATASET_ACCESSES; 32 | 33 | using epoch_context = ethash_epoch_context; 34 | using epoch_context_full = ethash_epoch_context_full; 35 | 36 | using result = ethash_result; 37 | 38 | /// Constructs a 256-bit hash from an array of bytes. 39 | /// 40 | /// @param bytes A pointer to array of at least 32 bytes. 41 | /// @return The constructed hash. 42 | inline hash256 hash256_from_bytes(const uint8_t bytes[32]) noexcept 43 | { 44 | hash256 h; 45 | std::memcpy(&h, bytes, sizeof(h)); 46 | return h; 47 | } 48 | 49 | struct search_result 50 | { 51 | bool solution_found = false; 52 | uint64_t nonce = 0; 53 | hash256 final_hash = {}; 54 | hash256 mix_hash = {}; 55 | 56 | search_result() noexcept = default; 57 | 58 | search_result(result res, uint64_t n) noexcept 59 | : solution_found(true), nonce(n), final_hash(res.final_hash), mix_hash(res.mix_hash) 60 | {} 61 | }; 62 | 63 | 64 | /// Alias for ethash_calculate_light_cache_num_items(). 65 | static constexpr auto calculate_light_cache_num_items = ethash_calculate_light_cache_num_items; 66 | 67 | /// Alias for ethash_calculate_full_dataset_num_items(). 68 | static constexpr auto calculate_full_dataset_num_items = ethash_calculate_full_dataset_num_items; 69 | 70 | /// Alias for ethash_calculate_epoch_seed(). 71 | static constexpr auto calculate_epoch_seed = ethash_calculate_epoch_seed; 72 | 73 | 74 | /// Calculates the epoch number out of the block number. 75 | inline constexpr int get_epoch_number(int block_number) noexcept 76 | { 77 | return block_number / epoch_length; 78 | } 79 | 80 | /** 81 | * Coverts the number of items of a light cache to size in bytes. 82 | * 83 | * @param num_items The number of items in the light cache. 84 | * @return The size of the light cache in bytes. 85 | */ 86 | inline constexpr size_t get_light_cache_size(int num_items) noexcept 87 | { 88 | return static_cast(num_items) * light_cache_item_size; 89 | } 90 | 91 | /** 92 | * Coverts the number of items of a full dataset to size in bytes. 93 | * 94 | * @param num_items The number of items in the full dataset. 95 | * @return The size of the full dataset in bytes. 96 | */ 97 | inline constexpr uint64_t get_full_dataset_size(int num_items) noexcept 98 | { 99 | return static_cast(num_items) * full_dataset_item_size; 100 | } 101 | 102 | /// Owned unique pointer to an epoch context. 103 | using epoch_context_ptr = std::unique_ptr; 104 | 105 | using epoch_context_full_ptr = 106 | std::unique_ptr; 107 | 108 | /// Creates Ethash epoch context. 109 | /// 110 | /// This is a wrapper for ethash_create_epoch_number C function that returns 111 | /// the context as a smart pointer which handles the destruction of the context. 112 | inline epoch_context_ptr create_epoch_context(int epoch_number) noexcept 113 | { 114 | return {ethash_create_epoch_context(epoch_number), ethash_destroy_epoch_context}; 115 | } 116 | 117 | inline epoch_context_full_ptr create_epoch_context_full(int epoch_number) noexcept 118 | { 119 | return {ethash_create_epoch_context_full(epoch_number), ethash_destroy_epoch_context_full}; 120 | } 121 | 122 | 123 | inline result hash( 124 | const epoch_context& context, const hash256& header_hash, uint64_t nonce) noexcept 125 | { 126 | return ethash_hash(&context, &header_hash, nonce); 127 | } 128 | 129 | result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept; 130 | 131 | inline bool verify_final_hash(const hash256& header_hash, const hash256& mix_hash, uint64_t nonce, 132 | const hash256& boundary) noexcept 133 | { 134 | return ethash_verify_final_hash(&header_hash, &mix_hash, nonce, &boundary); 135 | } 136 | 137 | inline bool verify(const epoch_context& context, const hash256& header_hash, const hash256& mix_hash, 138 | uint64_t nonce, const hash256& boundary) noexcept 139 | { 140 | return ethash_verify(&context, &header_hash, &mix_hash, nonce, &boundary); 141 | } 142 | 143 | search_result search_light(const epoch_context& context, const hash256& header_hash, 144 | const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept; 145 | 146 | search_result search(const epoch_context_full& context, const hash256& header_hash, 147 | const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept; 148 | 149 | 150 | /// Tries to find the epoch number matching the given seed hash. 151 | /// 152 | /// Mining pool protocols (many variants of stratum and "getwork") send out 153 | /// seed hash instead of epoch number to workers. This function tries to recover 154 | /// the epoch number from this seed hash. 155 | /// 156 | /// @param seed Ethash seed hash. 157 | /// @return The epoch number or -1 if not found. 158 | int find_epoch_number(const hash256& seed) noexcept; 159 | 160 | 161 | /// Get global shared epoch context. 162 | inline const epoch_context& get_global_epoch_context(int epoch_number) noexcept 163 | { 164 | return *ethash_get_global_epoch_context(epoch_number); 165 | } 166 | 167 | /// Get global shared epoch context with full dataset initialized. 168 | inline const epoch_context_full& get_global_epoch_context_full(int epoch_number) noexcept 169 | { 170 | return *ethash_get_global_epoch_context_full(epoch_number); 171 | } 172 | } // namespace ethash 173 | -------------------------------------------------------------------------------- /test/benchmarks/ethash_benchmarks.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include "../unittests/helpers.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | static void calculate_light_cache_num_items(benchmark::State& state) 15 | { 16 | const auto epoch_number = static_cast(state.range(0)); 17 | 18 | for (auto _ : state) 19 | { 20 | auto answer = ethash::calculate_light_cache_num_items(epoch_number); 21 | benchmark::DoNotOptimize(&answer); 22 | } 23 | } 24 | BENCHMARK(calculate_light_cache_num_items)->Arg(32638)->Arg(32639); 25 | 26 | static void calculate_full_dataset_num_items(benchmark::State& state) 27 | { 28 | const auto epoch_number = static_cast(state.range(0)); 29 | 30 | for (auto _ : state) 31 | { 32 | auto answer = ethash::calculate_full_dataset_num_items(epoch_number); 33 | benchmark::DoNotOptimize(&answer); 34 | } 35 | } 36 | BENCHMARK(calculate_full_dataset_num_items)->Arg(32638)->Arg(32639); 37 | 38 | 39 | static void seed(benchmark::State& state) 40 | { 41 | const int epoch_number = static_cast(state.range(0)); 42 | 43 | for (auto _ : state) 44 | { 45 | auto seed = ethash::calculate_epoch_seed(epoch_number); 46 | benchmark::DoNotOptimize(seed.bytes); 47 | } 48 | } 49 | BENCHMARK(seed)->Arg(1)->Arg(10)->Arg(100)->Arg(1000)->Arg(10000); 50 | 51 | 52 | static void light_cache(benchmark::State& state) 53 | { 54 | const int epoch_number = static_cast(state.range(0)); 55 | const auto num_items = ethash::calculate_light_cache_num_items(epoch_number); 56 | const auto seed = ethash::calculate_epoch_seed(epoch_number); 57 | 58 | std::unique_ptr light_cache{new ethash::hash512[num_items]}; 59 | 60 | for (auto _ : state) 61 | { 62 | ethash::build_light_cache(light_cache.get(), num_items, seed); 63 | benchmark::DoNotOptimize(light_cache.get()); 64 | } 65 | } 66 | BENCHMARK(light_cache)->Arg(1)->Unit(benchmark::kMillisecond); 67 | 68 | 69 | static void ethash_calculate_dataset_item_512(benchmark::State& state) 70 | { 71 | auto& ctx = get_ethash_epoch_context_0(); 72 | 73 | for (auto _ : state) 74 | { 75 | auto item = ethash::calculate_dataset_item_512(ctx, 1234); 76 | benchmark::DoNotOptimize(item.bytes); 77 | } 78 | } 79 | BENCHMARK(ethash_calculate_dataset_item_512); 80 | 81 | 82 | static void ethash_calculate_dataset_item_1024(benchmark::State& state) 83 | { 84 | auto& ctx = get_ethash_epoch_context_0(); 85 | 86 | for (auto _ : state) 87 | { 88 | auto item = ethash::calculate_dataset_item_1024(ctx, 1234); 89 | benchmark::DoNotOptimize(item.bytes); 90 | } 91 | } 92 | BENCHMARK(ethash_calculate_dataset_item_1024); 93 | 94 | 95 | static void ethash_calculate_dataset_item_2048(benchmark::State& state) 96 | { 97 | auto& ctx = get_ethash_epoch_context_0(); 98 | 99 | for (auto _ : state) 100 | { 101 | auto item = ethash::calculate_dataset_item_2048(ctx, 1234); 102 | benchmark::DoNotOptimize(item.bytes); 103 | } 104 | } 105 | BENCHMARK(ethash_calculate_dataset_item_2048); 106 | 107 | 108 | static void ethash_hash(benchmark::State& state) 109 | { 110 | // Get block number in millions. 111 | const int block_number = static_cast(state.range(0)) * 1000000; 112 | uint64_t nonce = 1; 113 | 114 | const auto& ctx = ethash::get_global_epoch_context(ethash::get_epoch_number(block_number)); 115 | 116 | for (auto _ : state) 117 | ethash::hash(ctx, {}, nonce++); 118 | } 119 | BENCHMARK(ethash_hash)->Unit(benchmark::kMicrosecond)->Arg(0)->Arg(10); 120 | 121 | 122 | static void verify(benchmark::State& state) 123 | { 124 | const int block_number = 5000000; 125 | const ethash::hash256 header_hash = 126 | to_hash256("bc544c2baba832600013bd5d1983f592e9557d04b0fb5ef7a100434a5fc8d52a"); 127 | const ethash::hash256 mix_hash = 128 | to_hash256("94cd4e844619ee20989578276a0a9046877d569d37ba076bf2e8e34f76189dea"); 129 | const uint64_t nonce = 0x4617a20003ba3f25; 130 | const ethash::hash256 boundry = 131 | to_hash256("0000000000001a5c000000000000000000000000000000000000000000000000"); 132 | 133 | static const auto ctx = ethash::create_epoch_context(ethash::get_epoch_number(block_number)); 134 | 135 | for (auto _ : state) 136 | ethash::verify(*ctx, header_hash, mix_hash, nonce, boundry); 137 | } 138 | BENCHMARK(verify); 139 | 140 | 141 | static void verify_mt(benchmark::State& state) 142 | { 143 | const int block_number = 5000000; 144 | const ethash::hash256 header_hash = 145 | to_hash256("bc544c2baba832600013bd5d1983f592e9557d04b0fb5ef7a100434a5fc8d52a"); 146 | const ethash::hash256 mix_hash = 147 | to_hash256("94cd4e844619ee20989578276a0a9046877d569d37ba076bf2e8e34f76189dea"); 148 | const uint64_t nonce = 0x4617a20003ba3f25; 149 | const ethash::hash256 boundry = 150 | to_hash256("0000000000001a5c000000000000000000000000000000000000000000000000"); 151 | 152 | static const auto ctx = ethash::create_epoch_context(ethash::get_epoch_number(block_number)); 153 | 154 | for (auto _ : state) 155 | ethash::verify(*ctx, header_hash, mix_hash, nonce, boundry); 156 | } 157 | BENCHMARK(verify_mt)->Threads(1)->Threads(2)->Threads(4)->Threads(8); 158 | 159 | 160 | static void verify_managed(benchmark::State& state) 161 | { 162 | const int block_number = 5000000; 163 | const ethash::hash256 header_hash = 164 | to_hash256("bc544c2baba832600013bd5d1983f592e9557d04b0fb5ef7a100434a5fc8d52a"); 165 | const ethash::hash256 mix_hash = 166 | to_hash256("94cd4e844619ee20989578276a0a9046877d569d37ba076bf2e8e34f76189dea"); 167 | const uint64_t nonce = 0x4617a20003ba3f25; 168 | const ethash::hash256 boundry = 169 | to_hash256("0000000000001a5c000000000000000000000000000000000000000000000000"); 170 | 171 | const int epoch_number = ethash::get_epoch_number(block_number); 172 | 173 | // This should create the light cache. 174 | ethash::get_global_epoch_context(epoch_number); 175 | 176 | for (auto _ : state) 177 | { 178 | auto& context = ethash::get_global_epoch_context(epoch_number); 179 | ethash::verify(context, header_hash, mix_hash, nonce, boundry); 180 | } 181 | } 182 | BENCHMARK(verify_managed)->Threads(1)->Threads(2)->Threads(4)->Threads(8); 183 | 184 | 185 | BENCHMARK_MAIN(); 186 | -------------------------------------------------------------------------------- /test/unittests/test_progpow.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | #include 7 | 8 | #include "helpers.hpp" 9 | #include "progpow_test_vectors.hpp" 10 | 11 | #include 12 | #include 13 | 14 | TEST(progpow, revision) 15 | { 16 | static_assert(progpow::revision[0] == '0', ""); 17 | static_assert(progpow::revision[1] == '.', ""); 18 | static_assert(progpow::revision[2] == '9', ""); 19 | static_assert(progpow::revision[3] == '.', ""); 20 | static_assert(progpow::revision[4] == '4', ""); 21 | EXPECT_EQ(progpow::revision, "0.9.4"); 22 | EXPECT_EQ(progpow::revision, (std::string{"0.9.4"})); 23 | } 24 | 25 | TEST(progpow, l1_cache) 26 | { 27 | auto& context = get_ethash_epoch_context_0(); 28 | 29 | constexpr auto test_size = 20; 30 | std::array cache_slice; 31 | for (size_t i = 0; i < cache_slice.size(); ++i) 32 | cache_slice[i] = ethash::le::uint32(context.l1_cache[i]); 33 | 34 | const std::array expected{ 35 | {2492749011, 430724829, 2029256771, 3095580433, 3583790154, 3025086503, 36 | 805985885, 4121693337, 2320382801, 3763444918, 1006127899, 1480743010, 37 | 2592936015, 2598973744, 3038068233, 2754267228, 2867798800, 2342573634, 38 | 467767296, 246004123}}; 39 | EXPECT_EQ(cache_slice, expected); 40 | } 41 | 42 | TEST(progpow, hash_empty) 43 | { 44 | auto& context = get_ethash_epoch_context_0(); 45 | 46 | const auto result = progpow::hash(context, 0, {}, 0); 47 | const auto mix_hex = "6e97b47b134fda0c7888802988e1a373affeb28bcd813b6e9a0fc669c935d03a"; 48 | const auto final_hex = "e601a7257a70dc48fccc97a7330d704d776047623b92883d77111fb36870f3d1"; 49 | EXPECT_EQ(to_hex(result.mix_hash), mix_hex); 50 | EXPECT_EQ(to_hex(result.final_hash), final_hex); 51 | } 52 | 53 | TEST(progpow, hash_30000) 54 | { 55 | const int block_number = 30000; 56 | const auto header = 57 | to_hash256("ffeeddccbbaa9988776655443322110000112233445566778899aabbccddeeff"); 58 | const uint64_t nonce = 0x123456789abcdef0; 59 | 60 | auto context = ethash::create_epoch_context(ethash::get_epoch_number(block_number)); 61 | 62 | const auto result = progpow::hash(*context, block_number, header, nonce); 63 | const auto mix_hex = "177b565752a375501e11b6d9d3679c2df6197b2cab3a1ba2d6b10b8c71a3d459"; 64 | const auto final_hex = "c824bee0418e3cfb7fae56e0d5b3b8b14ba895777feea81c70c0ba947146da69"; 65 | EXPECT_EQ(to_hex(result.mix_hash), mix_hex); 66 | EXPECT_EQ(to_hex(result.final_hash), final_hex); 67 | } 68 | 69 | TEST(progpow, hash_and_verify) 70 | { 71 | ethash::epoch_context_ptr context{nullptr, nullptr}; 72 | 73 | for (auto& t : progpow_hash_test_cases) 74 | { 75 | const auto epoch_number = ethash::get_epoch_number(t.block_number); 76 | if (!context || context->epoch_number != epoch_number) 77 | context = ethash::create_epoch_context(epoch_number); 78 | 79 | const auto header_hash = to_hash256(t.header_hash_hex); 80 | const auto nonce = std::stoull(t.nonce_hex, nullptr, 16); 81 | const auto result = progpow::hash(*context, t.block_number, header_hash, nonce); 82 | EXPECT_EQ(to_hex(result.mix_hash), t.mix_hash_hex); 83 | EXPECT_EQ(to_hex(result.final_hash), t.final_hash_hex); 84 | 85 | auto success = progpow::verify( 86 | *context, t.block_number, header_hash, result.mix_hash, nonce, result.final_hash); 87 | EXPECT_TRUE(success); 88 | 89 | auto lower_boundary = result.final_hash; 90 | --lower_boundary.bytes[31]; 91 | auto final_failure = progpow::verify( 92 | *context, t.block_number, header_hash, result.mix_hash, nonce, lower_boundary); 93 | EXPECT_FALSE(final_failure); 94 | 95 | auto different_mix = result.mix_hash; 96 | ++different_mix.bytes[7]; 97 | auto mix_failure = progpow::verify( 98 | *context, t.block_number, header_hash, different_mix, nonce, result.final_hash); 99 | EXPECT_FALSE(mix_failure); 100 | } 101 | } 102 | 103 | TEST(progpow, search) 104 | { 105 | auto ctxp = ethash::create_epoch_context_full(0); 106 | auto& ctx = *ctxp; 107 | auto& ctxl = reinterpret_cast(ctx); 108 | 109 | auto boundary = to_hash256("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); 110 | auto sr = progpow::search(ctx, 0, {}, boundary, 700, 100); 111 | auto srl = progpow::search_light(ctxl, 0, {}, boundary, 700, 100); 112 | 113 | EXPECT_EQ(sr.mix_hash, ethash::hash256{}); 114 | EXPECT_EQ(sr.final_hash, ethash::hash256{}); 115 | EXPECT_EQ(sr.nonce, 0x0); 116 | EXPECT_EQ(sr.mix_hash, srl.mix_hash); 117 | EXPECT_EQ(sr.final_hash, srl.final_hash); 118 | EXPECT_EQ(sr.nonce, srl.nonce); 119 | 120 | sr = progpow::search(ctx, 0, {}, boundary, 300, 100); 121 | srl = progpow::search_light(ctxl, 0, {}, boundary, 300, 100); 122 | 123 | EXPECT_NE(sr.mix_hash, ethash::hash256{}); 124 | EXPECT_NE(sr.final_hash, ethash::hash256{}); 125 | EXPECT_EQ(sr.nonce, 395); 126 | EXPECT_EQ(sr.mix_hash, srl.mix_hash); 127 | EXPECT_EQ(sr.final_hash, srl.final_hash); 128 | EXPECT_EQ(sr.nonce, srl.nonce); 129 | 130 | auto r = progpow::hash(ctx, 0, {}, 395); 131 | EXPECT_EQ(sr.final_hash, r.final_hash); 132 | EXPECT_EQ(sr.mix_hash, r.mix_hash); 133 | } 134 | 135 | #if ETHASH_TEST_GENERATION 136 | TEST(progpow, generate_hash_test_cases) 137 | { 138 | constexpr auto num_epochs = 2; 139 | 140 | using namespace progpow; 141 | hash256 h{}; 142 | for (int e = 0; e < num_epochs; ++e) 143 | { 144 | auto context = ethash::create_epoch_context(e); 145 | auto block_numbers = { 146 | e * epoch_length, 147 | e * epoch_length + period_length - 1, 148 | e * epoch_length + period_length, 149 | e * epoch_length + 2 * period_length - 1, 150 | (e + 1) * epoch_length - period_length, 151 | (e + 1) * epoch_length - 1, 152 | }; 153 | for (auto b : block_numbers) 154 | { 155 | auto i = uint64_t(b); 156 | auto nonce = i * i * i * 977 + i * i * 997 + i * 1009; 157 | auto r = hash(*context, b, h, nonce); 158 | 159 | std::cout << "{" << b << ", \"" << to_hex(h) << "\", \"" << std::hex 160 | << std::setfill('0') << std::setw(16) << nonce << std::dec << "\", \"" 161 | << to_hex(r.mix_hash) << "\", \"" << to_hex(r.final_hash) << "\"},\n"; 162 | 163 | h = r.final_hash; 164 | } 165 | } 166 | } 167 | #endif -------------------------------------------------------------------------------- /test/daemon/kawpow.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "../../test/unittests/helpers.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include /* strtoumax */ 15 | #include 16 | #include 17 | 18 | #define DEFAULT_PORT 8799 19 | 20 | static bool str_to_uint16(const char *str, uint16_t *res); 21 | 22 | int main(int argc, const char* argv[]) 23 | { 24 | static int epoch_number = 0; 25 | std::uint16_t SrvPort = DEFAULT_PORT; 26 | static ethash::epoch_context_ptr context_light{nullptr, nullptr}; 27 | 28 | for (int i = 0; i < argc; ++i) 29 | { 30 | const std::string arg{argv[i]}; 31 | 32 | if (arg == "-p" && i + 1 < argc) { 33 | if (!str_to_uint16(argv[++i], &SrvPort)) { 34 | fprintf(stderr, "conversion error\n"); 35 | exit(2); 36 | } 37 | } 38 | 39 | if (arg == "-e" && i + 1 < argc) 40 | epoch_number = atoi(argv[++i]); 41 | } 42 | 43 | // Build context 44 | if (!context_light || context_light->epoch_number != epoch_number) { 45 | std::cout << "Building context for epoch: " << epoch_number << std::endl; 46 | context_light = ethash::create_epoch_context(epoch_number); 47 | } 48 | 49 | if (!event_init()) 50 | { 51 | std::cerr << "Failed to init libevent." << std::endl; 52 | return -1; 53 | } 54 | 55 | // Setup server 56 | char const SrvAddress[] = "127.0.0.1"; 57 | std::unique_ptr Server(evhttp_start(SrvAddress, SrvPort), &evhttp_free); 58 | if (!Server) 59 | { 60 | std::cerr << "Failed to init http server." << std::endl; 61 | return -1; 62 | } 63 | 64 | std::cout << "Server started!" << std::endl; 65 | std::cout << "Listening on port: " << SrvPort << std::endl; 66 | 67 | void (*OnReq)(evhttp_request *req, void *) = [] (evhttp_request *req, void *) 68 | { 69 | auto *OutBuf = evhttp_request_get_output_buffer(req); 70 | 71 | if (!OutBuf) 72 | return; 73 | 74 | // Construct the query struct 75 | struct evkeyvalq headers{}; 76 | const struct evhttp_uri *uri = evhttp_request_get_evhttp_uri(req); 77 | const char * query = evhttp_uri_get_query(uri); 78 | evhttp_parse_query_str(query, &headers); 79 | 80 | // Get the headers from the query struct 81 | const char* header_hash_str = evhttp_find_header(&headers, "header_hash"); 82 | const char* mix_hash_str = evhttp_find_header(&headers, "mix_hash"); 83 | const char* nonce_str = evhttp_find_header(&headers, "nonce"); 84 | const char* height_str = evhttp_find_header(&headers, "height"); 85 | const char* share_boundary_str = evhttp_find_header(&headers, "share_boundary"); 86 | const char* block_boundary_str = evhttp_find_header(&headers, "block_boundary"); 87 | 88 | if (!header_hash_str || !mix_hash_str || !nonce_str || !height_str || !share_boundary_str || !block_boundary_str) { 89 | std::string error = ""; 90 | 91 | if (!header_hash_str) 92 | error = "Invalid header_hash"; 93 | else if (!mix_hash_str) 94 | error = "Invalid mix_hash"; 95 | else if (!nonce_str) 96 | error = "Invalid nonce"; 97 | else if (!height_str) 98 | error = "Invalid height"; 99 | else if (!share_boundary_str) 100 | error = "Invalid share_boundary"; 101 | else if (!block_boundary_str) 102 | error = "Invalid block_boundary"; 103 | 104 | evhttp_send_reply(req, HTTP_BADREQUEST, error.c_str(), OutBuf); 105 | } else { 106 | auto header_hash = to_hash256(header_hash_str); 107 | auto mix_hash = to_hash256(mix_hash_str); 108 | auto share_boundary = to_hash256(share_boundary_str); 109 | auto block_boundary = to_hash256(block_boundary_str); 110 | 111 | // Convert nonce from string 112 | uint64_t nNonce; 113 | errno = 0; 114 | char *endp = nullptr; 115 | errno = 0; // strtoull will not set errno if valid 116 | unsigned long long int n = strtoull(nonce_str, &endp, 16); 117 | nNonce = (uint64_t) n; 118 | 119 | // Convert height from string 120 | uint32_t nHeight; 121 | errno = 0; 122 | endp = nullptr; 123 | errno = 0; // strtoul will not set errno if valid 124 | unsigned long int nH = strtoul(height_str, &endp, 10); 125 | nHeight = (uint32_t) nH; 126 | 127 | // Check epoch number and context 128 | epoch_number = (int) nHeight / ETHASH_EPOCH_LENGTH; 129 | if (!context_light || context_light->epoch_number != epoch_number) { 130 | context_light = ethash::create_epoch_context(epoch_number); 131 | std::cout << "Building new context for epoch: " << epoch_number << std::endl; 132 | } 133 | 134 | const auto result = progpow::hash(*context_light, (int) nHeight, header_hash, nNonce); 135 | std::string share_met = "false"; 136 | std::string block_met = "false"; 137 | std::string mix_match = "false"; 138 | if (result.mix_hash == mix_hash) { 139 | mix_match = "true"; 140 | } 141 | 142 | if (ethash::is_less_or_equal(result.final_hash, share_boundary)) { 143 | share_met = "true"; 144 | } 145 | 146 | if (ethash::is_less_or_equal(result.final_hash, block_boundary)) { 147 | block_met = "true"; 148 | } 149 | 150 | evbuffer_add_printf(OutBuf, "{\"%s\":%s, \"%s\":%s, \"%s\":%s, \"%s\":\"%s\"}", "result", mix_match.c_str(), 151 | "share", share_met.c_str(), "block", block_met.c_str(), "digest", 152 | to_hex(result.final_hash).c_str()); 153 | evhttp_send_reply(req, HTTP_OK, "", OutBuf); 154 | } 155 | }; 156 | evhttp_set_gencb(Server.get(), OnReq, nullptr); 157 | if (event_dispatch() == -1) 158 | { 159 | std::cerr << "Failed to run message loop." << std::endl; 160 | return -1; 161 | } 162 | return 0; 163 | } 164 | 165 | static bool str_to_uint16(const char *str, uint16_t *res) 166 | { 167 | char *end; 168 | errno = 0; 169 | intmax_t val = strtoimax(str, &end, 10); 170 | if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str || *end != '\0') 171 | return false; 172 | *res = (uint16_t) val; 173 | return true; 174 | } -------------------------------------------------------------------------------- /cmake/cable/CableCompilerSettings.cmake: -------------------------------------------------------------------------------- 1 | # Cable: CMake Bootstrap Library 2 | # Copyright 2018 Pawel Bylica. 3 | # Licensed under the Apache License, Version 2.0. See the LICENSE file. 4 | 5 | include(CheckCXXCompilerFlag) 6 | 7 | # Adds CXX compiler flag if the flag is supported by the compiler. 8 | # 9 | # This is effectively a combination of CMake's check_cxx_compiler_flag() 10 | # and add_compile_options(): 11 | # 12 | # if(check_cxx_compiler_flag(flag)) 13 | # add_compile_options(flag) 14 | # 15 | function(cable_add_cxx_compiler_flag_if_supported FLAG) 16 | # Remove leading - or / from the flag name. 17 | string(REGEX REPLACE "^-|/" "" name ${FLAG}) 18 | check_cxx_compiler_flag(${FLAG} ${name}) 19 | if(${name}) 20 | add_compile_options(${FLAG}) 21 | endif() 22 | 23 | # If the optional argument passed, store the result there. 24 | if(ARGV1) 25 | set(${ARGV1} ${name} PARENT_SCOPE) 26 | endif() 27 | endfunction() 28 | 29 | 30 | # Configures the compiler with default flags. 31 | macro(cable_configure_compiler) 32 | if(NOT PROJECT_IS_NESTED) 33 | # Do this configuration only in the top project. 34 | 35 | cmake_parse_arguments(cable "NO_CONVERSION_WARNINGS;NO_STACK_PROTECTION;NO_PEDANTIC" "" "" ${ARGN}) 36 | 37 | if(cable_UNPARSED_ARGUMENTS) 38 | message(FATAL_ERROR "cable_configure_compiler: Unknown options: ${cable_UNPARSED_ARGUMENTS}") 39 | endif() 40 | 41 | # Set helper variables recognizing C++ compilers. 42 | if(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU) 43 | set(CABLE_COMPILER_GNU TRUE) 44 | elseif(${CMAKE_CXX_COMPILER_ID} MATCHES Clang) 45 | # This matches both clang and AppleClang. 46 | set(CABLE_COMPILER_CLANG TRUE) 47 | endif() 48 | 49 | if(CABLE_COMPILER_GNU OR CABLE_COMPILER_CLANG) 50 | set(CABLE_COMPILER_GNULIKE TRUE) 51 | endif() 52 | 53 | if(CABLE_COMPILER_GNULIKE) 54 | 55 | if(NOT cable_NO_PEDANTIC) 56 | add_compile_options(-Wpedantic) 57 | endif() 58 | 59 | # Enable basing warnings set and treat them as errors. 60 | add_compile_options(-Werror -Wall -Wextra -Wshadow) 61 | 62 | if(NOT cable_NO_CONVERSION_WARNINGS) 63 | # Enable conversion warnings if not explicitly disabled. 64 | add_compile_options(-Wconversion -Wsign-conversion) 65 | endif() 66 | 67 | # Allow unknown pragmas, we don't want to wrap them with #ifdefs. 68 | add_compile_options(-Wno-unknown-pragmas) 69 | 70 | # Stack protection. 71 | check_cxx_compiler_flag(-fstack-protector fstack-protector) 72 | if(fstack-protector) 73 | # The compiler supports stack protection options. 74 | if(cable_NO_STACK_PROTECTION) 75 | # Stack protection explicitly disabled. 76 | # Add "no" flag, because in some configuration the compiler has it enabled by default. 77 | add_compile_options(-fno-stack-protector) 78 | else() 79 | # Try enabling the "strong" variant. 80 | cable_add_cxx_compiler_flag_if_supported(-fstack-protector-strong have_stack_protector_strong_support) 81 | if(NOT have_stack_protector_strong_support) 82 | # Fallback to standard variant of "strong" not available. 83 | add_compile_options(-fstack-protector) 84 | endif() 85 | endif() 86 | endif() 87 | 88 | cable_add_cxx_compiler_flag_if_supported(-Wimplicit-fallthrough) 89 | 90 | elseif(MSVC) 91 | 92 | # Get rid of default warning level. 93 | string(REPLACE " /W3" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 94 | string(REPLACE " /W3" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") 95 | 96 | # Enable basing warnings set and treat them as errors. 97 | add_compile_options(/W4 /WX) 98 | 99 | # Allow unknown pragmas, we don't want to wrap them with #ifdefs. 100 | add_compile_options(/wd4068) 101 | 102 | endif() 103 | 104 | # Option for arch=native. 105 | option(NATIVE "Build for native CPU" OFF) 106 | if(NATIVE) 107 | if(MSVC) 108 | add_compile_options(-arch:AVX) 109 | else() 110 | add_compile_options(-mtune=native -march=native) 111 | endif() 112 | elseif(NOT MSVC) 113 | # Tune for currently most common CPUs. 114 | cable_add_cxx_compiler_flag_if_supported(-mtune=generic) 115 | endif() 116 | 117 | # Sanitizers support. 118 | set(SANITIZE OFF CACHE STRING "Build with the specified sanitizer") 119 | if(SANITIZE) 120 | # Set the linker flags first, they are required to properly test the compiler flag. 121 | set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=${SANITIZE} ${CMAKE_SHARED_LINKER_FLAGS}") 122 | set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=${SANITIZE} ${CMAKE_EXE_LINKER_FLAGS}") 123 | 124 | set(test_name have_fsanitize_${SANITIZE}) 125 | check_cxx_compiler_flag(-fsanitize=${SANITIZE} ${test_name}) 126 | if(NOT ${test_name}) 127 | message(FATAL_ERROR "Unsupported sanitizer: ${SANITIZE}") 128 | endif() 129 | add_compile_options(-fno-omit-frame-pointer -fsanitize=${SANITIZE}) 130 | 131 | set(backlist_file ${PROJECT_SOURCE_DIR}/sanitizer-blacklist.txt) 132 | if(EXISTS ${backlist_file}) 133 | check_cxx_compiler_flag(-fsanitize-blacklist=${backlist_file} have_fsanitize-blacklist) 134 | if(have_fsanitize-blacklist) 135 | add_compile_options(-fsanitize-blacklist=${backlist_file}) 136 | endif() 137 | endif() 138 | endif() 139 | 140 | # Code coverage support. 141 | option(COVERAGE "Build with code coverage support" OFF) 142 | if(COVERAGE) 143 | # Set the linker flags first, they are required to properly test the compiler flag. 144 | set(CMAKE_SHARED_LINKER_FLAGS "--coverage ${CMAKE_SHARED_LINKER_FLAGS}") 145 | set(CMAKE_EXE_LINKER_FLAGS "--coverage ${CMAKE_EXE_LINKER_FLAGS}") 146 | 147 | set(CMAKE_REQUIRED_LIBRARIES "--coverage ${CMAKE_REQUIRED_LIBRARIES}") 148 | check_cxx_compiler_flag(--coverage have_coverage) 149 | string(REPLACE "--coverage " "" CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) 150 | if(NOT have_coverage) 151 | message(FATAL_ERROR "Coverage not supported") 152 | endif() 153 | add_compile_options(-g --coverage) 154 | endif() 155 | 156 | endif() 157 | endmacro() 158 | -------------------------------------------------------------------------------- /lib/keccak/keccakf800.c: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #include 7 | 8 | static uint32_t rol(uint32_t x, unsigned s) 9 | { 10 | return (x << s) | (x >> (32 - s)); 11 | } 12 | 13 | static const uint32_t round_constants[22] = { 14 | 0x00000001, 15 | 0x00008082, 16 | 0x0000808A, 17 | 0x80008000, 18 | 0x0000808B, 19 | 0x80000001, 20 | 0x80008081, 21 | 0x00008009, 22 | 0x0000008A, 23 | 0x00000088, 24 | 0x80008009, 25 | 0x8000000A, 26 | 0x8000808B, 27 | 0x0000008B, 28 | 0x00008089, 29 | 0x00008003, 30 | 0x00008002, 31 | 0x00000080, 32 | 0x0000800A, 33 | 0x8000000A, 34 | 0x80008081, 35 | 0x00008080, 36 | }; 37 | 38 | void ethash_keccakf800(uint32_t state[25]) 39 | { 40 | /* The implementation directly translated from ethash_keccakf1600. */ 41 | 42 | int round; 43 | 44 | uint32_t Aba, Abe, Abi, Abo, Abu; 45 | uint32_t Aga, Age, Agi, Ago, Agu; 46 | uint32_t Aka, Ake, Aki, Ako, Aku; 47 | uint32_t Ama, Ame, Ami, Amo, Amu; 48 | uint32_t Asa, Ase, Asi, Aso, Asu; 49 | 50 | uint32_t Eba, Ebe, Ebi, Ebo, Ebu; 51 | uint32_t Ega, Ege, Egi, Ego, Egu; 52 | uint32_t Eka, Eke, Eki, Eko, Eku; 53 | uint32_t Ema, Eme, Emi, Emo, Emu; 54 | uint32_t Esa, Ese, Esi, Eso, Esu; 55 | 56 | uint32_t Ba, Be, Bi, Bo, Bu; 57 | 58 | uint32_t Da, De, Di, Do, Du; 59 | 60 | Aba = state[0]; 61 | Abe = state[1]; 62 | Abi = state[2]; 63 | Abo = state[3]; 64 | Abu = state[4]; 65 | Aga = state[5]; 66 | Age = state[6]; 67 | Agi = state[7]; 68 | Ago = state[8]; 69 | Agu = state[9]; 70 | Aka = state[10]; 71 | Ake = state[11]; 72 | Aki = state[12]; 73 | Ako = state[13]; 74 | Aku = state[14]; 75 | Ama = state[15]; 76 | Ame = state[16]; 77 | Ami = state[17]; 78 | Amo = state[18]; 79 | Amu = state[19]; 80 | Asa = state[20]; 81 | Ase = state[21]; 82 | Asi = state[22]; 83 | Aso = state[23]; 84 | Asu = state[24]; 85 | 86 | for (round = 0; round < 22; round += 2) 87 | { 88 | /* Round (round + 0): Axx -> Exx */ 89 | 90 | Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa; 91 | Be = Abe ^ Age ^ Ake ^ Ame ^ Ase; 92 | Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; 93 | Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; 94 | Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; 95 | 96 | Da = Bu ^ rol(Be, 1); 97 | De = Ba ^ rol(Bi, 1); 98 | Di = Be ^ rol(Bo, 1); 99 | Do = Bi ^ rol(Bu, 1); 100 | Du = Bo ^ rol(Ba, 1); 101 | 102 | Ba = Aba ^ Da; 103 | Be = rol(Age ^ De, 12); 104 | Bi = rol(Aki ^ Di, 11); 105 | Bo = rol(Amo ^ Do, 21); 106 | Bu = rol(Asu ^ Du, 14); 107 | Eba = Ba ^ (~Be & Bi) ^ round_constants[round]; 108 | Ebe = Be ^ (~Bi & Bo); 109 | Ebi = Bi ^ (~Bo & Bu); 110 | Ebo = Bo ^ (~Bu & Ba); 111 | Ebu = Bu ^ (~Ba & Be); 112 | 113 | Ba = rol(Abo ^ Do, 28); 114 | Be = rol(Agu ^ Du, 20); 115 | Bi = rol(Aka ^ Da, 3); 116 | Bo = rol(Ame ^ De, 13); 117 | Bu = rol(Asi ^ Di, 29); 118 | Ega = Ba ^ (~Be & Bi); 119 | Ege = Be ^ (~Bi & Bo); 120 | Egi = Bi ^ (~Bo & Bu); 121 | Ego = Bo ^ (~Bu & Ba); 122 | Egu = Bu ^ (~Ba & Be); 123 | 124 | Ba = rol(Abe ^ De, 1); 125 | Be = rol(Agi ^ Di, 6); 126 | Bi = rol(Ako ^ Do, 25); 127 | Bo = rol(Amu ^ Du, 8); 128 | Bu = rol(Asa ^ Da, 18); 129 | Eka = Ba ^ (~Be & Bi); 130 | Eke = Be ^ (~Bi & Bo); 131 | Eki = Bi ^ (~Bo & Bu); 132 | Eko = Bo ^ (~Bu & Ba); 133 | Eku = Bu ^ (~Ba & Be); 134 | 135 | Ba = rol(Abu ^ Du, 27); 136 | Be = rol(Aga ^ Da, 4); 137 | Bi = rol(Ake ^ De, 10); 138 | Bo = rol(Ami ^ Di, 15); 139 | Bu = rol(Aso ^ Do, 24); 140 | Ema = Ba ^ (~Be & Bi); 141 | Eme = Be ^ (~Bi & Bo); 142 | Emi = Bi ^ (~Bo & Bu); 143 | Emo = Bo ^ (~Bu & Ba); 144 | Emu = Bu ^ (~Ba & Be); 145 | 146 | Ba = rol(Abi ^ Di, 30); 147 | Be = rol(Ago ^ Do, 23); 148 | Bi = rol(Aku ^ Du, 7); 149 | Bo = rol(Ama ^ Da, 9); 150 | Bu = rol(Ase ^ De, 2); 151 | Esa = Ba ^ (~Be & Bi); 152 | Ese = Be ^ (~Bi & Bo); 153 | Esi = Bi ^ (~Bo & Bu); 154 | Eso = Bo ^ (~Bu & Ba); 155 | Esu = Bu ^ (~Ba & Be); 156 | 157 | 158 | /* Round (round + 1): Exx -> Axx */ 159 | 160 | Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa; 161 | Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; 162 | Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; 163 | Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; 164 | Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; 165 | 166 | Da = Bu ^ rol(Be, 1); 167 | De = Ba ^ rol(Bi, 1); 168 | Di = Be ^ rol(Bo, 1); 169 | Do = Bi ^ rol(Bu, 1); 170 | Du = Bo ^ rol(Ba, 1); 171 | 172 | Ba = Eba ^ Da; 173 | Be = rol(Ege ^ De, 12); 174 | Bi = rol(Eki ^ Di, 11); 175 | Bo = rol(Emo ^ Do, 21); 176 | Bu = rol(Esu ^ Du, 14); 177 | Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1]; 178 | Abe = Be ^ (~Bi & Bo); 179 | Abi = Bi ^ (~Bo & Bu); 180 | Abo = Bo ^ (~Bu & Ba); 181 | Abu = Bu ^ (~Ba & Be); 182 | 183 | Ba = rol(Ebo ^ Do, 28); 184 | Be = rol(Egu ^ Du, 20); 185 | Bi = rol(Eka ^ Da, 3); 186 | Bo = rol(Eme ^ De, 13); 187 | Bu = rol(Esi ^ Di, 29); 188 | Aga = Ba ^ (~Be & Bi); 189 | Age = Be ^ (~Bi & Bo); 190 | Agi = Bi ^ (~Bo & Bu); 191 | Ago = Bo ^ (~Bu & Ba); 192 | Agu = Bu ^ (~Ba & Be); 193 | 194 | Ba = rol(Ebe ^ De, 1); 195 | Be = rol(Egi ^ Di, 6); 196 | Bi = rol(Eko ^ Do, 25); 197 | Bo = rol(Emu ^ Du, 8); 198 | Bu = rol(Esa ^ Da, 18); 199 | Aka = Ba ^ (~Be & Bi); 200 | Ake = Be ^ (~Bi & Bo); 201 | Aki = Bi ^ (~Bo & Bu); 202 | Ako = Bo ^ (~Bu & Ba); 203 | Aku = Bu ^ (~Ba & Be); 204 | 205 | Ba = rol(Ebu ^ Du, 27); 206 | Be = rol(Ega ^ Da, 4); 207 | Bi = rol(Eke ^ De, 10); 208 | Bo = rol(Emi ^ Di, 15); 209 | Bu = rol(Eso ^ Do, 24); 210 | Ama = Ba ^ (~Be & Bi); 211 | Ame = Be ^ (~Bi & Bo); 212 | Ami = Bi ^ (~Bo & Bu); 213 | Amo = Bo ^ (~Bu & Ba); 214 | Amu = Bu ^ (~Ba & Be); 215 | 216 | Ba = rol(Ebi ^ Di, 30); 217 | Be = rol(Ego ^ Do, 23); 218 | Bi = rol(Eku ^ Du, 7); 219 | Bo = rol(Ema ^ Da, 9); 220 | Bu = rol(Ese ^ De, 2); 221 | Asa = Ba ^ (~Be & Bi); 222 | Ase = Be ^ (~Bi & Bo); 223 | Asi = Bi ^ (~Bo & Bu); 224 | Aso = Bo ^ (~Bu & Ba); 225 | Asu = Bu ^ (~Ba & Be); 226 | } 227 | 228 | state[0] = Aba; 229 | state[1] = Abe; 230 | state[2] = Abi; 231 | state[3] = Abo; 232 | state[4] = Abu; 233 | state[5] = Aga; 234 | state[6] = Age; 235 | state[7] = Agi; 236 | state[8] = Ago; 237 | state[9] = Agu; 238 | state[10] = Aka; 239 | state[11] = Ake; 240 | state[12] = Aki; 241 | state[13] = Ako; 242 | state[14] = Aku; 243 | state[15] = Ama; 244 | state[16] = Ame; 245 | state[17] = Ami; 246 | state[18] = Amo; 247 | state[19] = Amu; 248 | state[20] = Asa; 249 | state[21] = Ase; 250 | state[22] = Asi; 251 | state[23] = Aso; 252 | state[24] = Asu; 253 | } 254 | -------------------------------------------------------------------------------- /lib/keccak/keccakf1600.c: -------------------------------------------------------------------------------- 1 | /* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | * Copyright 2018-2019 Pawel Bylica. 3 | * Licensed under the Apache License, Version 2.0. 4 | */ 5 | 6 | #include 7 | 8 | static uint64_t rol(uint64_t x, unsigned s) 9 | { 10 | return (x << s) | (x >> (64 - s)); 11 | } 12 | 13 | static const uint64_t round_constants[24] = { 14 | 0x0000000000000001, 15 | 0x0000000000008082, 16 | 0x800000000000808a, 17 | 0x8000000080008000, 18 | 0x000000000000808b, 19 | 0x0000000080000001, 20 | 0x8000000080008081, 21 | 0x8000000000008009, 22 | 0x000000000000008a, 23 | 0x0000000000000088, 24 | 0x0000000080008009, 25 | 0x000000008000000a, 26 | 0x000000008000808b, 27 | 0x800000000000008b, 28 | 0x8000000000008089, 29 | 0x8000000000008003, 30 | 0x8000000000008002, 31 | 0x8000000000000080, 32 | 0x000000000000800a, 33 | 0x800000008000000a, 34 | 0x8000000080008081, 35 | 0x8000000000008080, 36 | 0x0000000080000001, 37 | 0x8000000080008008, 38 | }; 39 | 40 | void ethash_keccakf1600(uint64_t state[25]) 41 | { 42 | /* The implementation based on the "simple" implementation by Ronny Van Keer. */ 43 | 44 | int round; 45 | 46 | uint64_t Aba, Abe, Abi, Abo, Abu; 47 | uint64_t Aga, Age, Agi, Ago, Agu; 48 | uint64_t Aka, Ake, Aki, Ako, Aku; 49 | uint64_t Ama, Ame, Ami, Amo, Amu; 50 | uint64_t Asa, Ase, Asi, Aso, Asu; 51 | 52 | uint64_t Eba, Ebe, Ebi, Ebo, Ebu; 53 | uint64_t Ega, Ege, Egi, Ego, Egu; 54 | uint64_t Eka, Eke, Eki, Eko, Eku; 55 | uint64_t Ema, Eme, Emi, Emo, Emu; 56 | uint64_t Esa, Ese, Esi, Eso, Esu; 57 | 58 | uint64_t Ba, Be, Bi, Bo, Bu; 59 | 60 | uint64_t Da, De, Di, Do, Du; 61 | 62 | Aba = state[0]; 63 | Abe = state[1]; 64 | Abi = state[2]; 65 | Abo = state[3]; 66 | Abu = state[4]; 67 | Aga = state[5]; 68 | Age = state[6]; 69 | Agi = state[7]; 70 | Ago = state[8]; 71 | Agu = state[9]; 72 | Aka = state[10]; 73 | Ake = state[11]; 74 | Aki = state[12]; 75 | Ako = state[13]; 76 | Aku = state[14]; 77 | Ama = state[15]; 78 | Ame = state[16]; 79 | Ami = state[17]; 80 | Amo = state[18]; 81 | Amu = state[19]; 82 | Asa = state[20]; 83 | Ase = state[21]; 84 | Asi = state[22]; 85 | Aso = state[23]; 86 | Asu = state[24]; 87 | 88 | for (round = 0; round < 24; round += 2) 89 | { 90 | /* Round (round + 0): Axx -> Exx */ 91 | 92 | Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa; 93 | Be = Abe ^ Age ^ Ake ^ Ame ^ Ase; 94 | Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; 95 | Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; 96 | Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; 97 | 98 | Da = Bu ^ rol(Be, 1); 99 | De = Ba ^ rol(Bi, 1); 100 | Di = Be ^ rol(Bo, 1); 101 | Do = Bi ^ rol(Bu, 1); 102 | Du = Bo ^ rol(Ba, 1); 103 | 104 | Ba = Aba ^ Da; 105 | Be = rol(Age ^ De, 44); 106 | Bi = rol(Aki ^ Di, 43); 107 | Bo = rol(Amo ^ Do, 21); 108 | Bu = rol(Asu ^ Du, 14); 109 | Eba = Ba ^ (~Be & Bi) ^ round_constants[round]; 110 | Ebe = Be ^ (~Bi & Bo); 111 | Ebi = Bi ^ (~Bo & Bu); 112 | Ebo = Bo ^ (~Bu & Ba); 113 | Ebu = Bu ^ (~Ba & Be); 114 | 115 | Ba = rol(Abo ^ Do, 28); 116 | Be = rol(Agu ^ Du, 20); 117 | Bi = rol(Aka ^ Da, 3); 118 | Bo = rol(Ame ^ De, 45); 119 | Bu = rol(Asi ^ Di, 61); 120 | Ega = Ba ^ (~Be & Bi); 121 | Ege = Be ^ (~Bi & Bo); 122 | Egi = Bi ^ (~Bo & Bu); 123 | Ego = Bo ^ (~Bu & Ba); 124 | Egu = Bu ^ (~Ba & Be); 125 | 126 | Ba = rol(Abe ^ De, 1); 127 | Be = rol(Agi ^ Di, 6); 128 | Bi = rol(Ako ^ Do, 25); 129 | Bo = rol(Amu ^ Du, 8); 130 | Bu = rol(Asa ^ Da, 18); 131 | Eka = Ba ^ (~Be & Bi); 132 | Eke = Be ^ (~Bi & Bo); 133 | Eki = Bi ^ (~Bo & Bu); 134 | Eko = Bo ^ (~Bu & Ba); 135 | Eku = Bu ^ (~Ba & Be); 136 | 137 | Ba = rol(Abu ^ Du, 27); 138 | Be = rol(Aga ^ Da, 36); 139 | Bi = rol(Ake ^ De, 10); 140 | Bo = rol(Ami ^ Di, 15); 141 | Bu = rol(Aso ^ Do, 56); 142 | Ema = Ba ^ (~Be & Bi); 143 | Eme = Be ^ (~Bi & Bo); 144 | Emi = Bi ^ (~Bo & Bu); 145 | Emo = Bo ^ (~Bu & Ba); 146 | Emu = Bu ^ (~Ba & Be); 147 | 148 | Ba = rol(Abi ^ Di, 62); 149 | Be = rol(Ago ^ Do, 55); 150 | Bi = rol(Aku ^ Du, 39); 151 | Bo = rol(Ama ^ Da, 41); 152 | Bu = rol(Ase ^ De, 2); 153 | Esa = Ba ^ (~Be & Bi); 154 | Ese = Be ^ (~Bi & Bo); 155 | Esi = Bi ^ (~Bo & Bu); 156 | Eso = Bo ^ (~Bu & Ba); 157 | Esu = Bu ^ (~Ba & Be); 158 | 159 | 160 | /* Round (round + 1): Exx -> Axx */ 161 | 162 | Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa; 163 | Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; 164 | Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; 165 | Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; 166 | Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; 167 | 168 | Da = Bu ^ rol(Be, 1); 169 | De = Ba ^ rol(Bi, 1); 170 | Di = Be ^ rol(Bo, 1); 171 | Do = Bi ^ rol(Bu, 1); 172 | Du = Bo ^ rol(Ba, 1); 173 | 174 | Ba = Eba ^ Da; 175 | Be = rol(Ege ^ De, 44); 176 | Bi = rol(Eki ^ Di, 43); 177 | Bo = rol(Emo ^ Do, 21); 178 | Bu = rol(Esu ^ Du, 14); 179 | Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1]; 180 | Abe = Be ^ (~Bi & Bo); 181 | Abi = Bi ^ (~Bo & Bu); 182 | Abo = Bo ^ (~Bu & Ba); 183 | Abu = Bu ^ (~Ba & Be); 184 | 185 | Ba = rol(Ebo ^ Do, 28); 186 | Be = rol(Egu ^ Du, 20); 187 | Bi = rol(Eka ^ Da, 3); 188 | Bo = rol(Eme ^ De, 45); 189 | Bu = rol(Esi ^ Di, 61); 190 | Aga = Ba ^ (~Be & Bi); 191 | Age = Be ^ (~Bi & Bo); 192 | Agi = Bi ^ (~Bo & Bu); 193 | Ago = Bo ^ (~Bu & Ba); 194 | Agu = Bu ^ (~Ba & Be); 195 | 196 | Ba = rol(Ebe ^ De, 1); 197 | Be = rol(Egi ^ Di, 6); 198 | Bi = rol(Eko ^ Do, 25); 199 | Bo = rol(Emu ^ Du, 8); 200 | Bu = rol(Esa ^ Da, 18); 201 | Aka = Ba ^ (~Be & Bi); 202 | Ake = Be ^ (~Bi & Bo); 203 | Aki = Bi ^ (~Bo & Bu); 204 | Ako = Bo ^ (~Bu & Ba); 205 | Aku = Bu ^ (~Ba & Be); 206 | 207 | Ba = rol(Ebu ^ Du, 27); 208 | Be = rol(Ega ^ Da, 36); 209 | Bi = rol(Eke ^ De, 10); 210 | Bo = rol(Emi ^ Di, 15); 211 | Bu = rol(Eso ^ Do, 56); 212 | Ama = Ba ^ (~Be & Bi); 213 | Ame = Be ^ (~Bi & Bo); 214 | Ami = Bi ^ (~Bo & Bu); 215 | Amo = Bo ^ (~Bu & Ba); 216 | Amu = Bu ^ (~Ba & Be); 217 | 218 | Ba = rol(Ebi ^ Di, 62); 219 | Be = rol(Ego ^ Do, 55); 220 | Bi = rol(Eku ^ Du, 39); 221 | Bo = rol(Ema ^ Da, 41); 222 | Bu = rol(Ese ^ De, 2); 223 | Asa = Ba ^ (~Be & Bi); 224 | Ase = Be ^ (~Bi & Bo); 225 | Asi = Bi ^ (~Bo & Bu); 226 | Aso = Bo ^ (~Bu & Ba); 227 | Asu = Bu ^ (~Ba & Be); 228 | } 229 | 230 | state[0] = Aba; 231 | state[1] = Abe; 232 | state[2] = Abi; 233 | state[3] = Abo; 234 | state[4] = Abu; 235 | state[5] = Aga; 236 | state[6] = Age; 237 | state[7] = Agi; 238 | state[8] = Ago; 239 | state[9] = Agu; 240 | state[10] = Aka; 241 | state[11] = Ake; 242 | state[12] = Aki; 243 | state[13] = Ako; 244 | state[14] = Aku; 245 | state[15] = Ama; 246 | state[16] = Ame; 247 | state[17] = Ami; 248 | state[18] = Amo; 249 | state[19] = Amu; 250 | state[20] = Asa; 251 | state[21] = Ase; 252 | state[22] = Asi; 253 | state[23] = Aso; 254 | state[24] = Asu; 255 | } 256 | -------------------------------------------------------------------------------- /test/fakeminer/fakeminer.cpp: -------------------------------------------------------------------------------- 1 | // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. 2 | // Copyright 2018-2019 Pawel Bylica. 3 | // Licensed under the Apache License, Version 2.0. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | using namespace std::chrono; 18 | using timer = std::chrono::steady_clock; 19 | 20 | namespace 21 | { 22 | class ethash_interface 23 | { 24 | public: 25 | virtual ~ethash_interface() noexcept = default; 26 | 27 | virtual void search(const ethash::hash256& header_hash, uint64_t nonce, size_t iterations) const 28 | noexcept = 0; 29 | }; 30 | 31 | class ethash_light : public ethash_interface 32 | { 33 | const ethash::epoch_context& context; 34 | 35 | public: 36 | explicit ethash_light(int epoch_number) 37 | : context(ethash::get_global_epoch_context(epoch_number)) 38 | {} 39 | 40 | void search(const ethash::hash256& header_hash, uint64_t nonce, size_t iterations) const 41 | noexcept override 42 | { 43 | ethash::search_light(context, header_hash, {}, nonce, iterations); 44 | } 45 | }; 46 | 47 | class ethash_full : public ethash_interface 48 | { 49 | const ethash::epoch_context_full& context; 50 | 51 | public: 52 | explicit ethash_full(int epoch_number) 53 | : context(ethash::get_global_epoch_context_full(epoch_number)) 54 | {} 55 | 56 | void search(const ethash::hash256& header_hash, uint64_t nonce, size_t iterations) const 57 | noexcept override 58 | { 59 | ethash::search(context, header_hash, {}, nonce, iterations); 60 | } 61 | }; 62 | 63 | 64 | std::atomic shared_block_number{0}; 65 | std::atomic num_hashes{0}; 66 | 67 | void worker(bool light, const ethash::hash256& header_hash, uint64_t start_nonce, int batch_size) 68 | { 69 | int current_epoch = -1; 70 | std::unique_ptr ei; 71 | uint64_t i = 0; 72 | size_t w = static_cast(batch_size); 73 | while (true) 74 | { 75 | int block_number = shared_block_number.load(std::memory_order_relaxed); 76 | if (block_number < 0) 77 | break; 78 | 79 | int e = ethash::get_epoch_number(block_number); 80 | 81 | if (current_epoch != e) 82 | { 83 | ei.reset( 84 | light ? static_cast(new ethash_light{e}) : new ethash_full{e}); 85 | current_epoch = e; 86 | } 87 | 88 | ei->search(header_hash, start_nonce + i, w); 89 | num_hashes.fetch_add(batch_size, std::memory_order_relaxed); 90 | i += w; 91 | } 92 | } 93 | } // namespace 94 | 95 | int main(int argc, const char* argv[]) 96 | { 97 | int num_blocks = 10; 98 | int start_block_number = 0; 99 | int block_time = 6; 100 | int work_size = 100; 101 | int num_threads = static_cast(std::thread::hardware_concurrency()); 102 | uint64_t start_nonce = 0; 103 | bool light = false; 104 | 105 | for (int i = 0; i < argc; ++i) 106 | { 107 | const std::string arg{argv[i]}; 108 | 109 | if (arg == "--light") 110 | light = true; 111 | else if (arg == "-i" && i + 1 < argc) 112 | num_blocks = std::stoi(argv[++i]); 113 | else if (arg == "-b" && i + 1 < argc) 114 | start_block_number = std::stoi(argv[++i]); 115 | else if (arg == "-t" && i + 1 < argc) 116 | num_threads = std::stoi(argv[++i]); 117 | else if (arg == "-n" && i + 1 < argc) 118 | start_nonce = std::stoul(argv[++i]); 119 | } 120 | 121 | auto flags = std::cout.flags(); 122 | std::cout << std::fixed << std::setprecision(2); 123 | 124 | // clang-format off 125 | std::cout << "Fakeminer Benchmark\n\nParameters:" 126 | << "\n dataset: " << (light ? "light" : "full") 127 | << "\n threads: " << num_threads 128 | << "\n blocks: " << num_blocks 129 | << "\n block time: " << block_time 130 | << "\n batch size: " << work_size 131 | << "\n start nonce: " << start_nonce 132 | << "\n\n"; 133 | // clang-format on 134 | 135 | const uint64_t divisor = static_cast(num_threads); 136 | const uint64_t nonce_space_per_thread = std::numeric_limits::max() / divisor; 137 | 138 | const ethash::hash256 header_hash{}; 139 | 140 | shared_block_number.store(start_block_number, std::memory_order_relaxed); 141 | std::vector> futures; 142 | 143 | for (int t = 0; t < num_threads; ++t) 144 | { 145 | futures.emplace_back( 146 | std::async(std::launch::async, worker, light, header_hash, start_nonce, work_size)); 147 | start_nonce += nonce_space_per_thread; 148 | } 149 | 150 | std::cout << "Progress:\n" 151 | << " |----- hashrate -----| |----- bandwidth -----|\n" 152 | << " epoch block current average current average\n"; 153 | 154 | int all_hashes = 0; 155 | auto start_time = timer::now(); 156 | auto time = start_time; 157 | static constexpr int khps_mbps_ratio = 158 | ethash::num_dataset_accesses * ethash::full_dataset_item_size / 1024; 159 | 160 | double current_duration = 0; 161 | double all_duration = 0; 162 | double current_khps = 0; 163 | double average_khps = 0; 164 | double current_bandwidth = 0; 165 | double average_bandwidth = 0; 166 | 167 | const milliseconds block_time_ms{block_time * 1000}; 168 | milliseconds sleep_time = block_time_ms; 169 | const int end_block_number = start_block_number + num_blocks; 170 | for (int block_number = start_block_number; block_number < end_block_number; ++block_number) 171 | { 172 | std::this_thread::sleep_for(sleep_time); 173 | int current_hashes = num_hashes.exchange(0, std::memory_order_relaxed); 174 | all_hashes += current_hashes; 175 | 176 | auto now = timer::now(); 177 | current_duration = double(duration_cast(now - time).count()); 178 | all_duration = double(duration_cast(now - start_time).count()); 179 | time = now; 180 | 181 | shared_block_number.store(block_number + 1, std::memory_order_relaxed); 182 | 183 | int e = ethash::get_epoch_number(block_number); 184 | 185 | current_khps = double(current_hashes) / current_duration; 186 | average_khps = double(all_hashes) / all_duration; 187 | current_bandwidth = double(current_hashes * khps_mbps_ratio) / 1024 / current_duration; 188 | average_bandwidth = double(all_hashes * khps_mbps_ratio) / 1024 / all_duration; 189 | 190 | std::cout << std::setw(7) << e << std::setw(9) << block_number << std::setw(10) 191 | << current_khps << " kh/s" << std::setw(9) << average_khps << " kh/s" 192 | << std::setw(10) << current_bandwidth << " GiB/s" << std::setw(8) 193 | << average_bandwidth << " GiB/s\n"; 194 | 195 | sleep_time = block_time_ms - duration_cast(timer::now() - now); 196 | } 197 | 198 | shared_block_number.store(-1, std::memory_order_relaxed); 199 | for (auto& future : futures) 200 | future.wait(); 201 | 202 | auto total_seconds = all_duration / 1000; 203 | 204 | std::cout << "\nSummary:\n time: " << std::setw(7) << total_seconds 205 | << " s\n latest hashrate: " << std::setw(7) << current_khps 206 | << " kh/s\n average hashrate: " << std::setw(7) << average_khps 207 | << " kh/s\n latest memory bandwitdh: " << std::setw(7) << current_bandwidth 208 | << " GiB/s\n average memory bandwitdh: " << std::setw(7) << average_bandwidth 209 | << " GiB/s\n"; 210 | 211 | std::cout.flags(flags); 212 | return 0; 213 | } 214 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | executors: 4 | linux: 5 | docker: 6 | - image: ethereum/cpp-build-env:11 7 | 8 | defaults: 9 | 10 | environment-info: &environment-info 11 | run: 12 | name: "Environment info" 13 | command: | 14 | echo CXX: $CXX 15 | $CXX --version 16 | $CXX --version > compiler.version 17 | 18 | update-submodules: &update-submodules 19 | run: 20 | name: "Update git submodules" 21 | command: | 22 | git submodule update --init --recursive 23 | 24 | install-m32: &install-m32 25 | run: 26 | name: "Install 32-bit toolchain" 27 | command: | 28 | sudo apt -q update 29 | sudo apt -qy install g++-multilib 30 | 31 | install-mips64: &install-mips64 32 | run: 33 | name: "Install mips64 toolchain" 34 | command: | 35 | sudo apt -q update 36 | sudo apt -qy install g++-mips64-linux-gnuabi64 qemu-user-static 37 | 38 | install-powerpc64: &install-powerpc64 39 | run: 40 | name: "Install powerpc64 toolchain" 41 | command: | 42 | sudo apt -q update 43 | sudo apt -qy install g++-powerpc64-linux-gnu qemu-user-static 44 | 45 | configure: &configure 46 | run: 47 | name: "Configure" 48 | # Build "out-of-source" to have better coverage report 49 | # (ninja is using relative paths otherwise). 50 | working_directory: ~/build 51 | command: | 52 | cmake ../project -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=/tmp/local $CMAKE_OPTIONS 53 | 54 | build: &build 55 | run: 56 | name: "Build" 57 | working_directory: ~/build 58 | command: | 59 | cmake --build . -- -j $BUILD_PARALLEL_JOBS 60 | cmake --build . --target install 61 | 62 | build-tests: &build-tests 63 | run: 64 | name: "Build ethash-test" 65 | working_directory: ~/build 66 | command: | 67 | cmake --build . --target ethash-test -- -j $BUILD_PARALLEL_JOBS 68 | 69 | test: &test 70 | run: 71 | name: "Test" 72 | working_directory: ~/build 73 | command: | 74 | if [ -z "$GTEST_FILTER" ]; then 75 | test/ethash-test 76 | else 77 | test/ethash-test --gtest_filter=$GTEST_FILTER 78 | fi 79 | 80 | test-cmake-config: &test-cmake-config 81 | run: 82 | name: "Test CMake config" 83 | working_directory: ~/project/test/integration/cmake-config 84 | command: | 85 | cmake -DCMAKE_PREFIX_PATH=/tmp/local . 86 | cmake --build . 87 | ./ethash-cmake-config-test 88 | 89 | test-mips64: &test-mips64 90 | run: 91 | name: "Test (mips64)" 92 | working_directory: ~/build 93 | command: | 94 | qemu-mips64 -L /usr/mips64-linux-gnuabi64 test/ethash-test 95 | 96 | benchmark: &benchmark 97 | run: 98 | name: "Benchmark" 99 | working_directory: ~/build 100 | command: | 101 | test/ethash-bench 102 | 103 | upload-coverage-data: &upload-coverage-data 104 | run: 105 | name: "Upload coverage data" 106 | command: | 107 | codecov --required --gcov-exec "$GCOV" --gcov-root ~/build 108 | 109 | 110 | macos-defaults: &macos-defaults 111 | environment: 112 | - BUILD_PARALLEL_JOBS: 2 113 | steps: 114 | - run: 115 | name: "Install CMake" 116 | command: | 117 | HOMEBREW_NO_AUTO_UPDATE=1 brew install -q cmake ninja 118 | - run: 119 | name: "Install Python3" 120 | # Python3 and requests are needed for Hunter upload. 121 | command: | 122 | export HOMEBREW_NO_AUTO_UPDATE=1 123 | if ! brew install -q python3; then 124 | brew upgrade -q python 125 | fi 126 | pip3 install -q requests 127 | - checkout 128 | - *configure 129 | - *build 130 | - *test 131 | 132 | 133 | jobs: 134 | 135 | linux-gcc-coverage: 136 | environment: 137 | - CXX: g++-8 138 | - CC: gcc-8 139 | - GCOV: gcov-8 140 | - BUILD_PARALLEL_JOBS: 2 141 | - BUILD_TYPE: Debug 142 | - CMAKE_OPTIONS: -DCOVERAGE=ON 143 | executor: linux 144 | steps: 145 | - checkout 146 | - *configure 147 | - *build 148 | - *test 149 | - *upload-coverage-data 150 | 151 | linux-clang-ubsan: 152 | environment: 153 | - CXX: clang++-8 154 | - CC: clang-8 155 | - BUILD_PARALLEL_JOBS: 2 156 | - CMAKE_OPTIONS: -DSANITIZE=undefined,integer,nullability 157 | - UBSAN_OPTIONS: halt_on_error=1 158 | executor: linux 159 | steps: 160 | - checkout 161 | - *configure 162 | - *build 163 | - *test 164 | - *benchmark 165 | 166 | linux-clang-asan: 167 | environment: 168 | - CXX: clang++-8 169 | - CC: clang-8 170 | - BUILD_PARALLEL_JOBS: 2 171 | - CMAKE_OPTIONS: -DSANITIZE=address 172 | - ASAN_OPTIONS: allocator_may_return_null=1 173 | executor: linux 174 | steps: 175 | - checkout 176 | - *configure 177 | - *build 178 | - *test 179 | - *benchmark 180 | 181 | linux-32bit-asan: 182 | environment: 183 | - BUILD_PARALLEL_JOBS: 2 184 | - CMAKE_OPTIONS: -DTOOLCHAIN=cxx11-32bit 185 | - CMAKE_OPTIONS: -DSANITIZE=address 186 | - GTEST_FILTER: -*_oom 187 | executor: linux 188 | steps: 189 | - checkout 190 | - *install-m32 191 | - *configure 192 | - *build 193 | - *test 194 | 195 | linux-32bit-ubsan: 196 | environment: 197 | - BUILD_PARALLEL_JOBS: 2 198 | - CMAKE_OPTIONS: -DTOOLCHAIN=cxx11-32bit 199 | - CMAKE_OPTIONS: -DSANITIZE=undefined 200 | - UBSAN_OPTIONS: halt_on_error=1 201 | executor: linux 202 | steps: 203 | - checkout 204 | - *install-m32 205 | - *configure 206 | - *build 207 | - *test 208 | 209 | mips64: 210 | environment: 211 | - BUILD_PARALLEL_JOBS: 2 212 | - TEST_PARALLEL_JOBS: 2 213 | - CMAKE_OPTIONS: -DTOOLCHAIN=mips64 -DCMAKE_EXE_LINKER_FLAGS=-static 214 | executor: linux 215 | steps: 216 | - checkout 217 | - *install-mips64 218 | - *configure 219 | - *build-tests 220 | - store_artifacts: 221 | path: ~/build/test/ethash-test 222 | destination: ethash-test 223 | - run: 224 | name: "Test mips64" 225 | working_directory: ~/build 226 | command: | # Software emulation in qemu will not handle threads. 227 | qemu-mips64-static test/ethash-test --gtest_filter='-*_multithreaded.*' 228 | 229 | powerpc64: 230 | environment: 231 | - BUILD_PARALLEL_JOBS: 2 232 | - TEST_PARALLEL_JOBS: 2 233 | - CMAKE_OPTIONS: -DTOOLCHAIN=powerpc64 -DCMAKE_EXE_LINKER_FLAGS=-static 234 | executor: linux 235 | steps: 236 | - checkout 237 | - *install-powerpc64 238 | - *configure 239 | - *build-tests 240 | - store_artifacts: 241 | path: ~/build/test/ethash-test 242 | destination: ethash-test 243 | - run: 244 | name: "Test powerpc64" 245 | working_directory: ~/build 246 | command: | # Software emulation in qemu will not handle threads. 247 | qemu-ppc64-static test/ethash-test --gtest_filter='-*_multithreaded.*' 248 | 249 | linux-release: 250 | environment: 251 | - CXX: clang++-8 252 | - CC: clang-8 253 | - BUILD_PARALLEL_JOBS: 4 254 | - CMAKE_OPTIONS: -DETHASH_BUILD_TESTS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DHUNTER_ENABLED=OFF 255 | docker: 256 | - image: ethereum/cpp-build-env:9 257 | steps: 258 | - checkout 259 | - *configure 260 | - *build 261 | - persist_to_workspace: 262 | root: /tmp/local 263 | paths: 264 | - "*" 265 | 266 | linux-release-python: 267 | docker: 268 | - image: quay.io/pypa/manylinux1_x86_64 269 | steps: 270 | - checkout 271 | - attach_workspace: 272 | at: ~/project/dist 273 | - run: 274 | name: "Build wheels" 275 | command: sh scripts/ci/python_build_wheels.sh 276 | - run: 277 | name: "Tag wheels" 278 | working_directory: ~/project/dist 279 | command: | 280 | find -name '*linux_x86_64.whl' -exec auditwheel repair {} \; 281 | - store_artifacts: 282 | path: ~/project/dist 283 | destination: dist 284 | - run: 285 | name: "Install CMake" 286 | command: | 287 | export PATH=/opt/python/cp37-cp37m/bin:$PATH 288 | pip install cmake 289 | - run: 290 | name: "Build source dist" 291 | command: | 292 | export PATH=/opt/python/cp37-cp37m/bin:$PATH 293 | ./setup.py sdist 294 | - run: 295 | name: "Build wheel with CMake build" 296 | command: | 297 | export PATH=/opt/python/cp37-cp37m/bin:$PATH 298 | ./setup.py bdist_wheel 299 | - run: 300 | name: "Test" 301 | command: | 302 | export PATH=/opt/python/cp37-cp37m/bin:$PATH 303 | ./setup.py test 304 | 305 | macos-xcode-tsan: 306 | <<: *macos-defaults 307 | environment: 308 | - BUILD_PARALLEL_JOBS: 2 309 | - CMAKE_OPTIONS: -DSANITIZE=thread 310 | - TSAN_OPTIONS: allocator_may_return_null=1 311 | macos: 312 | xcode: "10.0.0" 313 | 314 | macos-xcode83: 315 | <<: *macos-defaults 316 | macos: 317 | xcode: "8.3.3" 318 | 319 | macos-release: 320 | environment: 321 | - BUILD_PARALLEL_JOBS: 4 322 | - CMAKE_OPTIONS: -DETHASH_BUILD_TESTS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=~/project/dist 323 | macos: 324 | xcode: "10.2.1" 325 | steps: 326 | - run: 327 | name: "Install CMake" 328 | command: | 329 | which python3 330 | ls -l /usr/local/lib 331 | ls -l /usr/local/bin 332 | pip3 install cmake 333 | - checkout 334 | - *configure 335 | - *build 336 | - run: 337 | name: "Test" 338 | command: | 339 | ./setup.py test 340 | - run: 341 | name: "Build wheels" 342 | command: sh scripts/ci/python_build_wheels.sh 343 | - store_artifacts: 344 | path: ~/project/dist 345 | destination: dist 346 | 347 | 348 | workflows: 349 | version: 2 350 | ethash: 351 | jobs: 352 | - linux-gcc-coverage 353 | - linux-clang-ubsan 354 | - linux-clang-asan 355 | - linux-32bit-asan 356 | - linux-32bit-ubsan 357 | - mips64 358 | - powerpc64 359 | - macos-xcode-tsan 360 | - macos-xcode83 361 | - linux-release 362 | - linux-release-python: 363 | requires: 364 | - linux-release 365 | - macos-release 366 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------