Browse Source

Implementation of VerusHash CPU-friendly hash algorithm, parameters to enable it, miner, and all changes required to support it on new asset chains

pull/4/head
miketout 6 years ago
parent
commit
42181656c2
  1. 4
      .gitignore
  2. 21
      src/Makefile.am
  3. 2
      src/Makefile.gtest.include
  4. 2
      src/Makefile.qt.include
  5. 2
      src/Makefile.qttest.include
  6. 2
      src/Makefile.test.include
  7. 1
      src/Makefile.zcash.include
  8. 574
      src/crypto/haraka.c
  9. 111
      src/crypto/haraka.h
  10. 75
      src/crypto/verus_hash.cpp
  11. 54
      src/crypto/verus_hash.h
  12. 41
      src/hash.h
  13. 6
      src/init.cpp
  14. 13
      src/komodo_globals.h
  15. 27
      src/komodo_utils.h
  16. 231
      src/miner.cpp
  17. 6
      src/pow.cpp
  18. 24
      src/primitives/block.cpp
  19. 15
      src/primitives/block.h
  20. 5
      src/util.cpp

4
.gitignore

@ -116,3 +116,7 @@ contrib/debian/files
contrib/debian/substvars
src/rpcmisc~.cpp
src/komodod
src/genVERUSTEST
src/komodo-cli
src/komodo-tx

21
src/Makefile.am

@ -41,6 +41,7 @@ LIBBITCOIN_COMMON=libbitcoin_common.a
LIBBITCOIN_CLI=libbitcoin_cli.a
LIBBITCOIN_UTIL=libbitcoin_util.a
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
LIBVERUS_CRYPTO=crypto/libverus_crypto.a
LIBSECP256K1=secp256k1/libsecp256k1.la
LIBSNARK=snark/libsnark.a
LIBUNIVALUE=univalue/libunivalue.la
@ -68,6 +69,7 @@ $(LIBUNIVALUE): $(wildcard univalue/lib/*)
# But to build the less dependent modules first, we manually select their order here:
EXTRA_LIBRARIES = \
crypto/libbitcoin_crypto.a \
crypto/libverus_crypto.a \
libbitcoin_util.a \
libbitcoin_common.a \
libbitcoin_server.a \
@ -151,6 +153,7 @@ BITCOIN_CORE_H = \
core_io.h \
core_memusage.h \
deprecation.h \
haraka.h \
hash.h \
httprpc.h \
httpserver.h \
@ -341,7 +344,9 @@ crypto_libbitcoin_crypto_a_SOURCES = \
crypto/sha256.cpp \
crypto/sha256.h \
crypto/sha512.cpp \
crypto/sha512.h
crypto/sha512.h \
crypto/verus_hash.h \
crypto/verus_hash.cpp
if ENABLE_MINING
EQUIHASH_TROMP_SOURCES = \
@ -355,9 +360,16 @@ crypto_libbitcoin_crypto_a_SOURCES += \
${EQUIHASH_TROMP_SOURCES}
endif
# Verus hash specific library
crypto_libverus_crypto_a_CPPFLAGS = -O0 -Wint-conversion -march=native -funroll-loops -fomit-frame-pointer -fPIC $(AM_CPPFLAGS)
crypto_libverus_crypto_a_CXXFLAGS = -O0 -Wint-conversion -march=native -funroll-loops -fomit-frame-pointer -fPIC $(AM_CXXFLAGS)
crypto_libverus_crypto_a_SOURCES = \
crypto/haraka.h \
crypto/haraka.c
# common: shared between zcashd and non-server tools
libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_CPPFLAGS = -fPIC $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_common_a_CXXFLAGS = -fPIC $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
amount.cpp \
arith_uint256.cpp \
@ -441,6 +453,7 @@ komodod_LDADD = \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBZCASH) \
$(LIBSNARK) \
$(LIBLEVELDB) \
@ -463,6 +476,7 @@ komodod_LDADD += \
$(EVENT_PTHREADS_LIBS) \
$(EVENT_LIBS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBZCASH_LIBS)
if ENABLE_PROTON
@ -512,6 +526,7 @@ komodo_tx_LDADD = \
$(LIBZCASH) \
$(LIBSNARK) \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBZCASH_LIBS)
komodo_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)

2
src/Makefile.gtest.include

@ -49,7 +49,7 @@ endif
komodo_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
komodo_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
komodo_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
komodo_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
if ENABLE_ZMQ
zcash_gtest_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)

2
src/Makefile.qt.include

@ -361,7 +361,7 @@ qt_komodo_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
if ENABLE_WALLET
qt_komodo_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
qt_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS)
qt_komodo_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_komodo_qt_LIBTOOLFLAGS = --tag CXX

2
src/Makefile.qttest.include

@ -30,7 +30,7 @@ qt_test_test_komodo_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
if ENABLE_WALLET
qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS)
qt_test_test_komodo_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)

2
src/Makefile.test.include

@ -100,7 +100,7 @@ endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET

1
src/Makefile.zcash.include

@ -24,5 +24,6 @@ zcash_CreateJoinSplit_LDADD = \
$(LIBSNARK) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(BOOST_LIBS) \
$(LIBZCASH_LIBS)

574
src/crypto/haraka.c

@ -0,0 +1,574 @@
/*
The MIT License (MIT)
Copyright (c) 2016 kste
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Optimized Implementations for Haraka256 and Haraka512
*/
#include <stdio.h>
#include "crypto/haraka.h"
u128 rc[40];
void load_constants() {
rc[0] = _mm_set_epi32(0x0684704c,0xe620c00a,0xb2c5fef0,0x75817b9d);
rc[1] = _mm_set_epi32(0x8b66b4e1,0x88f3a06b,0x640f6ba4,0x2f08f717);
rc[2] = _mm_set_epi32(0x3402de2d,0x53f28498,0xcf029d60,0x9f029114);
rc[3] = _mm_set_epi32(0x0ed6eae6,0x2e7b4f08,0xbbf3bcaf,0xfd5b4f79);
rc[4] = _mm_set_epi32(0xcbcfb0cb,0x4872448b,0x79eecd1c,0xbe397044);
rc[5] = _mm_set_epi32(0x7eeacdee,0x6e9032b7,0x8d5335ed,0x2b8a057b);
rc[6] = _mm_set_epi32(0x67c28f43,0x5e2e7cd0,0xe2412761,0xda4fef1b);
rc[7] = _mm_set_epi32(0x2924d9b0,0xafcacc07,0x675ffde2,0x1fc70b3b);
rc[8] = _mm_set_epi32(0xab4d63f1,0xe6867fe9,0xecdb8fca,0xb9d465ee);
rc[9] = _mm_set_epi32(0x1c30bf84,0xd4b7cd64,0x5b2a404f,0xad037e33);
rc[10] = _mm_set_epi32(0xb2cc0bb9,0x941723bf,0x69028b2e,0x8df69800);
rc[11] = _mm_set_epi32(0xfa0478a6,0xde6f5572,0x4aaa9ec8,0x5c9d2d8a);
rc[12] = _mm_set_epi32(0xdfb49f2b,0x6b772a12,0x0efa4f2e,0x29129fd4);
rc[13] = _mm_set_epi32(0x1ea10344,0xf449a236,0x32d611ae,0xbb6a12ee);
rc[14] = _mm_set_epi32(0xaf044988,0x4b050084,0x5f9600c9,0x9ca8eca6);
rc[15] = _mm_set_epi32(0x21025ed8,0x9d199c4f,0x78a2c7e3,0x27e593ec);
rc[16] = _mm_set_epi32(0xbf3aaaf8,0xa759c9b7,0xb9282ecd,0x82d40173);
rc[17] = _mm_set_epi32(0x6260700d,0x6186b017,0x37f2efd9,0x10307d6b);
rc[18] = _mm_set_epi32(0x5aca45c2,0x21300443,0x81c29153,0xf6fc9ac6);
rc[19] = _mm_set_epi32(0x9223973c,0x226b68bb,0x2caf92e8,0x36d1943a);
rc[20] = _mm_set_epi32(0xd3bf9238,0x225886eb,0x6cbab958,0xe51071b4);
rc[21] = _mm_set_epi32(0xdb863ce5,0xaef0c677,0x933dfddd,0x24e1128d);
rc[22] = _mm_set_epi32(0xbb606268,0xffeba09c,0x83e48de3,0xcb2212b1);
rc[23] = _mm_set_epi32(0x734bd3dc,0xe2e4d19c,0x2db91a4e,0xc72bf77d);
rc[24] = _mm_set_epi32(0x43bb47c3,0x61301b43,0x4b1415c4,0x2cb3924e);
rc[25] = _mm_set_epi32(0xdba775a8,0xe707eff6,0x03b231dd,0x16eb6899);
rc[26] = _mm_set_epi32(0x6df3614b,0x3c755977,0x8e5e2302,0x7eca472c);
rc[27] = _mm_set_epi32(0xcda75a17,0xd6de7d77,0x6d1be5b9,0xb88617f9);
rc[28] = _mm_set_epi32(0xec6b43f0,0x6ba8e9aa,0x9d6c069d,0xa946ee5d);
rc[29] = _mm_set_epi32(0xcb1e6950,0xf957332b,0xa2531159,0x3bf327c1);
rc[30] = _mm_set_epi32(0x2cee0c75,0x00da619c,0xe4ed0353,0x600ed0d9);
rc[31] = _mm_set_epi32(0xf0b1a5a1,0x96e90cab,0x80bbbabc,0x63a4a350);
rc[32] = _mm_set_epi32(0xae3db102,0x5e962988,0xab0dde30,0x938dca39);
rc[33] = _mm_set_epi32(0x17bb8f38,0xd554a40b,0x8814f3a8,0x2e75b442);
rc[34] = _mm_set_epi32(0x34bb8a5b,0x5f427fd7,0xaeb6b779,0x360a16f6);
rc[35] = _mm_set_epi32(0x26f65241,0xcbe55438,0x43ce5918,0xffbaafde);
rc[36] = _mm_set_epi32(0x4ce99a54,0xb9f3026a,0xa2ca9cf7,0x839ec978);
rc[37] = _mm_set_epi32(0xae51a51a,0x1bdff7be,0x40c06e28,0x22901235);
rc[38] = _mm_set_epi32(0xa0c1613c,0xba7ed22b,0xc173bc0f,0x48a659cf);
rc[39] = _mm_set_epi32(0x756acc03,0x02288288,0x4ad6bdfd,0xe9c59da1);
}
void test_implementations() {
unsigned char *in = (unsigned char *)calloc(64*8, sizeof(unsigned char));
unsigned char *out256 = (unsigned char *)calloc(32*8, sizeof(unsigned char));
unsigned char *out512 = (unsigned char *)calloc(32*8, sizeof(unsigned char));
unsigned char testvector256[32] = {0x80, 0x27, 0xcc, 0xb8, 0x79, 0x49, 0x77, 0x4b,
0x78, 0xd0, 0x54, 0x5f, 0xb7, 0x2b, 0xf7, 0x0c,
0x69, 0x5c, 0x2a, 0x09, 0x23, 0xcb, 0xd4, 0x7b,
0xba, 0x11, 0x59, 0xef, 0xbf, 0x2b, 0x2c, 0x1c};
unsigned char testvector512[32] = {0xbe, 0x7f, 0x72, 0x3b, 0x4e, 0x80, 0xa9, 0x98,
0x13, 0xb2, 0x92, 0x28, 0x7f, 0x30, 0x6f, 0x62,
0x5a, 0x6d, 0x57, 0x33, 0x1c, 0xae, 0x5f, 0x34,
0xdd, 0x92, 0x77, 0xb0, 0x94, 0x5b, 0xe2, 0xaa};
int i;
// Input for testvector
for(i = 0; i < 512; i++) {
in[i] = i % 64;
}
load_constants();
haraka512_8x(out512, in);
// Verify output
for(i = 0; i < 32; i++) {
if (out512[i % 32] != testvector512[i]) {
printf("Error: testvector incorrect.\n");
return;
}
}
free(in);
free(out256);
free(out512);
}
void haraka256(unsigned char *out, const unsigned char *in) {
__m128i s[2], tmp;
s[0] = LOAD(in);
s[1] = LOAD(in + 16);
AES2(s[0], s[1], 0);
MIX2(s[0], s[1]);
AES2(s[0], s[1], 4);
MIX2(s[0], s[1]);
AES2(s[0], s[1], 8);
MIX2(s[0], s[1]);
AES2(s[0], s[1], 12);
MIX2(s[0], s[1]);
AES2(s[0], s[1], 16);
MIX2(s[0], s[1]);
s[0] = _mm_xor_si128(s[0], LOAD(in));
s[1] = _mm_xor_si128(s[1], LOAD(in + 16));
STORE(out, s[0]);
STORE(out + 16, s[1]);
}
void haraka256_4x(unsigned char *out, const unsigned char *in) {
__m128i s[4][2], tmp;
s[0][0] = LOAD(in);
s[0][1] = LOAD(in + 16);
s[1][0] = LOAD(in + 32);
s[1][1] = LOAD(in + 48);
s[2][0] = LOAD(in + 64);
s[2][1] = LOAD(in + 80);
s[3][0] = LOAD(in + 96);
s[3][1] = LOAD(in + 112);
// Round 1
AES2_4x(s[0], s[1], s[2], s[3], 0);
MIX2(s[0][0], s[0][1]);
MIX2(s[1][0], s[1][1]);
MIX2(s[2][0], s[2][1]);
MIX2(s[3][0], s[3][1]);
// Round 2
AES2_4x(s[0], s[1], s[2], s[3], 4);
MIX2(s[0][0], s[0][1]);
MIX2(s[1][0], s[1][1]);
MIX2(s[2][0], s[2][1]);
MIX2(s[3][0], s[3][1]);
// Round 3
AES2_4x(s[0], s[1], s[2], s[3], 8);
MIX2(s[0][0], s[0][1]);
MIX2(s[1][0], s[1][1]);
MIX2(s[2][0], s[2][1]);
MIX2(s[3][0], s[3][1]);
// Round 4
AES2_4x(s[0], s[1], s[2], s[3], 12);
MIX2(s[0][0], s[0][1]);
MIX2(s[1][0], s[1][1]);
MIX2(s[2][0], s[2][1]);
MIX2(s[3][0], s[3][1]);
// Round 5
AES2_4x(s[0], s[1], s[2], s[3], 16);
MIX2(s[0][0], s[0][1]);
MIX2(s[1][0], s[1][1]);
MIX2(s[2][0], s[2][1]);
MIX2(s[3][0], s[3][1]);
// Feed Forward
s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));
s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));
s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32));
s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48));
s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64));
s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80));
s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96));
s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112));
STORE(out, s[0][0]);
STORE(out + 16, s[0][1]);
STORE(out + 32, s[1][0]);
STORE(out + 48, s[1][1]);
STORE(out + 64, s[2][0]);
STORE(out + 80, s[2][1]);
STORE(out + 96, s[3][0]);
STORE(out + 112, s[3][1]);
}
void haraka256_8x(unsigned char *out, const unsigned char *in) {
// This is faster on Skylake, the code below is faster on Haswell.
haraka256_4x(out, in);
haraka256_4x(out + 128, in + 128);
return;
// __m128i s[8][2], tmp;
//
// int i;
//
// s[0][0] = LOAD(in);
// s[0][1] = LOAD(in + 16);
// s[1][0] = LOAD(in + 32);
// s[1][1] = LOAD(in + 48);
// s[2][0] = LOAD(in + 64);
// s[2][1] = LOAD(in + 80);
// s[3][0] = LOAD(in + 96);
// s[3][1] = LOAD(in + 112);
// s[4][0] = LOAD(in + 128);
// s[4][1] = LOAD(in + 144);
// s[5][0] = LOAD(in + 160);
// s[5][1] = LOAD(in + 176);
// s[6][0] = LOAD(in + 192);
// s[6][1] = LOAD(in + 208);
// s[7][0] = LOAD(in + 224);
// s[7][1] = LOAD(in + 240);
//
// // Round 1
// AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0);
//
// MIX2(s[0][0], s[0][1]);
// MIX2(s[1][0], s[1][1]);
// MIX2(s[2][0], s[2][1]);
// MIX2(s[3][0], s[3][1]);
// MIX2(s[4][0], s[4][1]);
// MIX2(s[5][0], s[5][1]);
// MIX2(s[6][0], s[6][1]);
// MIX2(s[7][0], s[7][1]);
//
//
// // Round 2
// AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 4);
//
// MIX2(s[0][0], s[0][1]);
// MIX2(s[1][0], s[1][1]);
// MIX2(s[2][0], s[2][1]);
// MIX2(s[3][0], s[3][1]);
// MIX2(s[4][0], s[4][1]);
// MIX2(s[5][0], s[5][1]);
// MIX2(s[6][0], s[6][1]);
// MIX2(s[7][0], s[7][1]);
//
// // Round 3
// AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8);
//
// MIX2(s[0][0], s[0][1]);
// MIX2(s[1][0], s[1][1]);
// MIX2(s[2][0], s[2][1]);
// MIX2(s[3][0], s[3][1]);
// MIX2(s[4][0], s[4][1]);
// MIX2(s[5][0], s[5][1]);
// MIX2(s[6][0], s[6][1]);
// MIX2(s[7][0], s[7][1]);
//
// // Round 4
// AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 12);
//
// MIX2(s[0][0], s[0][1]);
// MIX2(s[1][0], s[1][1]);
// MIX2(s[2][0], s[2][1]);
// MIX2(s[3][0], s[3][1]);
// MIX2(s[4][0], s[4][1]);
// MIX2(s[5][0], s[5][1]);
// MIX2(s[6][0], s[6][1]);
// MIX2(s[7][0], s[7][1]);
//
// // Round 5
// AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16);
//
// MIX2(s[0][0], s[0][1]);
// MIX2(s[1][0], s[1][1]);
// MIX2(s[2][0], s[2][1]);
// MIX2(s[3][0], s[3][1]);
// MIX2(s[4][0], s[4][1]);
// MIX2(s[5][0], s[5][1]);
// MIX2(s[6][0], s[6][1]);
// MIX2(s[7][0], s[7][1]);
//
// // Feed Forward
// s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));
// s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));
// s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32));
// s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48));
// s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64));
// s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80));
// s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96));
// s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112));
// s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 128));
// s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 144));
// s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 160));
// s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 176));
// s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 192));
// s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 208));
// s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 224));
// s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 240));
//
// STORE(out, s[0][0]);
// STORE(out + 16, s[0][1]);
// STORE(out + 32, s[1][0]);
// STORE(out + 48, s[1][1]);
// STORE(out + 64, s[2][0]);
// STORE(out + 80, s[2][1]);
// STORE(out + 96, s[3][0]);
// STORE(out + 112, s[3][1]);
// STORE(out + 128, s[4][0]);
// STORE(out + 144, s[4][1]);
// STORE(out + 160, s[5][0]);
// STORE(out + 176, s[5][1]);
// STORE(out + 192, s[6][0]);
// STORE(out + 208, s[6][1]);
// STORE(out + 224, s[7][0]);
// STORE(out + 240, s[7][1]);
}
void haraka512(unsigned char *out, const unsigned char *in) {
u128 s[4], tmp;
s[0] = LOAD(in);
s[1] = LOAD(in + 16);
s[2] = LOAD(in + 32);
s[3] = LOAD(in + 48);
AES4(s[0], s[1], s[2], s[3], 0);
MIX4(s[0], s[1], s[2], s[3]);
AES4(s[0], s[1], s[2], s[3], 8);
MIX4(s[0], s[1], s[2], s[3]);
AES4(s[0], s[1], s[2], s[3], 16);
MIX4(s[0], s[1], s[2], s[3]);
AES4(s[0], s[1], s[2], s[3], 24);
MIX4(s[0], s[1], s[2], s[3]);
AES4(s[0], s[1], s[2], s[3], 32);
MIX4(s[0], s[1], s[2], s[3]);
s[0] = _mm_xor_si128(s[0], LOAD(in));
s[1] = _mm_xor_si128(s[1], LOAD(in + 16));
s[2] = _mm_xor_si128(s[2], LOAD(in + 32));
s[3] = _mm_xor_si128(s[3], LOAD(in + 48));
TRUNCSTORE(out, s[0], s[1], s[2], s[3]);
}
void haraka512_4x(unsigned char *out, const unsigned char *in) {
u128 s[4][4], tmp;
s[0][0] = LOAD(in);
s[0][1] = LOAD(in + 16);
s[0][2] = LOAD(in + 32);
s[0][3] = LOAD(in + 48);
s[1][0] = LOAD(in + 64);
s[1][1] = LOAD(in + 80);
s[1][2] = LOAD(in + 96);
s[1][3] = LOAD(in + 112);
s[2][0] = LOAD(in + 128);
s[2][1] = LOAD(in + 144);
s[2][2] = LOAD(in + 160);
s[2][3] = LOAD(in + 176);
s[3][0] = LOAD(in + 192);
s[3][1] = LOAD(in + 208);
s[3][2] = LOAD(in + 224);
s[3][3] = LOAD(in + 240);
AES4_4x(s[0], s[1], s[2], s[3], 0);
MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
AES4_4x(s[0], s[1], s[2], s[3], 8);
MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
AES4_4x(s[0], s[1], s[2], s[3], 16);
MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
AES4_4x(s[0], s[1], s[2], s[3], 24);
MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
AES4_4x(s[0], s[1], s[2], s[3], 32);
MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));
s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));
s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32));
s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48));
s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64));
s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80));
s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96));
s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112));
s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128));
s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144));
s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160));
s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176));
s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192));
s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208));
s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224));
s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240));
TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]);
TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]);
TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]);
TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]);
}
void haraka512_8x(unsigned char *out, const unsigned char *in) {
// This is faster on Skylake, the code below is faster on Haswell.
haraka512_4x(out, in);
haraka512_4x(out + 128, in + 256);
// u128 s[8][4], tmp;
//
// s[0][0] = LOAD(in);
// s[0][1] = LOAD(in + 16);
// s[0][2] = LOAD(in + 32);
// s[0][3] = LOAD(in + 48);
// s[1][0] = LOAD(in + 64);
// s[1][1] = LOAD(in + 80);
// s[1][2] = LOAD(in + 96);
// s[1][3] = LOAD(in + 112);
// s[2][0] = LOAD(in + 128);
// s[2][1] = LOAD(in + 144);
// s[2][2] = LOAD(in + 160);
// s[2][3] = LOAD(in + 176);
// s[3][0] = LOAD(in + 192);
// s[3][1] = LOAD(in + 208);
// s[3][2] = LOAD(in + 224);
// s[3][3] = LOAD(in + 240);
// s[4][0] = LOAD(in + 256);
// s[4][1] = LOAD(in + 272);
// s[4][2] = LOAD(in + 288);
// s[4][3] = LOAD(in + 304);
// s[5][0] = LOAD(in + 320);
// s[5][1] = LOAD(in + 336);
// s[5][2] = LOAD(in + 352);
// s[5][3] = LOAD(in + 368);
// s[6][0] = LOAD(in + 384);
// s[6][1] = LOAD(in + 400);
// s[6][2] = LOAD(in + 416);
// s[6][3] = LOAD(in + 432);
// s[7][0] = LOAD(in + 448);
// s[7][1] = LOAD(in + 464);
// s[7][2] = LOAD(in + 480);
// s[7][3] = LOAD(in + 496);
//
// AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0);
// MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
// MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
// MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
// MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
// MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);
// MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);
// MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);
// MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);
//
// AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8);
// MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
// MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
// MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
// MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
// MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);
// MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);
// MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);
// MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);
//
// AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16);
// MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
// MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
// MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
// MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
// MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);
// MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);
// MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);
// MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);
//
// AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 24);
// MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
// MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
// MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
// MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
// MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);
// MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);
// MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);
// MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);
//
// AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 32);
// MIX4(s[0][0], s[0][1], s[0][2], s[0][3]);
// MIX4(s[1][0], s[1][1], s[1][2], s[1][3]);
// MIX4(s[2][0], s[2][1], s[2][2], s[2][3]);
// MIX4(s[3][0], s[3][1], s[3][2], s[3][3]);
// MIX4(s[4][0], s[4][1], s[4][2], s[4][3]);
// MIX4(s[5][0], s[5][1], s[5][2], s[5][3]);
// MIX4(s[6][0], s[6][1], s[6][2], s[6][3]);
// MIX4(s[7][0], s[7][1], s[7][2], s[7][3]);
//
//
// s[0][0] = _mm_xor_si128(s[0][0], LOAD(in));
// s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16));
// s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32));
// s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48));
// s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64));
// s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80));
// s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96));
// s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112));
// s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128));
// s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144));
// s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160));
// s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176));
// s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192));
// s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208));
// s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224));
// s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240));
// s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 256));
// s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 272));
// s[4][2] = _mm_xor_si128(s[4][2], LOAD(in + 288));
// s[4][3] = _mm_xor_si128(s[4][3], LOAD(in + 304));
// s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 320));
// s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 336));
// s[5][2] = _mm_xor_si128(s[5][2], LOAD(in + 352));
// s[5][3] = _mm_xor_si128(s[5][3], LOAD(in + 368));
// s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 384));
// s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 400));
// s[6][2] = _mm_xor_si128(s[6][2], LOAD(in + 416));
// s[6][3] = _mm_xor_si128(s[6][3], LOAD(in + 432));
// s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 448));
// s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 464));
// s[7][2] = _mm_xor_si128(s[7][2], LOAD(in + 480));
// s[7][3] = _mm_xor_si128(s[7][3], LOAD(in + 496));
//
// TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]);
// TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]);
// TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]);
// TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]);
// TRUNCSTORE(out + 128, s[4][0], s[4][1], s[4][2], s[4][3]);
// TRUNCSTORE(out + 160, s[5][0], s[5][1], s[5][2], s[5][3]);
// TRUNCSTORE(out + 192, s[6][0], s[6][1], s[6][2], s[6][3]);
// TRUNCSTORE(out + 224, s[7][0], s[7][1], s[7][2], s[7][3]);
}

111
src/crypto/haraka.h

@ -0,0 +1,111 @@
/*
The MIT License (MIT)
Copyright (c) 2016 kste
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Optimized Implementations for Haraka256 and Haraka512
*/
#ifndef HARAKA_H_
#define HARAKA_H_
#include "immintrin.h"
#define NUMROUNDS 5
#define u64 unsigned long
#define u128 __m128i
extern u128 rc[40];
#define LOAD(src) _mm_load_si128((u128 *)(src))
#define STORE(dest,src) _mm_storeu_si128((u128 *)(dest),src)
#define AES2(s0, s1, rci) \
s0 = _mm_aesenc_si128(s0, rc[rci]); \
s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \
s0 = _mm_aesenc_si128(s0, rc[rci + 2]); \
s1 = _mm_aesenc_si128(s1, rc[rci + 3]);
#define AES2_4x(s0, s1, s2, s3, rci) \
AES2(s0[0], s0[1], rci); \
AES2(s1[0], s1[1], rci); \
AES2(s2[0], s2[1], rci); \
AES2(s3[0], s3[1], rci);
#define AES2_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \
AES2_4x(s0, s1, s2, s3, rci); \
AES2_4x(s4, s5, s6, s7, rci);
#define AES4(s0, s1, s2, s3, rci) \
s0 = _mm_aesenc_si128(s0, rc[rci]); \
s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \
s2 = _mm_aesenc_si128(s2, rc[rci + 2]); \
s3 = _mm_aesenc_si128(s3, rc[rci + 3]); \
s0 = _mm_aesenc_si128(s0, rc[rci + 4]); \
s1 = _mm_aesenc_si128(s1, rc[rci + 5]); \
s2 = _mm_aesenc_si128(s2, rc[rci + 6]); \
s3 = _mm_aesenc_si128(s3, rc[rci + 7]); \
#define AES4_4x(s0, s1, s2, s3, rci) \
AES4(s0[0], s0[1], s0[2], s0[3], rci); \
AES4(s1[0], s1[1], s1[2], s1[3], rci); \
AES4(s2[0], s2[1], s2[2], s2[3], rci); \
AES4(s3[0], s3[1], s3[2], s3[3], rci);
#define AES4_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \
AES4_4x(s0, s1, s2, s3, rci); \
AES4_4x(s4, s5, s6, s7, rci);
#define MIX2(s0, s1) \
tmp = _mm_unpacklo_epi32(s0, s1); \
s1 = _mm_unpackhi_epi32(s0, s1); \
s0 = tmp;
#define MIX4(s0, s1, s2, s3) \
tmp = _mm_unpacklo_epi32(s0, s1); \
s0 = _mm_unpackhi_epi32(s0, s1); \
s1 = _mm_unpacklo_epi32(s2, s3); \
s2 = _mm_unpackhi_epi32(s2, s3); \
s3 = _mm_unpacklo_epi32(s0, s2); \
s0 = _mm_unpackhi_epi32(s0, s2); \
s2 = _mm_unpackhi_epi32(s1, tmp); \
s1 = _mm_unpacklo_epi32(s1, tmp);
#define TRUNCSTORE(out, s0, s1, s2, s3) \
*(u64*)(out) = (u64*)(s0)[1]; \
*(u64*)(out + 8) = (u64*)(s1)[1]; \
*(u64*)(out + 16) = (u64*)(s2)[0]; \
*(u64*)(out + 24) = (u64*)(s3)[0];
void load_constants();
void test_implementations();
void load_constants();
void haraka256(unsigned char *out, const unsigned char *in);
void haraka256_4x(unsigned char *out, const unsigned char *in);
void haraka256_8x(unsigned char *out, const unsigned char *in);
void haraka512(unsigned char *out, const unsigned char *in);
void haraka512_4x(unsigned char *out, const unsigned char *in);
void haraka512_8x(unsigned char *out, const unsigned char *in);
#endif

75
src/crypto/verus_hash.cpp

@ -0,0 +1,75 @@
// (C) 2018 The Verus Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
/*
This provides the PoW hash function for Verus, a CPU-optimized hash
function with a Haraka V2 core. Unlike Haraka, which is made for short
inputs only, Verus Hash takes any length of input and produces a 256
bit output.
*/
#include <string.h>
#include "crypto/common.h"
#include "crypto/verus_hash.h"
void CVerusHash::Hash(void *result, const void *data, size_t len)
{
unsigned char buf[128];
unsigned char *bufPtr = buf;
int pos = 0, nextOffset = 64;
unsigned char *bufPtr2 = bufPtr + nextOffset;
unsigned char *ptr = (unsigned char *)data;
// put our last result or zero at beginning of buffer each time
memset(bufPtr, 0, 32);
// digest up to 32 bytes at a time
for ( ; pos < len; pos += 32)
{
if (len - pos >= 32)
{
memcpy(bufPtr + 32, ptr + pos, 32);
}
else
{
int i = (int)(len - pos);
memcpy(bufPtr + 32, ptr + pos, i);
memset(bufPtr + 32 + i, 0, 32 - i);
}
haraka512(bufPtr2, bufPtr);
bufPtr2 = bufPtr;
bufPtr += nextOffset;
nextOffset *= -1;
}
memcpy(result, bufPtr, 32);
};
CVerusHash &CVerusHash::Write(const unsigned char *data, size_t len)
{
unsigned char *tmp;
// digest up to 32 bytes at a time
for ( int pos = 0; pos < len; pos += 32)
{
int room = 32 - curPos;
if (len - pos >= room)
{
memcpy(curBuf + 32 + curPos, data + pos, room);
haraka512(result, curBuf);
tmp = curBuf;
curBuf = result;
result = tmp;
pos += room;
curPos = 0;
}
else
{
memcpy(curBuf + 32 + curPos, data + pos, len - pos);
curPos = 32 - (len - pos);
pos = len;
}
}
return *this;
}

54
src/crypto/verus_hash.h

@ -0,0 +1,54 @@
// (C) 2018 The Verus Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
/*
This provides the PoW hash function for Verus, enabling CPU mining.
*/
#ifndef VERUS_HASH_H_
#define VERUS_HASH_H_
#include <cstring>
#include <vector>
extern "C"
{
#include "crypto/haraka.h"
}
class CVerusHash
{
public:
static void Hash(void *result, const void *data, size_t len);
CVerusHash() {}
CVerusHash &Write(const unsigned char *data, size_t len);
CVerusHash &Reset()
{
curBuf = buf1;
result = buf2;
curPos = 0;
std::fill(buf1, buf1 + sizeof(buf1), 0);
std::fill(buf2, buf2 + sizeof(buf2), 0);
}
void Finalize(unsigned char hash[32])
{
if (curPos)
{
std::fill(curBuf + 32 + curPos, curBuf + 64, 0);
haraka512(hash, curBuf);
}
else
std::memcpy(hash, result, 32);
}
private:
unsigned char buf1[64], buf2[64];
unsigned char *curBuf = buf1, *result = buf2;
size_t curPos = 0;
};
#endif

41
src/hash.h

@ -8,6 +8,7 @@
#include "crypto/ripemd160.h"
#include "crypto/sha256.h"
#include "crypto/verus_hash.h"
#include "serialize.h"
#include "uint256.h"
#include "version.h"
@ -192,6 +193,37 @@ public:
}
};
/** A writer stream (for serialization) that computes a 256-bit Verus hash. */
class CVerusHashWriter
{
private:
CVerusHash state;
public:
int nType;
int nVersion;
CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
CVerusHashWriter& write(const char *pch, size_t size) {
state.Write((const unsigned char*)pch, size);
return (*this);
}
// invalidates the object for further writing
uint256 GetHash() {
uint256 result;
state.Finalize((unsigned char*)&result);
return result;
}
template<typename T>
CVerusHashWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
};
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
@ -202,6 +234,15 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL
return ss.GetHash();
}
/** Compute the 256-bit Verus hash of an object's serialization. */
template<typename T>
uint256 SerializeVerusHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
{
CVerusHashWriter ss(nType, nVersion);
ss << obj;
return ss.GetHash();
}
unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);

6
src/init.cpp

@ -9,6 +9,7 @@
#include "init.h"
#include "crypto/common.h"
#include "primitives/block.h"
#include "addrman.h"
#include "amount.h"
#ifdef ENABLE_MINING
@ -1095,6 +1096,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle());
// set the hash algorithm to use for this chain
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH;
if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH)
CBlockHeader::SetVerusHash();
// Sanity check
if (!InitSanityCheck())
return InitError(_("Initialization sanity check failed. Komodo is shutting down."));

13
src/komodo_globals.h

@ -65,12 +65,21 @@ int64_t ASSETCHAINS_GENESISPREMINE = 5000000000;
// spec will use an op_return with CLTV at front and anything after |OP_RETURN|PUSH of rest|OPRETTYPE_TIMELOCK|script|
#define _ASSETCHAINS_TIMELOCKOFF -1
int64_t ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF;
uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0;
uint64_t ASSETCHAINS_TIMEUNLOCKTO = 0;
uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0;
uint32_t ASSETCHAINS_LASTERA = 1;
uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS];
#define _ASSETCHAINS_EQUIHASH 0
uint32_t ASSETCHAINS_NUMALGOS = 2;
uint32_t ASSETCHAINS_EQUIHASH = _ASSETCHAINS_EQUIHASH;
uint32_t ASSETCHAINS_VERUSHASH = 1;
const char *ASSETCHAINS_ALGORITHMS[] = {"equihash", "verushash"};
uint64_t ASSETCHAINS_NONCEMASK[] = {0xffff,0xffffff};
uint32_t ASSETCHAINS_NONCESHIFT[] = {32,40};
uint32_t ASSETCHAINS_HASHESPERROUND[] = {1,128};
uint32_t ASSETCHAINS_ALGO = _ASSETCHAINS_EQUIHASH;
uint32_t KOMODO_INITDONE;
char KMDUSERPASS[4096],BTCUSERPASS[4096]; uint16_t KMD_PORT = 7771,BITCOIND_PORT = 7771;
uint64_t PENDING_KOMODO_TX;

27
src/komodo_utils.h

@ -13,6 +13,7 @@
* *
******************************************************************************/
#include "komodo_defs.h"
#include <string.h>
#ifdef _WIN32
#include <sodium.h>
@ -1704,6 +1705,27 @@ void komodo_args(char *argv0)
}
if ( name.c_str()[0] != 0 )
{
std:locale loc;
std::string selectedAlgo = std::tolower(GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0])), loc);
for ( int i = 0; i < ASSETCHAINS_NUMALGOS; i++ )
{
if (std::string(ASSETCHAINS_ALGORITHMS[i]) == selectedAlgo)
{
ASSETCHAINS_ALGO = i;
// default is SHA256D, so leave it unless otherwise
if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH)
{
printf("ASSETCHAINS_ALGO, algorithm set to VerusHash\n");
}
break;
}
}
if (i == ASSETCHAINS_NUMALGOS)
{
printf("ASSETCHAINS_ALGO, algorithm not supported. using equihash\n");
}
ASSETCHAINS_LASTERA = GetArg("-ac_eras", 1);
if ( ASSETCHAINS_LASTERA < 1 || ASSETCHAINS_LASTERA > ASSETCHAINS_MAX_ERAS )
{
@ -1784,6 +1806,11 @@ void komodo_args(char *argv0)
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_TIMEUNLOCKTO),(void *)&ASSETCHAINS_TIMEUNLOCKTO);
}
if ( ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH )
{
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ALGO),(void *)&ASSETCHAINS_ALGO);
}
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_COMMISSION),(void *)&ASSETCHAINS_COMMISSION);
}

231
src/miner.cpp

@ -16,8 +16,10 @@
#include "consensus/validation.h"
#ifdef ENABLE_MINING
#include "crypto/equihash.h"
#include "crypto/verus_hash.h"
#endif
#include "hash.h"
#include "main.h"
#include "metrics.h"
#include "net.h"
@ -107,7 +109,9 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
extern int32_t ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
extern uint64_t ASSETCHAINS_COMMISSION;
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE;
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
extern const char *ASSETCHAINS_ALGORITHMS[];
extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern std::string NOTARY_PUBKEY;
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
@ -445,8 +449,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
pblocktemplate->vTxFees[0] = -nFees;
// Randomise nonce
arith_uint256 nonce = UintToArith256(GetRandHash());
// Clear the top and bottom 16 bits (for local use as thread flags and counters)
nonce <<= 32;
// Clear the top 16 and bottom 16 or 24 bits (for local use as thread flags and counters)
nonce <<= ASSETCHAINS_NONCESHIFT[ASSETCHAINS_ALGO];
nonce >>= 16;
pblock->nNonce = ArithToUint256(nonce);
@ -633,6 +637,214 @@ int32_t FOUND_BLOCK,KOMODO_MAYBEMINED;
extern int32_t KOMODO_LASTMINED;
int32_t roundrobin_delay;
#ifdef ENABLE_WALLET
void static BitcoinMiner_noeq(CWallet *pwallet)
#else
void static BitcoinMiner_noeq()
#endif
{
LogPrintf("KomodoMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
RenameThread("komodo-miner");
const CChainParams& chainparams = Params();
#ifdef ENABLE_WALLET
// Each thread has its own key
CReserveKey reservekey(pwallet);
#endif
// Each thread has its own counter
unsigned int nExtraNonce = 0;
std::vector<unsigned char> solnPlaceholder = std::vector<unsigned char>();
solnPlaceholder.resize(Eh200_9.SolutionWidth);
uint8_t *script; uint64_t total,checktoshis; int32_t i,j;
while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.Tip()->nHeight != 235300 &&
{
sleep(1);
if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 )
break;
}
miningTimer.start();
try {
fprintf(stderr,"Komodo miner mining %s with %s\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
while (true)
{
if (chainparams.MiningRequiresPeers())
{
miningTimer.stop();
do {
bool fvNodesEmpty;
{
LOCK(cs_vNodes);
fvNodesEmpty = vNodes.empty();
}
if (!fvNodesEmpty )
break;
MilliSleep(1000);
} while (true);
miningTimer.start();
}
// Create new block
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip();
if ( Mining_height != pindexPrev->nHeight+1 )
{
Mining_height = pindexPrev->nHeight+1;
Mining_start = (uint32_t)time(NULL);
}
//fprintf(stderr,"%s create new block ht.%d\n",ASSETCHAINS_SYMBOL,Mining_height);
#ifdef ENABLE_WALLET
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey);
#else
CBlockTemplate *ptr = CreateNewBlockWithKey();
#endif
if ( ptr == 0 )
{
static uint32_t counter;
if ( counter++ < 100 )
fprintf(stderr,"created illegal block, retry\n");
continue;
}
unique_ptr<CBlockTemplate> pblocktemplate(ptr);
if (!pblocktemplate.get())
{
if (GetArg("-mineraddress", "").empty()) {
LogPrintf("Error in KomodoMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
} else {
// Should never reach here, because -mineraddress validity is checked in init.cpp
LogPrintf("Error in KomodoMiner: Invalid -mineraddress\n");
}
return;
}
CBlock *pblock = &pblocktemplate->block;
if ( ASSETCHAINS_SYMBOL[0] != 0 )
{
if ( ASSETCHAINS_REWARD[0] == 0 && !ASSETCHAINS_LASTERA )
{
if ( pblock->vtx.size() == 1 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT )
{
static uint32_t counter;
if ( counter++ < 10 )
fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",ASSETCHAINS_SYMBOL);
sleep(10);
continue;
} else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
}
}
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
LogPrintf("Running %s miner with %u transactions in block (%u bytes)\n",ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO],
pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
//
// Search
//
uint32_t savebits; int64_t nStart = GetTime();
pblock->nSolution = solnPlaceholder;
savebits = pblock->nBits;
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
arith_uint256 mask(ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]);
Mining_start = 0;
while (true)
{
// for speed check multiples at a time
for (int i = 0; i < ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO]; i++)
{
solutionTargetChecks.increment();
// Update nNonce and nTime
pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
if ( UintToArith256(pblock->GetHash()) <= hashTarget )
{
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("KomodoMiner using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex());
#ifdef ENABLE_WALLET
ProcessBlockFound(pblock, *pwallet, reservekey);
#else
ProcessBlockFound(pblock));
#endif
SetThreadPriority(THREAD_PRIORITY_LOWEST);
// In regression test mode, stop mining after a block is found.
if (chainparams.MineBlocksOnDemand()) {
throw boost::thread_interrupted();
}
break;
}
// check if we're wrapping around on the nonce
if ((UintToArith256(pblock->nNonce) & mask) == mask)
{
fprintf(stderr,"%lx, break\n", ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]);
break;
}
}
// Check for stop or if block needs to be rebuilt
boost::this_thread::interruption_point();
if (vNodes.empty() && chainparams.MiningRequiresPeers())
{
if ( Mining_height > ASSETCHAINS_MINHEIGHT )
{
fprintf(stderr,"no nodes, break\n");
break;
}
}
if ((UintToArith256(pblock->nNonce) & mask) == mask)
{
fprintf(stderr,"%lx, break\n", ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]);
break;
}
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
{
fprintf(stderr,"timeout, break\n");
break;
}
if ( pindexPrev != chainActive.Tip() )
{
fprintf(stderr,"Tip advanced, break\n");
break;
}
pblock->nBits = savebits;
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
{
// Changing pblock->nTime can change work required on testnet:
hashTarget.SetCompact(pblock->nBits);
}
}
}
}
catch (const boost::thread_interrupted&)
{
miningTimer.stop();
LogPrintf("KomodoMiner terminated\n");
throw;
}
catch (const std::runtime_error &e)
{
miningTimer.stop();
LogPrintf("KomodoMiner runtime error: %s\n", e.what());
return;
}
miningTimer.stop();
}
#ifdef ENABLE_WALLET
void static BitcoinMiner(CWallet *pwallet)
#else
@ -755,7 +967,7 @@ void static BitcoinMiner()
CBlock *pblock = &pblocktemplate->block;
if ( ASSETCHAINS_SYMBOL[0] != 0 )
{
if ( ASSETCHAINS_REWARD[0] == 0 )
if ( ASSETCHAINS_REWARD[0] == 0 && !ASSETCHAINS_LASTERA )
{
if ( pblock->vtx.size() == 1 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT )
{
@ -840,6 +1052,7 @@ void static BitcoinMiner()
}*/
// Hash state
KOMODO_CHOSEN_ONE = 0;
crypto_generichash_blake2b_state state;
EhInitialiseState(n, k, state);
// I = the block header minus nonce and solution.
@ -1058,9 +1271,15 @@ void GenerateBitcoins(bool fGenerate, int nThreads)
minerThreads = new boost::thread_group();
for (int i = 0; i < nThreads; i++) {
#ifdef ENABLE_WALLET
minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
else
minerThreads->create_thread(boost::bind(&BitcoinMiner_noeq, pwallet));
#else
minerThreads->create_thread(&BitcoinMiner);
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
minerThreads->create_thread(&BitcoinMiner);
else
minerThreads->create_thread(&BitcoinMiner_noeq);
#endif
}
}

6
src/pow.cpp

@ -21,6 +21,8 @@
#endif // ENABLE_RUST
uint32_t komodo_chainactive_timestamp();
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH;
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
@ -83,6 +85,9 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
{
if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
return true;
unsigned int n = params.EquihashN();
unsigned int k = params.EquihashK();
@ -110,6 +115,7 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param
bool isValid;
EhIsValidSolution(n, k, state, pblock->nSolution, isValid);
if (!isValid)
return error("CheckEquihashSolution(): invalid solution");

24
src/primitives/block.cpp

@ -10,11 +10,33 @@
#include "utilstrencodings.h"
#include "crypto/common.h"
uint256 CBlockHeader::GetHash() const
// default hash algorithm for block
uint256 (CBlockHeader::*CBlockHeader::hashFunction)() const = &CBlockHeader::GetSHA256DHash;
uint256 CBlockHeader::GetSHA256DHash() const
{
return SerializeHash(*this);
}
uint256 CBlockHeader::GetVerusHash() const
{
if (hashPrevBlock == uint256())
// always use SHA256D for genesis block
return SerializeHash(*this);
else
return SerializeVerusHash(*this);
}
void CBlockHeader::SetSHA256DHash()
{
CBlockHeader::hashFunction = &CBlockHeader::GetSHA256DHash;
}
void CBlockHeader::SetVerusHash()
{
CBlockHeader::hashFunction = &CBlockHeader::GetVerusHash;
}
uint256 CBlock::BuildMerkleTree(bool* fMutated) const
{
/* WARNING! If you're reading this because you're learning about crypto

15
src/primitives/block.h

@ -23,6 +23,10 @@ public:
// header
static const size_t HEADER_SIZE=4+32+32+32+4+4+32; // excluding Equihash solution
static const int32_t CURRENT_VERSION=4;
static uint256 (CBlockHeader::*hashFunction)() const;
static void SetHashAlgo();
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
@ -69,7 +73,16 @@ public:
return (nBits == 0);
}
uint256 GetHash() const;
uint256 GetHash() const
{
return (this->*hashFunction)();
}
uint256 GetSHA256DHash() const;
static void SetSHA256DHash();
uint256 GetVerusHash() const;
static void SetVerusHash();
int64_t GetBlockTime() const
{

5
src/util.cpp

@ -970,8 +970,9 @@ std::string LicenseInfo()
return "\n" +
FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i The Zcash Developers"), COPYRIGHT_YEAR)) + "\n" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i jl777 and SuperNET developers"), COPYRIGHT_YEAR)) + "\n" +
"\n" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i jl777 and SuperNET developers"), COPYRIGHT_YEAR)) + "\n" +
FormatParagraph(strprintf(_("Copyright (C) 2018-%i The Verus developers"), COPYRIGHT_YEAR)) + "\n" +
"\n" +
FormatParagraph(_("This is experimental software.")) + "\n" +
"\n" +
FormatParagraph(_("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.")) + "\n" +

Loading…
Cancel
Save