mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
partial bitcoin#19055: Add MuHash3072 implementation
Excludes b111410914041b72961536c3e4037eba103a8085 and 01297fb3ca57e4b8cbc5a89fc7c6367de33b0bc6
This commit is contained in:
parent
5afca7f73c
commit
c7eb44a911
@ -797,6 +797,9 @@ if test x$use_lcov_branch != xno; then
|
||||
AC_SUBST(LCOV_OPTS, "$LCOV_OPTS --rc lcov_branch_coverage=1")
|
||||
fi
|
||||
|
||||
dnl Check for __int128
|
||||
AC_CHECK_TYPES([__int128])
|
||||
|
||||
dnl Check for endianness
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
|
@ -527,6 +527,8 @@ crypto_libdash_crypto_base_a_SOURCES = \
|
||||
crypto/hmac_sha256.h \
|
||||
crypto/hmac_sha512.cpp \
|
||||
crypto/hmac_sha512.h \
|
||||
crypto/muhash.h \
|
||||
crypto/muhash.cpp \
|
||||
crypto/poly1305.h \
|
||||
crypto/poly1305.cpp \
|
||||
crypto/pkcs5_pbkdf2_hmac_sha512.cpp \
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/muhash.h>
|
||||
#include <crypto/ripemd160.h>
|
||||
#include <crypto/sha1.h>
|
||||
#include <crypto/sha256.h>
|
||||
@ -244,6 +245,54 @@ static void FastRandom_1bit(benchmark::Bench& bench)
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHash(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
unsigned char key[32] = {0};
|
||||
int i = 0;
|
||||
bench.run([&] {
|
||||
key[0] = ++i;
|
||||
acc *= MuHash3072(key);
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashMul(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
MuHash3072 muhash{rng.randbytes(32)};
|
||||
|
||||
bench.run([&] {
|
||||
acc *= muhash;
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashDiv(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
MuHash3072 muhash{rng.randbytes(32)};
|
||||
|
||||
for (size_t i = 0; i < bench.epochIterations(); ++i) {
|
||||
acc *= muhash;
|
||||
}
|
||||
|
||||
bench.run([&] {
|
||||
acc /= muhash;
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashPrecompute(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
std::vector<unsigned char> key{rng.randbytes(32)};
|
||||
|
||||
bench.run([&] {
|
||||
MuHash3072{key};
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(HASH_1MB_DSHA256);
|
||||
BENCHMARK(HASH_1MB_RIPEMD160);
|
||||
BENCHMARK(HASH_1MB_SHA1);
|
||||
@ -272,3 +321,8 @@ BENCHMARK(HASH_SHA256D64_1024);
|
||||
|
||||
BENCHMARK(FastRandom_32bit);
|
||||
BENCHMARK(FastRandom_1bit);
|
||||
|
||||
BENCHMARK(MuHash);
|
||||
BENCHMARK(MuHashMul);
|
||||
BENCHMARK(MuHashDiv);
|
||||
BENCHMARK(MuHashPrecompute);
|
||||
|
338
src/crypto/muhash.cpp
Normal file
338
src/crypto/muhash.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
// Copyright (c) 2017-2020 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <crypto/muhash.h>
|
||||
|
||||
#include <crypto/chacha20.h>
|
||||
#include <crypto/common.h>
|
||||
#include <hash.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
using limb_t = Num3072::limb_t;
|
||||
using double_limb_t = Num3072::double_limb_t;
|
||||
constexpr int LIMB_SIZE = Num3072::LIMB_SIZE;
|
||||
constexpr int LIMBS = Num3072::LIMBS;
|
||||
/** 2^3072 - 1103717, the largest 3072-bit safe prime number, is used as the modulus. */
|
||||
constexpr limb_t MAX_PRIME_DIFF = 1103717;
|
||||
|
||||
/** Extract the lowest limb of [c0,c1,c2] into n, and left shift the number by 1 limb. */
|
||||
inline void extract3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& n)
|
||||
{
|
||||
n = c0;
|
||||
c0 = c1;
|
||||
c1 = c2;
|
||||
c2 = 0;
|
||||
}
|
||||
|
||||
/** [c0,c1] = a * b */
|
||||
inline void mul(limb_t& c0, limb_t& c1, const limb_t& a, const limb_t& b)
|
||||
{
|
||||
double_limb_t t = (double_limb_t)a * b;
|
||||
c1 = t >> LIMB_SIZE;
|
||||
c0 = t;
|
||||
}
|
||||
|
||||
/* [c0,c1,c2] += n * [d0,d1,d2]. c2 is 0 initially */
|
||||
inline void mulnadd3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& d0, limb_t& d1, limb_t& d2, const limb_t& n)
|
||||
{
|
||||
double_limb_t t = (double_limb_t)d0 * n + c0;
|
||||
c0 = t;
|
||||
t >>= LIMB_SIZE;
|
||||
t += (double_limb_t)d1 * n + c1;
|
||||
c1 = t;
|
||||
t >>= LIMB_SIZE;
|
||||
c2 = t + d2 * n;
|
||||
}
|
||||
|
||||
/* [c0,c1] *= n */
|
||||
inline void muln2(limb_t& c0, limb_t& c1, const limb_t& n)
|
||||
{
|
||||
double_limb_t t = (double_limb_t)c0 * n;
|
||||
c0 = t;
|
||||
t >>= LIMB_SIZE;
|
||||
t += (double_limb_t)c1 * n;
|
||||
c1 = t;
|
||||
}
|
||||
|
||||
/** [c0,c1,c2] += a * b */
|
||||
inline void muladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
|
||||
{
|
||||
double_limb_t t = (double_limb_t)a * b;
|
||||
limb_t th = t >> LIMB_SIZE;
|
||||
limb_t tl = t;
|
||||
|
||||
c0 += tl;
|
||||
th += (c0 < tl) ? 1 : 0;
|
||||
c1 += th;
|
||||
c2 += (c1 < th) ? 1 : 0;
|
||||
}
|
||||
|
||||
/** [c0,c1,c2] += 2 * a * b */
|
||||
inline void muldbladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
|
||||
{
|
||||
double_limb_t t = (double_limb_t)a * b;
|
||||
limb_t th = t >> LIMB_SIZE;
|
||||
limb_t tl = t;
|
||||
|
||||
c0 += tl;
|
||||
limb_t tt = th + ((c0 < tl) ? 1 : 0);
|
||||
c1 += tt;
|
||||
c2 += (c1 < tt) ? 1 : 0;
|
||||
c0 += tl;
|
||||
th += (c0 < tl) ? 1 : 0;
|
||||
c1 += th;
|
||||
c2 += (c1 < th) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add limb a to [c0,c1]: [c0,c1] += a. Then extract the lowest
|
||||
* limb of [c0,c1] into n, and left shift the number by 1 limb.
|
||||
* */
|
||||
inline void addnextract2(limb_t& c0, limb_t& c1, const limb_t& a, limb_t& n)
|
||||
{
|
||||
limb_t c2 = 0;
|
||||
|
||||
// add
|
||||
c0 += a;
|
||||
if (c0 < a) {
|
||||
c1 += 1;
|
||||
|
||||
// Handle case when c1 has overflown
|
||||
if (c1 == 0)
|
||||
c2 = 1;
|
||||
}
|
||||
|
||||
// extract
|
||||
n = c0;
|
||||
c0 = c1;
|
||||
c1 = c2;
|
||||
}
|
||||
|
||||
/** in_out = in_out^(2^sq) * mul */
|
||||
inline void square_n_mul(Num3072& in_out, const int sq, const Num3072& mul)
|
||||
{
|
||||
for (int j = 0; j < sq; ++j) in_out.Square();
|
||||
in_out.Multiply(mul);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/** Indicates wether d is larger than the modulus. */
|
||||
bool Num3072::IsOverflow() const
|
||||
{
|
||||
if (this->limbs[0] <= std::numeric_limits<limb_t>::max() - MAX_PRIME_DIFF) return false;
|
||||
for (int i = 1; i < LIMBS; ++i) {
|
||||
if (this->limbs[i] != std::numeric_limits<limb_t>::max()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Num3072::FullReduce()
|
||||
{
|
||||
limb_t c0 = MAX_PRIME_DIFF;
|
||||
limb_t c1 = 0;
|
||||
for (int i = 0; i < LIMBS; ++i) {
|
||||
addnextract2(c0, c1, this->limbs[i], this->limbs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Num3072 Num3072::GetInverse() const
|
||||
{
|
||||
// For fast exponentiation a sliding window exponentiation with repunit
|
||||
// precomputation is utilized. See "Fast Point Decompression for Standard
|
||||
// Elliptic Curves" (Brumley, Järvinen, 2008).
|
||||
|
||||
Num3072 p[12]; // p[i] = a^(2^(2^i)-1)
|
||||
Num3072 out;
|
||||
|
||||
p[0] = *this;
|
||||
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
p[i + 1] = p[i];
|
||||
for (int j = 0; j < (1 << i); ++j) p[i + 1].Square();
|
||||
p[i + 1].Multiply(p[i]);
|
||||
}
|
||||
|
||||
out = p[11];
|
||||
|
||||
square_n_mul(out, 512, p[9]);
|
||||
square_n_mul(out, 256, p[8]);
|
||||
square_n_mul(out, 128, p[7]);
|
||||
square_n_mul(out, 64, p[6]);
|
||||
square_n_mul(out, 32, p[5]);
|
||||
square_n_mul(out, 8, p[3]);
|
||||
square_n_mul(out, 2, p[1]);
|
||||
square_n_mul(out, 1, p[0]);
|
||||
square_n_mul(out, 5, p[2]);
|
||||
square_n_mul(out, 3, p[0]);
|
||||
square_n_mul(out, 2, p[0]);
|
||||
square_n_mul(out, 4, p[0]);
|
||||
square_n_mul(out, 4, p[1]);
|
||||
square_n_mul(out, 3, p[0]);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void Num3072::Multiply(const Num3072& a)
|
||||
{
|
||||
limb_t c0 = 0, c1 = 0, c2 = 0;
|
||||
Num3072 tmp;
|
||||
|
||||
/* Compute limbs 0..N-2 of this*a into tmp, including one reduction. */
|
||||
for (int j = 0; j < LIMBS - 1; ++j) {
|
||||
limb_t d0 = 0, d1 = 0, d2 = 0;
|
||||
mul(d0, d1, this->limbs[1 + j], a.limbs[LIMBS + j - (1 + j)]);
|
||||
for (int i = 2 + j; i < LIMBS; ++i) muladd3(d0, d1, d2, this->limbs[i], a.limbs[LIMBS + j - i]);
|
||||
mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
|
||||
for (int i = 0; i < j + 1; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[j - i]);
|
||||
extract3(c0, c1, c2, tmp.limbs[j]);
|
||||
}
|
||||
|
||||
/* Compute limb N-1 of a*b into tmp. */
|
||||
assert(c2 == 0);
|
||||
for (int i = 0; i < LIMBS; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[LIMBS - 1 - i]);
|
||||
extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
|
||||
|
||||
/* Perform a second reduction. */
|
||||
muln2(c0, c1, MAX_PRIME_DIFF);
|
||||
for (int j = 0; j < LIMBS; ++j) {
|
||||
addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
|
||||
}
|
||||
|
||||
assert(c1 == 0);
|
||||
assert(c0 == 0 || c0 == 1);
|
||||
|
||||
/* Perform up to two more reductions if the internal state has already
|
||||
* overflown the MAX of Num3072 or if it is larger than the modulus or
|
||||
* if both are the case.
|
||||
* */
|
||||
if (this->IsOverflow()) this->FullReduce();
|
||||
if (c0) this->FullReduce();
|
||||
}
|
||||
|
||||
void Num3072::Square()
|
||||
{
|
||||
limb_t c0 = 0, c1 = 0, c2 = 0;
|
||||
Num3072 tmp;
|
||||
|
||||
/* Compute limbs 0..N-2 of this*this into tmp, including one reduction. */
|
||||
for (int j = 0; j < LIMBS - 1; ++j) {
|
||||
limb_t d0 = 0, d1 = 0, d2 = 0;
|
||||
for (int i = 0; i < (LIMBS - 1 - j) / 2; ++i) muldbladd3(d0, d1, d2, this->limbs[i + j + 1], this->limbs[LIMBS - 1 - i]);
|
||||
if ((j + 1) & 1) muladd3(d0, d1, d2, this->limbs[(LIMBS - 1 - j) / 2 + j + 1], this->limbs[LIMBS - 1 - (LIMBS - 1 - j) / 2]);
|
||||
mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
|
||||
for (int i = 0; i < (j + 1) / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[j - i]);
|
||||
if ((j + 1) & 1) muladd3(c0, c1, c2, this->limbs[(j + 1) / 2], this->limbs[j - (j + 1) / 2]);
|
||||
extract3(c0, c1, c2, tmp.limbs[j]);
|
||||
}
|
||||
|
||||
assert(c2 == 0);
|
||||
for (int i = 0; i < LIMBS / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[LIMBS - 1 - i]);
|
||||
extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
|
||||
|
||||
/* Perform a second reduction. */
|
||||
muln2(c0, c1, MAX_PRIME_DIFF);
|
||||
for (int j = 0; j < LIMBS; ++j) {
|
||||
addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
|
||||
}
|
||||
|
||||
assert(c1 == 0);
|
||||
assert(c0 == 0 || c0 == 1);
|
||||
|
||||
/* Perform up to two more reductions if the internal state has already
|
||||
* overflown the MAX of Num3072 or if it is larger than the modulus or
|
||||
* if both are the case.
|
||||
* */
|
||||
if (this->IsOverflow()) this->FullReduce();
|
||||
if (c0) this->FullReduce();
|
||||
}
|
||||
|
||||
void Num3072::SetToOne()
|
||||
{
|
||||
this->limbs[0] = 1;
|
||||
for (int i = 1; i < LIMBS; ++i) this->limbs[i] = 0;
|
||||
}
|
||||
|
||||
void Num3072::Divide(const Num3072& a)
|
||||
{
|
||||
if (this->IsOverflow()) this->FullReduce();
|
||||
|
||||
Num3072 inv{};
|
||||
if (a.IsOverflow()) {
|
||||
Num3072 b = a;
|
||||
b.FullReduce();
|
||||
inv = b.GetInverse();
|
||||
} else {
|
||||
inv = a.GetInverse();
|
||||
}
|
||||
|
||||
this->Multiply(inv);
|
||||
if (this->IsOverflow()) this->FullReduce();
|
||||
}
|
||||
|
||||
Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
|
||||
Num3072 out{};
|
||||
uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
|
||||
unsigned char tmp[BYTE_SIZE];
|
||||
ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, BYTE_SIZE);
|
||||
for (int i = 0; i < LIMBS; ++i) {
|
||||
if (sizeof(limb_t) == 4) {
|
||||
out.limbs[i] = ReadLE32(tmp + 4 * i);
|
||||
} else if (sizeof(limb_t) == 8) {
|
||||
out.limbs[i] = ReadLE64(tmp + 8 * i);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
MuHash3072::MuHash3072(Span<const unsigned char> in) noexcept
|
||||
{
|
||||
m_numerator = ToNum3072(in);
|
||||
}
|
||||
|
||||
void MuHash3072::Finalize(uint256& out) noexcept
|
||||
{
|
||||
m_numerator.Divide(m_denominator);
|
||||
m_denominator.SetToOne(); // Needed to keep the MuHash object valid
|
||||
|
||||
unsigned char data[384];
|
||||
for (int i = 0; i < LIMBS; ++i) {
|
||||
if (sizeof(limb_t) == 4) {
|
||||
WriteLE32(data + i * 4, m_numerator.limbs[i]);
|
||||
} else if (sizeof(limb_t) == 8) {
|
||||
WriteLE64(data + i * 8, m_numerator.limbs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
out = (CHashWriter(SER_DISK, 0) << data).GetSHA256();
|
||||
}
|
||||
|
||||
MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept
|
||||
{
|
||||
m_numerator.Multiply(mul.m_numerator);
|
||||
m_denominator.Multiply(mul.m_denominator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MuHash3072& MuHash3072::operator/=(const MuHash3072& div) noexcept
|
||||
{
|
||||
m_numerator.Multiply(div.m_denominator);
|
||||
m_denominator.Multiply(div.m_numerator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MuHash3072& MuHash3072::Insert(Span<const unsigned char> in) noexcept {
|
||||
m_numerator.Multiply(ToNum3072(in));
|
||||
return *this;
|
||||
}
|
||||
|
||||
MuHash3072& MuHash3072::Remove(Span<const unsigned char> in) noexcept {
|
||||
m_numerator.Divide(ToNum3072(in));
|
||||
return *this;
|
||||
}
|
130
src/crypto/muhash.h
Normal file
130
src/crypto/muhash.h
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2017-2020 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_CRYPTO_MUHASH_H
|
||||
#define BITCOIN_CRYPTO_MUHASH_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/dash-config.h>
|
||||
#endif
|
||||
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class Num3072
|
||||
{
|
||||
private:
|
||||
void FullReduce();
|
||||
bool IsOverflow() const;
|
||||
Num3072 GetInverse() const;
|
||||
|
||||
public:
|
||||
|
||||
#ifdef HAVE___INT128
|
||||
typedef unsigned __int128 double_limb_t;
|
||||
typedef uint64_t limb_t;
|
||||
static constexpr int LIMBS = 48;
|
||||
static constexpr int LIMB_SIZE = 64;
|
||||
#else
|
||||
typedef uint64_t double_limb_t;
|
||||
typedef uint32_t limb_t;
|
||||
static constexpr int LIMBS = 96;
|
||||
static constexpr int LIMB_SIZE = 32;
|
||||
#endif
|
||||
limb_t limbs[LIMBS];
|
||||
|
||||
// Sanity check for Num3072 constants
|
||||
static_assert(LIMB_SIZE * LIMBS == 3072, "Num3072 isn't 3072 bits");
|
||||
static_assert(sizeof(double_limb_t) == sizeof(limb_t) * 2, "bad size for double_limb_t");
|
||||
static_assert(sizeof(limb_t) * 8 == LIMB_SIZE, "LIMB_SIZE is incorrect");
|
||||
|
||||
// Hard coded values in MuHash3072 constructor and Finalize
|
||||
static_assert(sizeof(limb_t) == 4 || sizeof(limb_t) == 8, "bad size for limb_t");
|
||||
|
||||
void Multiply(const Num3072& a);
|
||||
void Divide(const Num3072& a);
|
||||
void SetToOne();
|
||||
void Square();
|
||||
|
||||
Num3072() { this->SetToOne(); };
|
||||
|
||||
SERIALIZE_METHODS(Num3072, obj)
|
||||
{
|
||||
for (auto& limb : obj.limbs) {
|
||||
READWRITE(limb);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** A class representing MuHash sets
|
||||
*
|
||||
* MuHash is a hashing algorithm that supports adding set elements in any
|
||||
* order but also deleting in any order. As a result, it can maintain a
|
||||
* running sum for a set of data as a whole, and add/remove when data
|
||||
* is added to or removed from it. A downside of MuHash is that computing
|
||||
* an inverse is relatively expensive. This is solved by representing
|
||||
* the running value as a fraction, and multiplying added elements into
|
||||
* the numerator and removed elements into the denominator. Only when the
|
||||
* final hash is desired, a single modular inverse and multiplication is
|
||||
* needed to combine the two. The combination is also run on serialization
|
||||
* to allow for space-efficient storage on disk.
|
||||
*
|
||||
* As the update operations are also associative, H(a)+H(b)+H(c)+H(d) can
|
||||
* in fact be computed as (H(a)+H(b)) + (H(c)+H(d)). This implies that
|
||||
* all of this is perfectly parallellizable: each thread can process an
|
||||
* arbitrary subset of the update operations, allowing them to be
|
||||
* efficiently combined later.
|
||||
*
|
||||
* Muhash does not support checking if an element is already part of the
|
||||
* set. That is why this class does not enforce the use of a set as the
|
||||
* data it represents because there is no efficient way to do so.
|
||||
* It is possible to add elements more than once and also to remove
|
||||
* elements that have not been added before. However, this implementation
|
||||
* is intended to represent a set of elements.
|
||||
*
|
||||
* See also https://cseweb.ucsd.edu/~mihir/papers/inchash.pdf and
|
||||
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-May/014337.html.
|
||||
*/
|
||||
class MuHash3072
|
||||
{
|
||||
private:
|
||||
static constexpr size_t BYTE_SIZE = 384;
|
||||
|
||||
Num3072 m_numerator;
|
||||
Num3072 m_denominator;
|
||||
|
||||
Num3072 ToNum3072(Span<const unsigned char> in);
|
||||
|
||||
public:
|
||||
/* The empty set. */
|
||||
MuHash3072() noexcept {};
|
||||
|
||||
/* A singleton with variable sized data in it. */
|
||||
explicit MuHash3072(Span<const unsigned char> in) noexcept;
|
||||
|
||||
/* Insert a single piece of data into the set. */
|
||||
MuHash3072& Insert(Span<const unsigned char> in) noexcept;
|
||||
|
||||
/* Remove a single piece of data from the set. */
|
||||
MuHash3072& Remove(Span<const unsigned char> in) noexcept;
|
||||
|
||||
/* Multiply (resulting in a hash for the union of the sets) */
|
||||
MuHash3072& operator*=(const MuHash3072& mul) noexcept;
|
||||
|
||||
/* Divide (resulting in a hash for the difference of the sets) */
|
||||
MuHash3072& operator/=(const MuHash3072& div) noexcept;
|
||||
|
||||
/* Finalize into a 32-byte hash. Does not change this object's value. */
|
||||
void Finalize(uint256& out) noexcept;
|
||||
|
||||
SERIALIZE_METHODS(MuHash3072, obj)
|
||||
{
|
||||
READWRITE(obj.m_numerator);
|
||||
READWRITE(obj.m_denominator);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_CRYPTO_MUHASH_H
|
@ -15,7 +15,9 @@
|
||||
#include <crypto/sha256.h>
|
||||
#include <crypto/sha3.h>
|
||||
#include <crypto/sha512.h>
|
||||
#include <crypto/muhash.h>
|
||||
#include <random.h>
|
||||
#include <streams.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
@ -880,4 +882,92 @@ BOOST_AUTO_TEST_CASE(sha3_256_tests)
|
||||
TestSHA3_256("72c57c359e10684d0517e46653a02d18d29eff803eb009e4d5eb9e95add9ad1a4ac1f38a70296f3a369a16985ca3c957de2084cdc9bdd8994eb59b8815e0debad4ec1f001feac089820db8becdaf896aaf95721e8674e5d476b43bd2b873a7d135cd685f545b438210f9319e4dcd55986c85303c1ddf18dc746fe63a409df0a998ed376eb683e16c09e6e9018504152b3e7628ef350659fb716e058a5263a18823d2f2f6ee6a8091945a48ae1c5cb1694cf2c1fe76ef9177953afe8899cfa2b7fe0603bfa3180937dadfb66fbbdd119bbf8063338aa4a699075a3bfdbae8db7e5211d0917e9665a702fc9b0a0a901d08bea97654162d82a9f05622b060b634244779c33427eb7a29353a5f48b07cbefa72f3622ac5900bef77b71d6b314296f304c8426f451f32049b1f6af156a9dab702e8907d3cd72bb2c50493f4d593e731b285b70c803b74825b3524cda3205a8897106615260ac93c01c5ec14f5b11127783989d1824527e99e04f6a340e827b559f24db9292fcdd354838f9339a5fa1d7f6b2087f04835828b13463dd40927866f16ae33ed501ec0e6c4e63948768c5aeea3e4f6754985954bea7d61088c44430204ef491b74a64bde1358cecb2cad28ee6a3de5b752ff6a051104d88478653339457ac45ba44cbb65f54d1969d047cda746931d5e6a8b48e211416aefd5729f3d60b56b54e7f85aa2f42de3cb69419240c24e67139a11790a709edef2ac52cf35dd0a08af45926ebe9761f498ff83bfe263d6897ee97943a4b982fe3404ef0b4a45e06113c60340e0664f14799bf59cb4b3934b465fabefd87155905ee5309ba41e9e402973311831ea600b16437f71df39ee77130490c4d0227e5d1757fdc66af3ae6b9953053ed9aafca0160209858a7d4dd38fe10e0cb153672d08633ed6c54977aa0a6e67f9ff2f8c9d22dd7b21de08192960fd0e0da68d77c8d810db11dcaa61c725cd4092cbff76c8e1debd8d0361bb3f2e607911d45716f53067bdc0d89dd4889177765166a424e9fc0cb711201099dda213355e6639ac7eb86eca2ae0ab38b7f674f37ef8a6fcca1a6f52f55d9e1dcd631d2c3c82bba129172feb991d5af51afecd9d61a88b6832e4107480e392aed61a8644f551665ebff6b20953b635737a4f895e429fddcfe801f606fbda74b3bf6f5767d0fac14907fcfd0aa1d4c11b9e91b01d68052399b51a29f1ae6acd965109977c14a555cbcbd21ad8cb9f8853506d4bc21c01e62d61d7b21be1b923be54914e6b0a7ca84dd11f1159193e1184568a6134a6bbadf5b4df986edcf2019390ae841cfaa44435e28ce877d3dae4177992fa5d4e5c005876dbe3d1e63bec7dcc0942762b48b1ecc6c1a918409a8a72812a1e245c0c67be6e729c2b49bc6ee4d24a8f63e78e75db45655c26a9a78aff36fcd67117f26b8f654dca664b9f0e30681874cb749e1a692720078856286c2560b0292cc837933423147569350955c9571bf8941ba128fd339cb4268f46b94bc6ee203eb7026813706ea51c4f24c91866fc23a724bf2501327e6ae89c29f8db315dc28d2c7c719514036367e018f4835f63fdecd71f9bdced7132b6c4f8b13c69a517026fcd3622d67cb632320d5e7308f78f4b7cea11f6291b137851dc6cd6366f2785c71c3f237f81a7658b2a8d512b61e0ad5a4710b7b124151689fcb2116063fbff7e9115fed7b93de834970b838e49f8f8ba5f1f874c354078b5810a55ae289a56da563f1da6cd80a3757d6073fa55e016e45ac6cec1f69d871c92fd0ae9670c74249045e6b464787f9504128736309fed205f8df4d90e332908581298d9c75a3fa36ab0c3c9272e62de53ab290c803d67b696fd615c260a47bffad16746f18ba1a10a061bacbea9369693b3c042eec36bed289d7d12e52bca8aa1c2dff88ca7816498d25626d0f1e106ebb0b4a12138e00f3df5b1c2f49d98b1756e69b641b7c6353d99dbff050f4d76842c6cf1c2a4b062fc8e6336fa689b7c9d5c6b4ab8c15a5c20e514ff070a602d85ae52fa7810c22f8eeffd34a095b93342144f7a98d024216b3d68ed7bea047517bfcd83ec83febd1ba0e5858e2bdc1d8b1f7b0f89e90ccc432a3f930cb8209462e64556c5054c56ca2a85f16b32eb83a10459d13516faa4d23302b7607b9bd38dab2239ac9e9440c314433fdfb3ceadab4b4f87415ed6f240e017221f3b5f7ac196cdf54957bec42fe6893994b46de3d27dc7fb58ca88feb5b9e79cf20053d12530ac524337b22a3629bea52f40b06d3e2128f32060f9105847daed81d35f20e2002817434659baff64494c5b5c7f9216bfda38412a0f70511159dc73bb6bae1f8eaa0ef08d99bcb31f94f6be12c29c83df45926430b366c99fca3270c15fc4056398fdf3135b7779e3066a006961d1ac0ad1c83179ce39e87a96b722ec23aabc065badf3e188347a360772ca6a447abac7e6a44f0d4632d52926332e44a0a86bff5ce699fd063bdda3ffd4c41b53ded49fecec67f40599b934e16e3fd1bc063ad7026f8d71bfd4cbaf56599586774723194b692036f1b6bb242e2ffb9c600b5215b412764599476ce475c9e5b396fbcebd6be323dcf4d0048077400aac7500db41dc95fc7f7edbe7c9c2ec5ea89943fe13b42217eef530bbd023671509e12dfce4e1c1c82955d965e6a68aa66f6967dba48feda572db1f099d9a6dc4bc8edade852b5e824a06890dc48a6a6510ecaf8cf7620d757290e3166d431abecc624fa9ac2234d2eb783308ead45544910c633a94964b2ef5fbc409cb8835ac4147d384e12e0a5e13951f7de0ee13eafcb0ca0c04946d7804040c0a3cd088352424b097adb7aad1ca4495952f3e6c0158c02d2bcec33bfda69301434a84d9027ce02c0b9725dad118", "d894b86261436362e64241e61f6b3e6589daf64dc641f60570c4c0bf3b1f2ca3");
|
||||
}
|
||||
|
||||
static MuHash3072 FromInt(unsigned char i) {
|
||||
unsigned char tmp[32] = {i, 0};
|
||||
return MuHash3072(tmp);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(muhash_tests)
|
||||
{
|
||||
uint256 out;
|
||||
|
||||
for (int iter = 0; iter < 10; ++iter) {
|
||||
uint256 res;
|
||||
int table[4];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
table[i] = g_insecure_rand_ctx.randbits(3);
|
||||
}
|
||||
for (int order = 0; order < 4; ++order) {
|
||||
MuHash3072 acc;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
int t = table[i ^ order];
|
||||
if (t & 4) {
|
||||
acc /= FromInt(t & 3);
|
||||
} else {
|
||||
acc *= FromInt(t & 3);
|
||||
}
|
||||
}
|
||||
acc.Finalize(out);
|
||||
if (order == 0) {
|
||||
res = out;
|
||||
} else {
|
||||
BOOST_CHECK(res == out);
|
||||
}
|
||||
}
|
||||
|
||||
MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X
|
||||
MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X, y=Y
|
||||
MuHash3072 z; // x=X, y=Y, z=1
|
||||
z *= x; // x=X, y=Y, z=X
|
||||
z *= y; // x=X, y=Y, z=X*Y
|
||||
y *= x; // x=X, y=Y*X, z=X*Y
|
||||
z /= y; // x=X, y=Y*X, z=1
|
||||
z.Finalize(out);
|
||||
|
||||
uint256 out2;
|
||||
MuHash3072 a;
|
||||
a.Finalize(out2);
|
||||
|
||||
BOOST_CHECK_EQUAL(out, out2);
|
||||
}
|
||||
|
||||
MuHash3072 acc = FromInt(0);
|
||||
acc *= FromInt(1);
|
||||
acc /= FromInt(2);
|
||||
acc.Finalize(out);
|
||||
BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863"));
|
||||
|
||||
MuHash3072 acc2 = FromInt(0);
|
||||
unsigned char tmp[32] = {1, 0};
|
||||
acc2.Insert(tmp);
|
||||
unsigned char tmp2[32] = {2, 0};
|
||||
acc2.Remove(tmp2);
|
||||
acc2.Finalize(out);
|
||||
BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863"));
|
||||
|
||||
// Test MuHash3072 serialization
|
||||
MuHash3072 serchk = FromInt(1); serchk *= FromInt(2);
|
||||
std::string ser_exp = "1fa093295ea30a6a3acdc7b3f770fa538eff537528e990e2910e40bbcfd7f6696b1256901929094694b56316de342f593303dd12ac43e06dce1be1ff8301c845beb15468fff0ef002dbf80c29f26e6452bccc91b5cb9437ad410d2a67ea847887fa3c6a6553309946880fe20db2c73fe0641adbd4e86edfee0d9f8cd0ee1230898873dc13ed8ddcaf045c80faa082774279007a2253f8922ee3ef361d378a6af3ddaf180b190ac97e556888c36b3d1fb1c85aab9ccd46e3deaeb7b7cf5db067a7e9ff86b658cf3acd6662bbcce37232daa753c48b794356c020090c831a8304416e2aa7ad633c0ddb2f11be1be316a81be7f7e472071c042cb68faef549c221ebff209273638b741aba5a81675c45a5fa92fea4ca821d7a324cb1e1a2ccd3b76c4228ec8066dad2a5df6e1bd0de45c7dd5de8070bdb46db6c554cf9aefc9b7b2bbf9f75b1864d9f95005314593905c0109b71f703d49944ae94477b51dac10a816bb6d1c700bafabc8bd86fac8df24be519a2f2836b16392e18036cb13e48c5c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||
CDataStream ss_chk(SER_DISK, PROTOCOL_VERSION);
|
||||
ss_chk << serchk;
|
||||
BOOST_CHECK_EQUAL(ser_exp, HexStr(ss_chk.str()));
|
||||
|
||||
// Test MuHash3072 deserialization
|
||||
MuHash3072 deserchk;
|
||||
ss_chk >> deserchk;
|
||||
uint256 out3;
|
||||
serchk.Finalize(out);
|
||||
deserchk.Finalize(out3);
|
||||
BOOST_CHECK_EQUAL(HexStr(out), HexStr(out3));
|
||||
|
||||
// Test MuHash3072 overflow, meaning the internal data is larger than the modulus.
|
||||
CDataStream ss_max(ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), SER_DISK, PROTOCOL_VERSION);
|
||||
MuHash3072 overflowchk;
|
||||
ss_max >> overflowchk;
|
||||
|
||||
uint256 out4;
|
||||
overflowchk.Finalize(out4);
|
||||
BOOST_CHECK_EQUAL(HexStr(out4), "3a31e6903aff0de9f62f9a9f7f8b861de76ce2cda09822b90014319ae5dc2271");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
@ -78,11 +78,13 @@ class MuHash3072:
|
||||
|
||||
def insert(self, data):
|
||||
"""Insert a byte array data in the set."""
|
||||
self.numerator = (self.numerator * data_to_num3072(data)) % self.MODULUS
|
||||
data_hash = hashlib.sha256(data).digest()
|
||||
self.numerator = (self.numerator * data_to_num3072(data_hash)) % self.MODULUS
|
||||
|
||||
def remove(self, data):
|
||||
"""Remove a byte array from the set."""
|
||||
self.denominator = (self.denominator * data_to_num3072(data)) % self.MODULUS
|
||||
data_hash = hashlib.sha256(data).digest()
|
||||
self.denominator = (self.denominator * data_to_num3072(data_hash)) % self.MODULUS
|
||||
|
||||
def digest(self):
|
||||
"""Extract the final hash. Does not modify this object."""
|
||||
@ -93,12 +95,12 @@ class MuHash3072:
|
||||
class TestFrameworkMuhash(unittest.TestCase):
|
||||
def test_muhash(self):
|
||||
muhash = MuHash3072()
|
||||
muhash.insert([0]*32)
|
||||
muhash.insert([1] + [0]*31)
|
||||
muhash.remove([2] + [0]*31)
|
||||
muhash.insert(b'\x00' * 32)
|
||||
muhash.insert((b'\x01' + b'\x00' * 31))
|
||||
muhash.remove((b'\x02' + b'\x00' * 31))
|
||||
finalized = muhash.digest()
|
||||
# This mirrors the result in the C++ MuHash3072 unit test
|
||||
self.assertEqual(finalized[::-1].hex(), "a44e16d5e34d259b349af21c06e65d653915d2e208e4e03f389af750dc0bfdc3")
|
||||
self.assertEqual(finalized[::-1].hex(), "10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863")
|
||||
|
||||
def test_chacha20(self):
|
||||
def chacha_check(key, result):
|
||||
|
Loading…
Reference in New Issue
Block a user