diff --git a/src/common.h b/src/common.h index f331c70..73700e0 100644 --- a/src/common.h +++ b/src/common.h @@ -162,7 +162,7 @@ struct alignas(uint64_t) hash { uint8_t h[HASH_SIZE]; - FORCEINLINE hash() : h{} {} + FORCEINLINE constexpr hash() : h{} {} constexpr hash(std::initializer_list l) : h{} { auto it = l.begin(); diff --git a/src/keccak.h b/src/keccak.h index e97b297..8d73419 100644 --- a/src/keccak.h +++ b/src/keccak.h @@ -17,6 +17,8 @@ #pragma once +#include "keccak_constexpr.h" + namespace p2pool { enum KeccakParams { @@ -26,12 +28,6 @@ enum KeccakParams { extern const uint64_t keccakf_rndc[24]; -// keccak hash of a single 0x00 byte -constexpr hash keccak_0x00{ 0xbc, 0x36, 0x78, 0x9e, 0x7a, 0x1e, 0x28, 0x14, 0x36, 0x46, 0x42, 0x29, 0x82, 0x8f, 0x81, 0x7d, 0x66, 0x12, 0xf7, 0xb4, 0x77, 0xd6, 0x65, 0x91, 0xff, 0x96, 0xa9, 0xe0, 0x64, 0xbc, 0xc9, 0x8a }; - -// keccak hash of "subaddress_viewpub" -constexpr hash keccak_subaddress_viewpub{ 0x40, 0xb2, 0x0e, 0x14, 0xc5, 0x9e, 0xdc, 0x32, 0x57, 0xb1, 0x71, 0xb0, 0xf3, 0x76, 0x27, 0x01, 0x8e, 0x92, 0x45, 0xed, 0xd5, 0x2a, 0x69, 0x0b, 0xf6, 0xd9, 0xe6, 0x21, 0xa0, 0x98, 0xb9, 0x6a }; - typedef void (*keccakf_func)(std::array&); extern keccakf_func keccakf; diff --git a/src/keccak_constexpr.h b/src/keccak_constexpr.h new file mode 100644 index 0000000..620134a --- /dev/null +++ b/src/keccak_constexpr.h @@ -0,0 +1,144 @@ +/* + * This file is part of the Monero P2Pool + * Copyright (c) 2021-2025 SChernykh + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +namespace p2pool { + +namespace ConstexprKeccak +{ + +template +static FORCEINLINE constexpr uint64_t rotl64(uint64_t x) { return (x << y) | (x >> (64 - y)); } + +template +static FORCEINLINE constexpr void keccakf(std::array& st) +{ + constexpr 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 + }; + + for (int round = 0; round < ROUNDS; ++round) { + uint64_t bc[5] = {}; + + // Theta + for (int i = 0; i < 5; ++i) bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + + for (int i = 0; i < 5; ++i) { + const uint64_t t = bc[(i + 4) % 5] ^ rotl64<1>(bc[(i + 1) % 5]); + for (int j = 0; j < 25; j += 5) st[i + j] ^= t; + } + + // Rho Pi + const uint64_t st1 = st[1]; + st[ 1] = rotl64<44>(st[ 6]); + st[ 6] = rotl64<20>(st[ 9]); + st[ 9] = rotl64<61>(st[22]); + st[22] = rotl64<39>(st[14]); + st[14] = rotl64<18>(st[20]); + st[20] = rotl64<62>(st[ 2]); + st[ 2] = rotl64<43>(st[12]); + st[12] = rotl64<25>(st[13]); + st[13] = rotl64< 8>(st[19]); + st[19] = rotl64<56>(st[23]); + st[23] = rotl64<41>(st[15]); + st[15] = rotl64<27>(st[ 4]); + st[ 4] = rotl64<14>(st[24]); + st[24] = rotl64< 2>(st[21]); + st[21] = rotl64<55>(st[ 8]); + st[ 8] = rotl64<45>(st[16]); + st[16] = rotl64<36>(st[ 5]); + st[ 5] = rotl64<28>(st[ 3]); + st[ 3] = rotl64<21>(st[18]); + st[18] = rotl64<15>(st[17]); + st[17] = rotl64<10>(st[11]); + st[11] = rotl64< 6>(st[ 7]); + st[ 7] = rotl64< 3>(st[10]); + st[10] = rotl64< 1>(st1); + + // Chi + for (int i = 0; i < 25; i += 5) { + const uint64_t t[5] = { st[i], st[i + 1], st[i + 2], st[i + 3], st[i + 4] }; + for (int j = 0; j < 5; ++j) st[i + j] ^= ~t[(j + 1) % 5] & t[(j + 2) % 5]; + } + + // Iota + st[0] ^= keccakf_rndc[round]; + } +} + +} // namespace ConstexprKeccak + +template +static constexpr hash keccak(const char (&input)[len]) +{ + hash result{}; + + if constexpr (len <= 0) { + return result; + } + + constexpr int inlen = len - 1; + + constexpr int rsiz = 136; + constexpr int rsizw = rsiz / 8; + + static_assert(inlen < rsiz, "Too long input"); + + uint8_t temp[144] = {}; + + for (int i = 0; i < inlen; ++i) { + temp[i] = static_cast(input[i]); + } + + temp[inlen] = 1; + temp[rsiz - 1] |= 0x80; + + std::array st = {}; + + for (int i = 0; i < rsizw; i++) { + uint64_t k = 0; + for (int j = 0; j < 8; ++j) { + k |= static_cast(temp[i * 8 + j]) << (j * 8); + } + st[i] ^= k; + } + + ConstexprKeccak::keccakf<24>(st); + + for (size_t i = 0; i < HASH_SIZE; ++i) { + result.h[i] = static_cast(st[i / 8] >> ((i % 8) * 8)); + } + + return result; +} + +constexpr hash keccak_0x00 = keccak("\0"); +constexpr hash keccak_subaddress_viewpub = keccak("subaddress_viewpub"); +constexpr hash keccak_onion_address_v3 = keccak("onion_address_v3"); + +static_assert((keccak_0x00.h[0] == 0xBC) && (keccak_0x00.h[1] == 0x36) && (keccak_0x00.h[2] == 0x78) && (keccak_0x00.h[3] == 0x9E), "constexpr keccak code check failed"); + +} // namespace p2pool diff --git a/src/merge_mining_client_tari.cpp b/src/merge_mining_client_tari.cpp index 1603c43..05e23ff 100644 --- a/src/merge_mining_client_tari.cpp +++ b/src/merge_mining_client_tari.cpp @@ -240,7 +240,8 @@ void MergeMiningClientTari::on_external_block(const PoolBlock& block) // Filter aux chain data only for (const auto& i : block.m_mergeMiningExtra) { - if (i.first != keccak_subaddress_viewpub) { + if ((i.first != keccak_subaddress_viewpub) && + (i.first != keccak_onion_address_v3)) { mm_extra.emplace_back(i.first, i.second); } }