diff --git a/src/crypto/wild_keccak.cpp b/src/crypto/wild_keccak.cpp new file mode 100644 index 00000000..569b4f51 --- /dev/null +++ b/src/crypto/wild_keccak.cpp @@ -0,0 +1,119 @@ +// keccak.c +// 19-Nov-11 Markku-Juhani O. Saarinen +// A baseline Keccak (3rd round) implementation. + +// Memory-hard extension of keccak for PoW +// Copyright (c) 2014 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include "wild_keccak.h" +namespace crypto +{ + + const uint64_t keccakf_rndc[24] = + { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + + const int keccakf_rotc[24] = + { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + }; + + const int keccakf_piln[24] = + { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + }; + + // update the state with given number of rounds + void regular_f::keccakf(uint64_t st[25], int rounds) + { + int i, j, round; + uint64_t t, bc[5]; + + for (round = 0; round < rounds; round++) { + + // Theta + for (i = 0; i < 5; i++) + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + + for (i = 0; i < 5; i++) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + st[j + i] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; i++) { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + for (i = 0; i < 5; i++) + bc[i] = st[j + i]; + for (i = 0; i < 5; i++) + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } + } + + void mul_f::keccakf(uint64_t st[25], int rounds) + { + int i, j, round; + uint64_t t, bc[5]; + + for (round = 0; round < rounds; round++) { + + // Theta + for (i = 0; i < 5; i++) + { + bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] * st[i + 15] * st[i + 20];//surprise + } + + for (i = 0; i < 5; i++) { + t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); + for (j = 0; j < 25; j += 5) + st[j + i] ^= t; + } + + // Rho Pi + t = st[1]; + for (i = 0; i < 24; i++) { + j = keccakf_piln[i]; + bc[0] = st[j]; + st[j] = ROTL64(t, keccakf_rotc[i]); + t = bc[0]; + } + + // Chi + for (j = 0; j < 25; j += 5) { + for (i = 0; i < 5; i++) + bc[i] = st[j + i]; + for (i = 0; i < 5; i++) + st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } + } +} \ No newline at end of file diff --git a/src/crypto/wild_keccak.h b/src/crypto/wild_keccak.h new file mode 100644 index 00000000..ed105799 --- /dev/null +++ b/src/crypto/wild_keccak.h @@ -0,0 +1,382 @@ +// keccak.h +// 19-Nov-11 Markku-Juhani O. Saarinen + +// Copyright (c) 2014 The Boolberry developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#pragma once + +#include +#include +#include "crypto.h" + +extern "C" { +//#include "crypto/alt/KeccakNISTInterface.h" + } + +#ifndef KECCAK_ROUNDS +#define KECCAK_ROUNDS 24 +#endif + +#ifndef ROTL64 +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#endif + +// compute a keccak hash (md) of given byte length from "in" + +#define KK_MIXIN_SIZE 24 + +namespace crypto +{ + +//inline +// void wild_keccak_dbl_opt(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, const UINT64* pscr, UINT64 scr_sz) +// { +// Hash(256, in, inlen*8, md, pscr, scr_sz); +// Hash(256, md, mdlen*8, md, pscr, scr_sz); +// } + + + //template + inline + crypto::hash xor_pod(const crypto::hash& a, const crypto::hash& b) + { + //static_assert(sizeof(pod_operand_a) == sizeof(pod_operand_b), "invalid xor_h usage: different sizes"); + //static_assert(sizeof(pod_operand_a)%8 == 0, "invalid xor_h usage: wrong size"); + + hash r; + for(size_t i = 0; i != 4; i++) + { + ((uint64_t*)&r)[i] = ((const uint64_t*)&a)[i] ^ ((const uint64_t*)&b)[i]; + } + return r; + } + +#define XOR_2(A, B) crypto::xor_pod(A, B) +#define XOR_3(A, B, C) crypto::xor_pod(A, XOR_2(B, C)) +#define XOR_4(A, B, C, D) crypto::xor_pod(A, XOR_3(B, C, D)) + + +#define OPT_XOR_4_RES(A_, B_, C_, D_, Res) \ + crypto::hash A = A_;crypto::hash B = B_;crypto::hash C = C_; crypto::hash D = D_; \ + ((uint64_t*)&Res)[0] = ((const uint64_t*)&A)[0] ^ ((const uint64_t*)&B)[0] ^ ((const uint64_t*)&C)[0] ^ ((const uint64_t*)&D)[0]; \ + ((uint64_t*)&Res)[1] = ((const uint64_t*)&A)[1] ^ ((const uint64_t*)&B)[1] ^ ((const uint64_t*)&C)[1] ^ ((const uint64_t*)&D)[1]; \ + ((uint64_t*)&Res)[2] = ((const uint64_t*)&A)[2] ^ ((const uint64_t*)&B)[2] ^ ((const uint64_t*)&C)[2] ^ ((const uint64_t*)&D)[2]; \ + ((uint64_t*)&Res)[3] = ((const uint64_t*)&A)[3] ^ ((const uint64_t*)&B)[3] ^ ((const uint64_t*)&C)[3] ^ ((const uint64_t*)&D)[3]; + + + typedef uint64_t state_t_m[25]; + typedef uint64_t mixin_t[KK_MIXIN_SIZE]; + + //with multiplication, for tests + template + int keccak_generic(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen) + { + state_t_m st; + uint8_t temp[144]; + size_t i, rsiz, rsizw; + + rsiz = sizeof(state_t_m) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + + memset(st, 0, sizeof(st)); + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) in)[i]; + f_traits::keccakf(st, KECCAK_ROUNDS); + } + + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) temp)[i]; + + f_traits::keccakf(st, KECCAK_ROUNDS); + + memcpy(md, st, mdlen); + + return 0; + } + /*inline + void print_state(UINT64* state, const char* comment, size_t rount) + { + printf("master_funct: %s round: %d\r\n", comment, rount); + int i; + for(i = 0; i != 25; i++) + { + printf("[%i]: %p\r\n", i, state[i]); + } + }*/ + + template + int wild_keccak(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) + { + state_t_m st; + uint8_t temp[144]; + uint64_t rsiz, rsizw; + + rsiz = sizeof(state_t_m) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + memset(&st[0], 0, 25*sizeof(st[0])); + + + for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) + { + for (size_t i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) in)[i]; + + for(size_t ll = 0; ll != KECCAK_ROUNDS; ll++) + { + if(ll != 0) + {//skip first round + mixin_t mix_in; + cb(st, mix_in); + for (size_t k = 0; k < KK_MIXIN_SIZE; k++) + st[k] ^= mix_in[k]; + } + //print_state(&st[0], "before_permut", ll); + f_traits::keccakf(st, 1); + //print_state(&st[0], "after_permut", ll); + } + } + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (size_t i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *) temp)[i]; + + for(size_t ll = 0; ll != KECCAK_ROUNDS; ll++) + { + if(ll != 0) + {//skip first state with + mixin_t mix_in; + cb(st, mix_in); + for (size_t k = 0; k < KK_MIXIN_SIZE; k++) + st[k] ^= mix_in[k]; + } + f_traits::keccakf(st, 1); + } + + memcpy(md, st, mdlen); + + return 0; + } + + template + int wild_keccak2(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) + { + state_t_m st; + uint8_t temp[144]; + uint64_t rsiz, rsizw; + + rsiz = sizeof(state_t_m) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; + rsizw = rsiz / 8; + memset(&st[0], 0, 25 * sizeof(st[0])); + + + for (; inlen >= rsiz; inlen -= rsiz, in += rsiz) + { + for (size_t i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *)in)[i]; + + for (int keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) + { + if (keccak_round != 0) + {//skip first round + mixin_t mix_in; + cb(st, mix_in); + for (size_t k = 0; k < KK_MIXIN_SIZE; k++) + st[k] ^= mix_in[k]; + } + //print_state(&st[0], "before_permut", ll); + f_traits::keccakf(st, keccak_round); + //print_state(&st[0], "after_permut", ll); + } + } + + // last block and padding + memcpy(temp, in, inlen); + temp[inlen++] = 1; + memset(temp + inlen, 0, rsiz - inlen); + temp[rsiz - 1] |= 0x80; + + for (size_t i = 0; i < rsizw; i++) + st[i] ^= ((uint64_t *)temp)[i]; + + for (int keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) + { + if (keccak_round != 0) + {//skip first state with + mixin_t mix_in; + cb(st, mix_in); + for (size_t k = 0; k < KK_MIXIN_SIZE; k++) + st[k] ^= mix_in[k]; + } + f_traits::keccakf(st, keccak_round); + } + + memcpy(md, st, mdlen); + + return 0; + } + + template + int wild_keccak_dbl(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) + { + //Satoshi's classic + wild_keccak(in, inlen, md, mdlen, cb); + wild_keccak(md, mdlen, md, mdlen, cb); + return 0; + } + + template + int wild_keccak2_dbl(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) + { + //Satoshi's classic + wild_keccak2(in, inlen, md, mdlen, cb); + wild_keccak2(md, mdlen, md, mdlen, cb); + return 0; + } + + class regular_f + { + public: + static void keccakf(uint64_t st[25], int rounds); + }; + + class mul_f + { + public: + static void keccakf(uint64_t st[25], int rounds); + }; + + //------------------------------------------------------------------ + template + bool get_blob_longhash(const std::string& bd, crypto::hash& res, uint64_t height, callback_t accessor) + { + crypto::wild_keccak_dbl(reinterpret_cast(bd.data()), bd.size(), reinterpret_cast(&res), sizeof(res), [&](crypto::state_t_m& st, crypto::mixin_t& mix) + { + if (!height) + { + memset(&mix, 0, sizeof(mix)); + return; + } +#define GET_H(index) accessor(st[index]) + for (size_t i = 0; i != 6; i++) + { + *(crypto::hash*)&mix[i * 4] = XOR_4(GET_H(i * 4), GET_H(i * 4 + 1), GET_H(i * 4 + 2), GET_H(i * 4 + 3)); + } + }); + return true; + } + //------------------------------------------------------------------ + inline + crypto::hash get_blob_longhash(const std::string& bd, uint64_t height, const std::vector& scratchpad, uint64_t sz) + { + crypto::hash h = { 0 }; + get_blob_longhash(bd, h, height, [&](uint64_t index) -> const crypto::hash& + { + return scratchpad[index%sz]; + }); + return h; + } + //------------------------------------------------------------------ + template + bool get_wild_keccak2_over_accessor(const std::string& bd, crypto::hash& res, uint64_t height, callback_t accessor) + { + crypto::wild_keccak2_dbl(reinterpret_cast(bd.data()), bd.size(), reinterpret_cast(&res), sizeof(res), [&](crypto::state_t_m& st, crypto::mixin_t& mix) + { + if (!height) + { + memset(&mix, 0, sizeof(mix)); + return; + } + +#define GET_M(index) accessor(mix[index]) + + for (size_t i = 0; i != 6; i++) + { + *(crypto::hash*)&mix[i * 4] = XOR_4(GET_H(i * 4), GET_H(i * 4 + 1), GET_H(i * 4 + 2), GET_H(i * 4 + 3)); + } + for (size_t i = 0; i != 6; i++) + { + *(crypto::hash*)&mix[(5-i) * 4] = XOR_4(GET_M(i * 4), GET_M(i * 4 + 1), GET_M(i * 4 + 2), GET_M(i * 4 + 3)); + } + }); + return true; + } + + //------------------------------------------------------------------ + inline + bool get_wild_keccak2(const std::string& bd, crypto::hash& res, uint64_t height, const std::vector& scratchpad, uint64_t sz) + { + crypto::wild_keccak2_dbl(reinterpret_cast(bd.data()), bd.size(), reinterpret_cast(&res), sizeof(res), [&](crypto::state_t_m& st, crypto::mixin_t& mix) + { + if (!height) + { + memset(&mix, 0, sizeof(mix)); + return; + } + +#define OPT_GET_H(index) scratchpad[st[index]%sz] +#define OPT_GET_M(index) scratchpad[mix[index]%sz] + + for (size_t i = 0; i != 6; i++) + { + OPT_XOR_4_RES(OPT_GET_H(i * 4), OPT_GET_H(i * 4 + 1), OPT_GET_H(i * 4 + 2), OPT_GET_H(i * 4 + 3), (*(crypto::hash*)&mix[i * 4])); + } + for (size_t i = 0; i != 6; i++) + { + OPT_XOR_4_RES(OPT_GET_M(i * 4), OPT_GET_M(i * 4 + 1), OPT_GET_M(i * 4 + 2), OPT_GET_M(i * 4 + 3), (*(crypto::hash*)&mix[ (5-i) * 4])); + } + }); + return true; + } + //------------------------------------------------------------------ + inline + bool get_wild_keccak(const std::string& bd, crypto::hash& res, uint64_t height, const std::vector& scratchpad, uint64_t sz) + { + crypto::wild_keccak_dbl(reinterpret_cast(bd.data()), bd.size(), reinterpret_cast(&res), sizeof(res), [&](crypto::state_t_m& st, crypto::mixin_t& mix) + { + if (!height) + { + memset(&mix, 0, sizeof(mix)); + return; + } + +#define OPT_GET_H(index) scratchpad[st[index]%sz] +#define OPT_GET_M(index) scratchpad[mix[index]%sz] + + for (size_t i = 0; i != 6; i++) + { + OPT_XOR_4_RES(OPT_GET_H(i * 4), OPT_GET_H(i * 4 + 1), OPT_GET_H(i * 4 + 2), OPT_GET_H(i * 4 + 3), (*(crypto::hash*)&mix[i * 4])); + } + }); + return true; + } + //------------------------------------------------------------------ + inline + crypto::hash get_wild_keccak2_over_scratchpad(const std::string& bd, uint64_t height, const std::vector& scratchpad, uint64_t sz) + { + crypto::hash h = { 0 }; + get_wild_keccak2_over_accessor(bd, h, height, [&](uint64_t index) -> const crypto::hash& + { + return scratchpad[index%sz]; + }); + return h; + } + +} + diff --git a/src/crypto/wild_keccak2.cpp b/src/crypto/wild_keccak2.cpp deleted file mode 100644 index ecf4b7ea..00000000 --- a/src/crypto/wild_keccak2.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// keccak.c -// 19-Nov-11 Markku-Juhani O. Saarinen -// A baseline Keccak (3rd round) implementation. - -// Memory-hard extension of keccak for PoW -// Copyright (c) 2014 The Boolberry developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - - -#include "wild_keccak.h" -namespace crypto -{ - - const uint64_t keccakf_rndc[24] = - { - 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, - 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, - 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, - 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, - 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, - 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, - 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 - }; - - const int keccakf_rotc[24] = - { - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 - }; - - const int keccakf_piln[24] = - { - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 - }; - - // update the state with given number of rounds - void regular_f::keccakf2(uint64_t st[25], int round_index) - { - int i, j, round; - uint64_t t, bc[5]; - - - // Theta - for (i = 0; i < 5; i++) - bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; - - for (i = 0; i < 5; i++) { - t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); - for (j = 0; j < 25; j += 5) - st[j + i] ^= t; - } - - // Rho Pi - t = st[1]; - for (i = 0; i < 24; i++) { - j = keccakf_piln[i]; - bc[0] = st[j]; - st[j] = ROTL64(t, keccakf_rotc[i]); - t = bc[0]; - } - - // Chi - for (j = 0; j < 25; j += 5) { - for (i = 0; i < 5; i++) - bc[i] = st[j + i]; - for (i = 0; i < 5; i++) - st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; - } - - // Iota - st[0] ^= keccakf_rndc[round_index]; - } -} \ No newline at end of file diff --git a/src/crypto/wild_keccak2.h b/src/crypto/wild_keccak2.h deleted file mode 100644 index 2e8dbc8d..00000000 --- a/src/crypto/wild_keccak2.h +++ /dev/null @@ -1,149 +0,0 @@ -// keccak.h -// 19-Nov-11 Markku-Juhani O. Saarinen - -// Copyright (c) 2014 The Boolberry developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - - -#pragma once - -#include -#include -#include "crypto.h" - -extern "C" { -#include "crypto/alt/KeccakNISTInterface.h" - } - -#ifndef KECCAK_ROUNDS -#define KECCAK_ROUNDS 24 -#endif - -#ifndef ROTL64 -#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) -#endif - -// compute a keccak hash (md) of given byte length from "in" - -#define KK_MIXIN_SIZE 24 - -namespace crypto -{ - -inline -// void wild_keccak_dbl_opt(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, const UINT64* pscr, UINT64 scr_sz) -// { -// Hash(256, in, inlen*8, md, pscr, scr_sz); -// Hash(256, md, mdlen*8, md, pscr, scr_sz); -// } - - - template - pod_operand_a xor_pod(const pod_operand_a& a, const pod_operand_b& b) - { - static_assert(sizeof(pod_operand_a) == sizeof(pod_operand_b), "invalid xor_h usage: different sizes"); - static_assert(sizeof(pod_operand_a)%8 == 0, "invalid xor_h usage: wrong size"); - - hash r; - for(size_t i = 0; i != 4; i++) - { - ((uint64_t*)&r)[i] = ((const uint64_t*)&a)[i] ^ ((const uint64_t*)&b)[i]; - } - return r; - } - -#define XOR_2(A, B) crypto::xor_pod(A, B) -#define XOR_3(A, B, C) crypto::xor_pod(A, XOR_2(B, C)) -#define XOR_4(A, B, C, D) crypto::xor_pod(A, XOR_3(B, C, D)) -#define XOR_5(A, B, C, D, E) crypto::xor_pod(A, XOR_4(B, C, D, E)) -#define XOR_8(A, B, C, D, F, G, H, I) crypto::xor_pod(XOR_4(A, B, C, D), XOR_4(F, G, H, I)) - - - - - typedef uint64_t state_t_m[25]; - typedef uint64_t mixin_t[KK_MIXIN_SIZE]; - - - template - int wild_keccak2(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) - { - state_t_m st; - uint8_t temp[144]; - uint64_t rsiz, rsizw; - - rsiz = sizeof(state_t_m) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; - rsizw = rsiz / 8; - memset(&st[0], 0, 25*sizeof(st[0])); - - - for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) - { - for (size_t i = 0; i < rsizw; i++) - st[i] ^= ((uint64_t *) in)[i]; - - for(size_t keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) - { - if(keccak_round != 0) - {//skip first round - mixin_t mix_in; - cb(st, mix_in); - for (size_t k = 0; k < KK_MIXIN_SIZE; k++) - st[k] ^= mix_in[k]; - } - //print_state(&st[0], "before_permut", ll); - f_traits::keccakf(st, 1); - //print_state(&st[0], "after_permut", ll); - } - } - - // last block and padding - memcpy(temp, in, inlen); - temp[inlen++] = 1; - memset(temp + inlen, 0, rsiz - inlen); - temp[rsiz - 1] |= 0x80; - - for (size_t i = 0; i < rsizw; i++) - st[i] ^= ((uint64_t *) temp)[i]; - - for(size_t keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) - { - if(keccak_round != 0) - {//skip first state with - mixin_t mix_in; - cb(st, mix_in); - for (size_t k = 0; k < KK_MIXIN_SIZE; k++) - st[k] ^= mix_in[k]; - } - f_traits::keccakf(st, 1); - } - - memcpy(md, st, mdlen); - - return 0; - } - - - template - int wild_keccak2_dbl(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, crypto::hash* pscratchpad, uint64_t sz) - { - //Satoshi's classic - regular_f::wild_keccak2(in, inlen, md, mdlen, cb); - regular_f::wild_keccak2(md, mdlen, md, mdlen, cb); - return 0; - } - - class regular_f - { - public: - static void keccakf(uint64_t st[25], int rounds); - }; -// -// class mul_f -// { -// public: -// static void keccakf(uint64_t st[25], int rounds); -// }; -} - diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 8efc358d..2baab74e 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -312,6 +312,7 @@ namespace currency crypto::hash get_block_longhash(uint64_t h, const crypto::hash& block_long_ash, uint64_t nonce); void get_block_longhash(const block& b, crypto::hash& res); crypto::hash get_block_longhash(const block& b); + bool unserialize_block_complete_entry(const COMMAND_RPC_GET_BLOCKS_FAST::response& serialized, COMMAND_RPC_GET_BLOCKS_DIRECT::response& unserialized); diff --git a/tests/performance_tests/keccak_test.h b/tests/performance_tests/keccak_test.h new file mode 100644 index 00000000..3a09b258 --- /dev/null +++ b/tests/performance_tests/keccak_test.h @@ -0,0 +1,235 @@ +// Copyright (c) 2012-2013 The Boolberry developers +// Copyright (c) 2012-2013 The Zano developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "crypto/crypto.h" +#include "currency_core/currency_basic.h" + + +extern "C" { +#include "crypto/keccak.h" +//#include "crypto/alt/KeccakNISTInterface.h" +} + + +#include "crypto/wild_keccak.h" +//#include "crypto/wild_keccak2.h" +#include "../core_tests/random_helper.h" + + + + + +#define TEST_BUFF_LEN 200 + +class test_keccak_base +{ +public: + static const size_t loop_count = 100000; + + bool init() + { + currency::block b; + m_buff = currency::get_block_hashing_blob(b); + m_buff.append(32 * 4, 0); + return true; + } + + bool pretest() + { + ++m_buff[0]; + if (!m_buff[0]) + ++m_buff[0]; + return true; + } +protected: + std::string m_buff; +}; + +// class test_keccak : public test_keccak_base +// { +// public: +// bool test() +// { +// pretest(); +// crypto::hash h; +// keccak(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); +// LOG_PRINT_L4(h); +// return true; +// } +// }; + + +class test_keccak_generic : public test_keccak_base +{ +public: + bool test() + { + pretest(); + crypto::hash h; + crypto::keccak_generic(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); + LOG_PRINT_L4(h); + return true; + } +}; + +class test_keccak_generic_with_mul : public test_keccak_base +{ +public: + bool test() + { + pretest(); + crypto::hash h; + crypto::keccak_generic(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); + return true; + } +}; + +template +class test_wild_keccak : public test_keccak_base +{ +public: + bool init() + { + m_scratchpad_vec.resize(scratchpad_size / sizeof(crypto::hash)); + for (auto& h : m_scratchpad_vec) + h = crypto::rand(); + + return test_keccak_base::init(); + } + + bool test() + { + pretest(); + + crypto::hash h; + crypto::wild_keccak_dbl(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h), [&](crypto::state_t_m& st, crypto::mixin_t& mix) + { +#define SCR_I(i) m_scratchpad_vec[st[i]%m_scratchpad_vec.size()] + for (size_t i = 0; i != 6; i++) + { + *(crypto::hash*)&mix[i * 4] = XOR_4(SCR_I(i * 4), SCR_I(i * 4 + 1), SCR_I(i * 4 + 2), SCR_I(i * 4 + 3)); + } + }); + + return true; + } +protected: + std::vector m_scratchpad_vec; +}; + + +template +class test_wild_keccak2 : public test_keccak_base +{ +public: + bool init() + { + m_scratchpad_vec.resize(scratchpad_size / sizeof(crypto::hash)); + for (auto& h : m_scratchpad_vec) + h = crypto::rand(); + + return test_keccak_base::init(); + } + + bool test() + { + pretest(); + + crypto::hash h2; + crypto::wild_keccak_dbl_opt(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h2), sizeof(h2), (const UINT64*)&m_scratchpad_vec[0], m_scratchpad_vec.size() * 4); + LOG_PRINT_L4("HASH:" << h2); + return true; + } +protected: + std::vector m_scratchpad_vec; +}; + +#ifdef _DEBUG + #define max_measere_scratchpad 100000 +#else + #define max_measere_scratchpad 10000000 +#endif +#define measere_rounds 10000 +void measure_keccak_over_scratchpad() +{ + std::cout << std::setw(20) << std::left << "sz\t" << + std::setw(10) << "original\t" << + std::setw(10) << "original opt\t" << + std::setw(10) << "w2\t" << + std::setw(10) << "w2_opt" << ENDL; + + std::vector scratchpad_vec; + scratchpad_vec.resize(max_measere_scratchpad); + std::string has_str = "Keccak is a family of sponge functions. The sponge function is a generalization of the concept of cryptographic hash function with infinite output and can perform quasi all symmetric cryptographic functions, from hashing to pseudo-random number generation to authenticated encryption"; + + //static const uint64_t my_own_random_seed = 4669201609102990671; + //random_state_test_restorer::reset_random(my_own_random_seed); // random seeded, entering deterministic mode... + //uint64_t size_original = scratchpad_vec.size(); + //scratchpad_vec.resize(i / sizeof(crypto::hash)); + for (size_t j = 0; j != scratchpad_vec.size(); j++) + scratchpad_vec[j] = crypto::rand(); + + + crypto::hash res_to_test = { 0 }; + crypto::hash res_etalon = { 0 }; + OPT_XOR_4_RES(scratchpad_vec[0], scratchpad_vec[1], scratchpad_vec[2], scratchpad_vec[3], res_to_test); + res_etalon = XOR_4(scratchpad_vec[0], scratchpad_vec[1], scratchpad_vec[2], scratchpad_vec[3]); + + + + crypto::hash res_h1 = currency::null_hash; + res_h1 = crypto::get_wild_keccak2_over_scratchpad(has_str, 1, scratchpad_vec, 1000); + + crypto::hash res_h2 = currency::null_hash; + crypto::get_wild_keccak2(has_str, res_h2, 1, scratchpad_vec, 1000); + if (res_h2 != res_h1) + { + return; + } + + for (uint64_t i = 1000; i < max_measere_scratchpad; i += 50000) + { + + crypto::hash res_h = currency::null_hash; + uint64_t ticks_a = epee::misc_utils::get_tick_count(); + *(uint64_t*)(&has_str[8]) = i; + //original keccak + for (size_t r = 0; r != measere_rounds; r++) + { + *(size_t*)(&has_str[0]) = r; + res_h = crypto::get_blob_longhash(has_str, 1, scratchpad_vec, i); + } + //original keccak opt + uint64_t ticks_b = epee::misc_utils::get_tick_count(); + for (size_t r = 0; r != measere_rounds; r++) + { + *(size_t*)(&has_str[1]) = r; + crypto::get_wild_keccak(has_str, res_h, 1, scratchpad_vec, i); + } + + //wild keccak 2 + uint64_t ticks_c = epee::misc_utils::get_tick_count(); + for (size_t r = 0; r != measere_rounds; r++) + { + *(size_t*)(&has_str[1]) = r; + res_h = crypto::get_wild_keccak2_over_scratchpad(has_str, 1, scratchpad_vec, i); + } + //wild keccak 2 opt + uint64_t ticks_d = epee::misc_utils::get_tick_count(); + for (size_t r = 0; r != measere_rounds; r++) + { + crypto::get_wild_keccak2(has_str, res_h, 1, scratchpad_vec, i); + } + + uint64_t ticks_e = epee::misc_utils::get_tick_count(); + std::cout << std::setw(20) << std::left << i * sizeof(crypto::hash) << "\t" << + std::setw(10) << ticks_b - ticks_a << "\t" << + std::setw(10) << ticks_c - ticks_b << "\t" << + std::setw(10) << ticks_d - ticks_c << "\t" << + std::setw(10) << ticks_e - ticks_d << ENDL; + } +} diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index ebcf36f7..49728abb 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -17,6 +17,7 @@ #include "is_out_to_acc.h" #include "core_market_performance_test.h" #include "serialization_performance_test.h" +#include "keccak_test.h" int main(int argc, char** argv) { @@ -24,7 +25,7 @@ int main(int argc, char** argv) epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2); - run_serialization_performance_test(); + //run_serialization_performance_test(); //return 1; //run_core_market_performance_tests(100000); @@ -34,6 +35,8 @@ int main(int argc, char** argv) performance_timer timer; timer.start(); + measure_keccak_over_scratchpad(); + /* TEST_PERFORMANCE2(test_construct_tx, 1, 1); TEST_PERFORMANCE2(test_construct_tx, 1, 2); @@ -61,11 +64,11 @@ int main(int argc, char** argv) TEST_PERFORMANCE1(test_check_ring_signature, 10); TEST_PERFORMANCE1(test_check_ring_signature, 100); */ - TEST_PERFORMANCE0(test_is_out_to_acc); + //TEST_PERFORMANCE0(test_is_out_to_acc); //TEST_PERFORMANCE0(test_generate_key_image_helper); - TEST_PERFORMANCE0(test_generate_key_derivation); + //TEST_PERFORMANCE0(test_generate_key_derivation); //TEST_PERFORMANCE0(test_generate_key_image); - TEST_PERFORMANCE0(test_derive_public_key); + //TEST_PERFORMANCE0(test_derive_public_key); //TEST_PERFORMANCE0(test_derive_secret_key); std::cout << "Tests finished. Elapsed time: " << timer.elapsed_ms() / 1000 << " sec" << std::endl;