Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Optimize Keccak implementation and remove Crypto++ dependency #47

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ project(ethash)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
set(ETHHASH_LIBS ethash)

if (WIN32 AND WANT_CRYPTOPP)
add_subdirectory(cryptopp)
endif()

add_subdirectory(src/libethash)
# bin2h.cmake doesn't work
if (NOT OpenCL_FOUND)
Expand Down
6 changes: 3 additions & 3 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
include setup.py

# C sources
# C/C++ sources
include src/libethash/internal.c
include src/libethash/sha3.c
include src/libethash/keccak.cpp
include src/libethash/util.c
include src/python/core.c

Expand All @@ -13,5 +13,5 @@ include src/libethash/endian.h
include src/libethash/ethash.h
include src/libethash/fnv.h
include src/libethash/internal.h
include src/libethash/sha3.h
include src/libethash/keccak.h
include src/libethash/util.h
13 changes: 0 additions & 13 deletions cryptopp/CMakeLists.txt

This file was deleted.

6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'src/python/core.c',
'src/libethash/io.c',
'src/libethash/internal.c',
'src/libethash/sha3.c']
'src/libethash/keccak.cpp']
if os.name == 'nt':
sources += [
'src/libethash/util.c',
Expand All @@ -25,13 +25,13 @@
'src/libethash/io.h',
'src/libethash/fnv.h',
'src/libethash/internal.h',
'src/libethash/sha3.h',
'src/libethash/keccak.h',
'src/libethash/util.h',
]
pyethash = Extension('pyethash',
sources=sources,
depends=depends,
extra_compile_args=["-Isrc/", "-std=gnu99", "-Wall"])
extra_compile_args=["-Isrc/", "-std=gnu99", "-std=c++11", "-Wall"])

setup(
name='pyethash',
Expand Down
11 changes: 2 additions & 9 deletions src/benchmark/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,7 @@
#endif
#include <vector>
#include <algorithm>

#ifdef WITH_CRYPTOPP
#include <libethash/sha3_cryptopp.h>
#include <string>

#else
#include "libethash/sha3.h"
#endif // WITH_CRYPTOPP
#include <libethash/keccak.h>

#undef min
#undef max
Expand Down Expand Up @@ -135,7 +128,7 @@ extern "C" int main(void)
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - startTime).count();

ethash_h256_t cache_hash;
SHA3_256(&cache_hash, (uint8_t const*)cache_mem, params.cache_size);
keccak256(&cache_hash, (uint8_t const*)cache_mem, params.cache_size);
debugf("ethash_mkcache: %ums, sha3: %s\n", (unsigned)((time*1000)/CLOCKS_PER_SEC), bytesToHexString(&cache_hash, sizeof(cache_hash)).data());

// print a couple of test hashes
Expand Down
14 changes: 2 additions & 12 deletions src/libethash/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ set(CMAKE_BUILD_TYPE Release)

if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()

set(FILES util.h
keccak.h keccak.cpp
io.c
internal.c
ethash.h
Expand All @@ -25,18 +27,6 @@ else()
list(APPEND FILES io_posix.c)
endif()

if (NOT CRYPTOPP_FOUND)
find_package(CryptoPP 5.6.2)
endif()

if (CRYPTOPP_FOUND)
add_definitions(-DWITH_CRYPTOPP)
include_directories( ${CRYPTOPP_INCLUDE_DIRS} )
list(APPEND FILES sha3_cryptopp.cpp sha3_cryptopp.h)
else()
list(APPEND FILES sha3.c sha3.h)
endif()

add_library(${LIBRARY} ${FILES})

if (CRYPTOPP_FOUND)
Expand Down
29 changes: 11 additions & 18 deletions src/libethash/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,7 @@
#include "internal.h"
#include "data_sizes.h"
#include "io.h"

#ifdef WITH_CRYPTOPP

#include "sha3_cryptopp.h"

#else
#include "sha3.h"
#endif // WITH_CRYPTOPP
#include "keccak.h"

uint64_t ethash_get_datasize(uint32_t const block_number)
{
Expand Down Expand Up @@ -67,10 +60,10 @@ bool static ethash_compute_cache_nodes(
}
uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node));

SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32);
keccak512(nodes[0].bytes, (uint8_t*)seed, 32);

for (unsigned i = 1; i != num_nodes; ++i) {
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
keccak512(nodes[i].bytes, nodes[i - 1].bytes, 64);
}

for (unsigned j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
Expand All @@ -81,7 +74,7 @@ bool static ethash_compute_cache_nodes(
for (unsigned w = 0; w != NODE_WORDS; ++w) {
data.words[w] ^= nodes[idx].words[w];
}
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
keccak512(nodes[i].bytes, data.bytes, sizeof(data));
}
}

Expand Down Expand Up @@ -133,7 +126,7 @@ void ethash_calculate_dag_item(
node const* init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
keccak512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = ret->xmm[0];
Expand Down Expand Up @@ -171,7 +164,7 @@ void ethash_calculate_dag_item(
}
#endif
}
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
keccak512(ret->bytes, ret->bytes, sizeof(node));
}

bool ethash_compute_full_data(
Expand Down Expand Up @@ -213,7 +206,7 @@ static bool ethash_hash(
fix_endian64(s_mix[0].double_words[4], nonce);

// compute sha3-512 hash and replicate across mix
SHA3_512(s_mix->bytes, s_mix->bytes, 40);
keccak512(s_mix->bytes, s_mix->bytes, 40);
fix_endian_arr32(s_mix[0].words, 16);

node* const mix = s_mix + 1;
Expand Down Expand Up @@ -279,7 +272,7 @@ static bool ethash_hash(
fix_endian_arr32(mix->words, MIX_WORDS / 4);
memcpy(&ret->mix_hash, mix->bytes, 32);
// final Keccak hash
SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
keccak256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
return true;
}

Expand All @@ -294,17 +287,17 @@ void ethash_quick_hash(
memcpy(buf, header_hash, 32);
fix_endian64_same(nonce);
memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40);
keccak512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64 + 32);
keccak256(return_hash, buf, 64 + 32);
}

void ethash_get_seedhash(ethash_h256_t* seedhash, const uint32_t block_number)
{
ethash_h256_reset(seedhash);
const uint32_t epochs = block_number / ETHASH_EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(seedhash, (uint8_t*)seedhash, 32);
keccak256(seedhash, (uint8_t*)seedhash, 32);
}

int ethash_quick_check_difficulty(
Expand Down
121 changes: 121 additions & 0 deletions src/libethash/keccak.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@

/*
Core Keccack implementation devided from https://github.com/coruus/keccak-tiny by David Leon Gil
*/

#include "keccak.h"

#include <cstring>

namespace
{
uint8_t const rho[] = { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 };
uint8_t const pi[] = { 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 };
uint64_t const RC[] = { 1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};

inline uint64_t rot(uint64_t x, uint64_t s) { return x << s | x >> (64 - s); }

#define REPEAT6(e) e e e e e e
#define REPEAT24(e) REPEAT6(e e e e)
#define REPEAT5(e) e e e e e
#define FOR5(v, s, e) v = 0; REPEAT5(e; v += s;)

/// Keccak-f[1600]
inline void keccakf1600(uint64_t* a)
{
uint64_t b[5] = {0};
uint64_t t = 0;
uint8_t x, y;

for (size_t i = 0; i < 24; ++i)
{
// Round[1600](a,RC):
// theta step:
FOR5(x, 1,
b[x] = 0;
FOR5(y, 5,
b[x] ^= a[x + y]; ))
FOR5(x, 1,
FOR5(y, 5,
a[y + x] ^= b[(x + 4) % 5] ^ rot(b[(x + 1) % 5], 1); ))

// rho and pi steps
t = a[1];
x = 0;
REPEAT24(b[0] = a[pi[x]];
a[pi[x]] = rot(t, rho[x]);
t = b[0];
x++; )
// chi step
FOR5(y,
5,
FOR5(x, 1,
b[x] = a[y + x];)
FOR5(x, 1,
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
// iota step
a[0] ^= RC[i];
}
}

inline void xorin(uint64_t* dst, const uint64_t* src, size_t size)
{
for (size_t i = 0; i < size; ++i)
dst[i] ^= src[i];
}

inline void keccak(uint64_t* out, size_t outSize, const uint64_t* data, size_t size)
{
static const size_t stateSize = 200;
const auto r = stateSize - (2 * outSize); // 256: 136, 512: 72
uint64_t a[stateSize / 8] = {0};
// Absorb input.
while (size >= r)
{
xorin(a, data, r / 8);
keccakf1600(a);
data += r / 8;
size -= r;
}
// Xor in the DS and pad frame.
a[size / 8] ^= 0x01; // 0x01: Keccak, 0x06: SHA3
a[(r - 1) / 8] ^= 0x8000000000000000;
// Xor in the last block.
xorin(a, data, size / 8);
keccakf1600(a);
std::memcpy(out, a, outSize); // TODO: How about using out as a state
}
}

extern "C"
{

void keccak256(ethash_h256_t* out, uint8_t const* data, size_t size)
{
// FIXME: What with unaligned memory?
keccak((uint64_t*)out, 32, (uint64_t*)data, size);
}

void keccak512(uint8_t* out, uint8_t const* data, size_t size)
{
keccak((uint64_t*)out, 64, (uint64_t*)data, size);
}

void keccak256_96(ethash_h256_t* out, uint8_t const* data)
{
keccak((uint64_t*)out, 32, (uint64_t*)data, 96 / 8);
}

void keccak512_40(uint8_t* out, uint8_t const* data)
{
keccak((uint64_t*)out, 64, (uint64_t*)data, 40 / 8);
}

} // extern "C"
23 changes: 23 additions & 0 deletions src/libethash/keccak.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <stdint.h>
#include <stddef.h>

struct ethash_h256;
typedef struct ethash_h256 ethash_h256_t;

#ifdef __cplusplus
extern "C" {
#endif

void keccak256(ethash_h256_t* out, uint8_t const* data, size_t size);

void keccak512(uint8_t* out, uint8_t const* data, size_t size);

void keccak256_96(ethash_h256_t* out, uint8_t const* data);

void keccak512_40(uint8_t* out, uint8_t const* data);

#ifdef __cplusplus
}
#endif
Loading