forked from lthn/blockchain
wk2 sandbox
This commit is contained in:
parent
f23e97c10c
commit
2152d1588a
7 changed files with 744 additions and 229 deletions
119
src/crypto/wild_keccak.cpp
Normal file
119
src/crypto/wild_keccak.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// keccak.c
|
||||
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
382
src/crypto/wild_keccak.h
Normal file
382
src/crypto/wild_keccak.h
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
// keccak.h
|
||||
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
|
||||
|
||||
// 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#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<typename pod_operand_a, typename pod_operand_b>
|
||||
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<class f_traits>
|
||||
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<class f_traits, class callback_t>
|
||||
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<class f_traits, class callback_t>
|
||||
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<class f_traits, class callback_t>
|
||||
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<f_traits>(in, inlen, md, mdlen, cb);
|
||||
wild_keccak<f_traits>(md, mdlen, md, mdlen, cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class f_traits, class callback_t>
|
||||
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<f_traits>(in, inlen, md, mdlen, cb);
|
||||
wild_keccak2<f_traits>(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<typename callback_t>
|
||||
bool get_blob_longhash(const std::string& bd, crypto::hash& res, uint64_t height, callback_t accessor)
|
||||
{
|
||||
crypto::wild_keccak_dbl<crypto::mul_f>(reinterpret_cast<const uint8_t*>(bd.data()), bd.size(), reinterpret_cast<uint8_t*>(&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<crypto::hash>& 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<typename callback_t>
|
||||
bool get_wild_keccak2_over_accessor(const std::string& bd, crypto::hash& res, uint64_t height, callback_t accessor)
|
||||
{
|
||||
crypto::wild_keccak2_dbl<crypto::regular_f>(reinterpret_cast<const uint8_t*>(bd.data()), bd.size(), reinterpret_cast<uint8_t*>(&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<crypto::hash>& scratchpad, uint64_t sz)
|
||||
{
|
||||
crypto::wild_keccak2_dbl<crypto::regular_f>(reinterpret_cast<const uint8_t*>(bd.data()), bd.size(), reinterpret_cast<uint8_t*>(&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<crypto::hash>& scratchpad, uint64_t sz)
|
||||
{
|
||||
crypto::wild_keccak_dbl<crypto::mul_f>(reinterpret_cast<const uint8_t*>(bd.data()), bd.size(), reinterpret_cast<uint8_t*>(&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<crypto::hash>& 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
// keccak.c
|
||||
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
// keccak.h
|
||||
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
|
||||
|
||||
// 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 <stdint.h>
|
||||
#include <string.h>
|
||||
#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<typename pod_operand_a, typename pod_operand_b>
|
||||
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<class f_traits, class callback_t>
|
||||
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<class f_traits, class callback_t>
|
||||
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);
|
||||
// };
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
235
tests/performance_tests/keccak_test.h
Normal file
235
tests/performance_tests/keccak_test.h
Normal file
|
|
@ -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<const uint8_t*>(&m_buff[0]), m_buff.size(), reinterpret_cast<uint8_t*>(&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<crypto::regular_f>(reinterpret_cast<const uint8_t*>(&m_buff[0]), m_buff.size(), reinterpret_cast<uint8_t*>(&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<crypto::mul_f>(reinterpret_cast<const uint8_t*>(&m_buff[0]), m_buff.size(), reinterpret_cast<uint8_t*>(&h), sizeof(h));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<int scratchpad_size>
|
||||
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<crypto::hash>();
|
||||
|
||||
return test_keccak_base::init();
|
||||
}
|
||||
|
||||
bool test()
|
||||
{
|
||||
pretest();
|
||||
|
||||
crypto::hash h;
|
||||
crypto::wild_keccak_dbl<crypto::mul_f>(reinterpret_cast<const uint8_t*>(&m_buff[0]), m_buff.size(), reinterpret_cast<uint8_t*>(&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<crypto::hash> m_scratchpad_vec;
|
||||
};
|
||||
|
||||
|
||||
template<int scratchpad_size>
|
||||
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<crypto::hash>();
|
||||
|
||||
return test_keccak_base::init();
|
||||
}
|
||||
|
||||
bool test()
|
||||
{
|
||||
pretest();
|
||||
|
||||
crypto::hash h2;
|
||||
crypto::wild_keccak_dbl_opt(reinterpret_cast<const uint8_t*>(&m_buff[0]), m_buff.size(), reinterpret_cast<uint8_t*>(&h2), sizeof(h2), (const UINT64*)&m_scratchpad_vec[0], m_scratchpad_vec.size() * 4);
|
||||
LOG_PRINT_L4("HASH:" << h2);
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
std::vector<crypto::hash> 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<crypto::hash> 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>();
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue