Skip to content

Commit d55a51d

Browse files
sipafjahr
authored andcommitted
MuHash3072 implementation
1 parent adff8fe commit d55a51d

File tree

6 files changed

+401
-0
lines changed

6 files changed

+401
-0
lines changed

configure.ac

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,9 @@ if test x$use_lcov_branch != xno; then
662662
AC_SUBST(LCOV_OPTS, "$LCOV_OPTS --rc lcov_branch_coverage=1")
663663
fi
664664

665+
dnl Check for __int128
666+
AC_CHECK_TYPES([__int128])
667+
665668
dnl Check for endianness
666669
AC_C_BIGENDIAN
667670

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \
369369
crypto/hmac_sha512.h \
370370
crypto/poly1305.h \
371371
crypto/poly1305.cpp \
372+
crypto/muhash.cpp \
373+
crypto/muhash.h \
372374
crypto/ripemd160.cpp \
373375
crypto/ripemd160.h \
374376
crypto/sha1.cpp \

src/bench/crypto_hash.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <hash.h>
99
#include <random.h>
1010
#include <uint256.h>
11+
#include <crypto/muhash.h>
1112
#include <crypto/ripemd160.h>
1213
#include <crypto/sha1.h>
1314
#include <crypto/sha256.h>
@@ -92,6 +93,19 @@ static void FastRandom_1bit(benchmark::State& state)
9293
}
9394
}
9495

96+
static void MuHash(benchmark::State& state)
97+
{
98+
FastRandomContext rng(true);
99+
MuHash3072 acc;
100+
unsigned char key[32] = {0};
101+
while (state.KeepRunning()) {
102+
for (int i = 0; i < 1000; i++) {
103+
key[0] = i;
104+
acc *= MuHash3072(key);
105+
}
106+
}
107+
}
108+
95109
BENCHMARK(RIPEMD160, 440);
96110
BENCHMARK(SHA1, 570);
97111
BENCHMARK(SHA256, 340);
@@ -102,3 +116,5 @@ BENCHMARK(SipHash_32b, 40 * 1000 * 1000);
102116
BENCHMARK(SHA256D64_1024, 7400);
103117
BENCHMARK(FastRandom_32bit, 110 * 1000 * 1000);
104118
BENCHMARK(FastRandom_1bit, 440 * 1000 * 1000);
119+
120+
BENCHMARK(MuHash);

src/crypto/muhash.cpp

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
// Copyright (c) 2017 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include "muhash.h"
6+
7+
#include <limits>
8+
#include "common.h"
9+
#include "chacha20.h"
10+
11+
#include <assert.h>
12+
#include <stdio.h>
13+
14+
namespace {
15+
16+
/** Extract the lowest limb of [c0,c1,c2] into n, and left shift the number by 1 limb. */
17+
#define extract3(c0,c1,c2,n) { \
18+
(n) = c0; \
19+
c0 = c1; \
20+
c1 = c2; \
21+
c2 = 0; \
22+
}
23+
24+
/** Extract the lowest limb of [c0,c1] into n, and left shift the number by 1 limb. */
25+
#define extract2(c0,c1,n) { \
26+
(n) = c0; \
27+
c0 = c1; \
28+
c1 = 0; \
29+
}
30+
31+
/** [c0,c1] = a * b */
32+
#define mul(c0,c1,a,b) { \
33+
Num3072::double_limb_type t = (Num3072::double_limb_type)a * b; \
34+
c2 = 0; \
35+
c1 = t >> Num3072::LIMB_SIZE; \
36+
c0 = t; \
37+
}
38+
39+
/* [c0,c1,c2] += n * [d0,d1,d2]. c2 is 0 initially */
40+
#define mulnadd3(c0,c1,c2,d0,d1,d2,n) { \
41+
Num3072::double_limb_type t = (Num3072::double_limb_type)d0 * n + c0; \
42+
c0 = t; \
43+
t >>= Num3072::LIMB_SIZE; \
44+
t += (Num3072::double_limb_type)d1 * n + c1; \
45+
c1 = t; \
46+
t >>= Num3072::LIMB_SIZE; \
47+
c2 = t + d2 * n; \
48+
}
49+
50+
/* [c0,c1] *= n */
51+
#define muln2(c0,c1,n) { \
52+
Num3072::double_limb_type t = (Num3072::double_limb_type)c0 * n; \
53+
c0 = t; \
54+
t >>= Num3072::LIMB_SIZE; \
55+
t += (Num3072::double_limb_type)c1 * n; \
56+
c1 = t; \
57+
t >>= Num3072::LIMB_SIZE; \
58+
}
59+
60+
/** [c0,c1,c2] += a * b */
61+
#define muladd3(c0,c1,c2,a,b) { \
62+
Num3072::limb_type tl, th; \
63+
{ \
64+
Num3072::double_limb_type t = (Num3072::double_limb_type)a * b; \
65+
th = t >> Num3072::LIMB_SIZE; \
66+
tl = t; \
67+
} \
68+
c0 += tl; \
69+
th += (c0 < tl) ? 1 : 0; \
70+
c1 += th; \
71+
c2 += (c1 < th) ? 1 : 0; \
72+
}
73+
74+
/** [c0,c1,c2] += 2 * a * b */
75+
#define muldbladd3(c0,c1,c2,a,b) { \
76+
Num3072::limb_type tl, th; \
77+
{ \
78+
Num3072::double_limb_type t = (Num3072::double_limb_type)a * b; \
79+
th = t >> Num3072::LIMB_SIZE; \
80+
tl = t; \
81+
} \
82+
c0 += tl; \
83+
Num3072::limb_type tt = th + ((c0 < tl) ? 1 : 0); \
84+
c1 += tt; \
85+
c2 += (c1 < tt) ? 1 : 0; \
86+
c0 += tl; \
87+
th += (c0 < tl) ? 1 : 0; \
88+
c1 += th; \
89+
c2 += (c1 < th) ? 1 : 0; \
90+
}
91+
92+
/** [c0,c1] += a */
93+
#define add2(c0,c1,a) { \
94+
c0 += (a); \
95+
c1 += (c0 < (a)) ? 1 : 0; \
96+
}
97+
98+
bool IsOverflow(const Num3072* d)
99+
{
100+
for (int i = 1; i < Num3072::LIMBS - 1; ++i) {
101+
if (d->limbs[i] != std::numeric_limits<Num3072::limb_type>::max()) return false;
102+
}
103+
if (d->limbs[0] <= std::numeric_limits<Num3072::limb_type>::max() - 1103717) return false;
104+
return true;
105+
}
106+
107+
void FullReduce(Num3072* d)
108+
{
109+
Num3072::limb_type c0 = 1103717;
110+
for (int i = 0; i < Num3072::LIMBS; ++i) {
111+
Num3072::limb_type c1 = 0;
112+
add2(c0, c1, d->limbs[i]);
113+
extract2(c0, c1, d->limbs[i]);
114+
}
115+
}
116+
117+
void Multiply(Num3072* out, const Num3072* a, const Num3072* b)
118+
{
119+
Num3072::limb_type c0 = 0, c1 = 0;
120+
Num3072 tmp;
121+
122+
/* Compute limbs 0..N-2 of a*b into tmp, including one reduction. */
123+
for (int j = 0; j < Num3072::LIMBS - 1; ++j) {
124+
Num3072::limb_type d0 = 0, d1 = 0, d2 = 0, c2 = 0;
125+
mul(d0, d1, a->limbs[1 + j], b->limbs[Num3072::LIMBS + j - (1 + j)]);
126+
for (int i = 2 + j; i < Num3072::LIMBS; ++i) muladd3(d0, d1, d2, a->limbs[i], b->limbs[Num3072::LIMBS + j - i]);
127+
mulnadd3(c0, c1, c2, d0, d1, d2, 1103717);
128+
for (int i = 0; i < j + 1; ++i) muladd3(c0, c1, c2, a->limbs[i], b->limbs[j - i]);
129+
extract3(c0, c1, c2, tmp.limbs[j]);
130+
}
131+
/* Compute limb N-1 of a*b into tmp. */
132+
{
133+
Num3072::limb_type c2 = 0;
134+
for (int i = 0; i < Num3072::LIMBS; ++i) muladd3(c0, c1, c2, a->limbs[i], b->limbs[Num3072::LIMBS - 1 - i]);
135+
extract3(c0, c1, c2, tmp.limbs[Num3072::LIMBS - 1]);
136+
}
137+
/* Perform a second reduction. */
138+
muln2(c0, c1, 1103717);
139+
for (int j = 0; j < Num3072::LIMBS; ++j) {
140+
add2(c0, c1, tmp.limbs[j]);
141+
extract2(c0, c1, out->limbs[j]);
142+
}
143+
assert(c1 == 0);
144+
assert(c0 == 0 || c0 == 1);
145+
/* Perform a potential third reduction. */
146+
if (c0) FullReduce(out);
147+
}
148+
149+
void Square(Num3072* out, const Num3072* a)
150+
{
151+
Num3072::limb_type c0 = 0, c1 = 0;
152+
Num3072 tmp;
153+
154+
/* Compute limbs 0..N-2 of a*a into tmp, including one reduction. */
155+
for (int j = 0; j < Num3072::LIMBS - 1; ++j) {
156+
Num3072::limb_type d0 = 0, d1 = 0, d2 = 0, c2 = 0;
157+
for (int i = 0; i < (Num3072::LIMBS - 1 - j) / 2; ++i) muldbladd3(d0, d1, d2, a->limbs[i + j + 1], a->limbs[Num3072::LIMBS - 1 - i]);
158+
if ((j + 1) & 1) muladd3(d0, d1, d2, a->limbs[(Num3072::LIMBS - 1 - j) / 2 + j + 1], a->limbs[Num3072::LIMBS - 1 - (Num3072::LIMBS - 1 - j) / 2]);
159+
mulnadd3(c0, c1, c2, d0, d1, d2, 1103717);
160+
for (int i = 0; i < (j + 1) / 2; ++i) muldbladd3(c0, c1, c2, a->limbs[i], a->limbs[j - i]);
161+
if ((j + 1) & 1) muladd3(c0, c1, c2, a->limbs[(j + 1) / 2], a->limbs[j - (j + 1) / 2]);
162+
extract3(c0, c1, c2, tmp.limbs[j]);
163+
}
164+
{
165+
Num3072::limb_type c2 = 0;
166+
for (int i = 0; i < Num3072::LIMBS / 2; ++i) muldbladd3(c0, c1, c2, a->limbs[i], a->limbs[Num3072::LIMBS - 1 - i]);
167+
extract3(c0, c1, c2, tmp.limbs[Num3072::LIMBS - 1]);
168+
}
169+
/* Perform a second reduction. */
170+
muln2(c0, c1, 1103717);
171+
for (int j = 0; j < Num3072::LIMBS; ++j) {
172+
add2(c0, c1, tmp.limbs[j]);
173+
extract2(c0, c1, out->limbs[j]);
174+
}
175+
assert(c1 == 0);
176+
assert(c0 == 0 || c0 == 1);
177+
/* Perform a potential third reduction. */
178+
if (c0) FullReduce(out);
179+
}
180+
181+
void Inverse(Num3072* out, const Num3072* a)
182+
{
183+
Num3072 p[12]; // p[i] = a^(2^(2^i)-1)
184+
Num3072 x;
185+
186+
p[0] = *a;
187+
188+
for (int i = 0; i < 11; ++i) {
189+
p[i + 1] = p[i];
190+
for (int j = 0; j < (1 << i); ++j) Square(&p[i + 1], &p[i + 1]);
191+
Multiply(&p[i + 1], &p[i + 1], &p[i]);
192+
}
193+
194+
x = p[11];
195+
196+
for (int j = 0; j < 512; ++j) Square(&x, &x);
197+
Multiply(&x, &x, &p[9]);
198+
for (int j = 0; j < 256; ++j) Square(&x, &x);
199+
Multiply(&x, &x, &p[8]);
200+
for (int j = 0; j < 128; ++j) Square(&x, &x);
201+
Multiply(&x, &x, &p[7]);
202+
for (int j = 0; j < 64; ++j) Square(&x, &x);
203+
Multiply(&x, &x, &p[6]);
204+
for (int j = 0; j < 32; ++j) Square(&x, &x);
205+
Multiply(&x, &x, &p[5]);
206+
for (int j = 0; j < 8; ++j) Square(&x, &x);
207+
Multiply(&x, &x, &p[3]);
208+
for (int j = 0; j < 2; ++j) Square(&x, &x);
209+
Multiply(&x, &x, &p[1]);
210+
for (int j = 0; j < 1; ++j) Square(&x, &x);
211+
Multiply(&x, &x, &p[0]);
212+
for (int j = 0; j < 5; ++j) Square(&x, &x);
213+
Multiply(&x, &x, &p[2]);
214+
for (int j = 0; j < 3; ++j) Square(&x, &x);
215+
Multiply(&x, &x, &p[0]);
216+
for (int j = 0; j < 2; ++j) Square(&x, &x);
217+
Multiply(&x, &x, &p[0]);
218+
for (int j = 0; j < 4; ++j) Square(&x, &x);
219+
Multiply(&x, &x, &p[0]);
220+
for (int j = 0; j < 4; ++j) Square(&x, &x);
221+
Multiply(&x, &x, &p[1]);
222+
for (int j = 0; j < 3; ++j) Square(&x, &x);
223+
Multiply(&x, &x, &p[0]);
224+
225+
*out = x;
226+
}
227+
228+
}
229+
230+
MuHash3072::MuHash3072() noexcept
231+
{
232+
data.limbs[0] = 1;
233+
for (int i = 1; i < Num3072::LIMBS; ++i) data.limbs[i] = 0;
234+
}
235+
236+
MuHash3072::MuHash3072(const unsigned char* key32) noexcept
237+
{
238+
unsigned char tmp[384];
239+
ChaCha20(key32, 32).Output(tmp, 384);
240+
for (int i = 0; i < Num3072::LIMBS; ++i) {
241+
if (sizeof(Num3072::limb_type) == 4) {
242+
data.limbs[i] = ReadLE32(tmp + 4 * i);
243+
} else if (sizeof(Num3072::limb_type) == 8) {
244+
data.limbs[i] = ReadLE64(tmp + 8 * i);
245+
}
246+
}
247+
}
248+
249+
void MuHash3072::Finalize(unsigned char* hash384) noexcept
250+
{
251+
if (IsOverflow(&data)) FullReduce(&data);
252+
for (int i = 0; i < Num3072::LIMBS; ++i) {
253+
if (sizeof(Num3072::limb_type) == 4) {
254+
WriteLE32(hash384 + i * 4, data.limbs[i]);
255+
} else if (sizeof(Num3072::limb_type) == 8) {
256+
WriteLE64(hash384 + i * 8, data.limbs[i]);
257+
}
258+
}
259+
}
260+
261+
MuHash3072& MuHash3072::operator*=(const MuHash3072& x) noexcept
262+
{
263+
Multiply(&this->data, &this->data, &x.data);
264+
return *this;
265+
}
266+
267+
MuHash3072& MuHash3072::operator/=(const MuHash3072& x) noexcept
268+
{
269+
Num3072 tmp;
270+
Inverse(&tmp, &x.data);
271+
Multiply(&this->data, &this->data, &tmp);
272+
return *this;
273+
}

src/crypto/muhash.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) 2017 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_CRYPTO_MUHASH_H
6+
#define BITCOIN_CRYPTO_MUHASH_H
7+
8+
#if defined(HAVE_CONFIG_H)
9+
#include "bitcoin-config.h"
10+
#endif
11+
12+
#include <stdint.h>
13+
14+
struct Num3072 {
15+
#ifdef HAVE___INT128
16+
typedef unsigned __int128 double_limb_type;
17+
typedef uint64_t limb_type;
18+
static constexpr int LIMBS = 48;
19+
static constexpr int LIMB_SIZE = 64;
20+
#else
21+
typedef uint64_t double_limb_type;
22+
typedef uint32_t limb_type;
23+
static constexpr int LIMBS = 96;
24+
static constexpr int LIMB_SIZE = 32;
25+
#endif
26+
limb_type limbs[LIMBS];
27+
};
28+
29+
/** A class representing MuHash sets */
30+
class MuHash3072
31+
{
32+
private:
33+
Num3072 data;
34+
35+
public:
36+
/* The empty set. */
37+
MuHash3072() noexcept;
38+
39+
/* A singleton with a single 32-byte key in it. */
40+
explicit MuHash3072(const unsigned char* key32) noexcept;
41+
42+
/* Multiply (resulting in a hash for the union of the sets) */
43+
MuHash3072& operator*=(const MuHash3072& add) noexcept;
44+
45+
/* Divide (resulting in a hash for the difference of the sets) */
46+
MuHash3072& operator/=(const MuHash3072& sub) noexcept;
47+
48+
/* Finalize into a 384-byte hash. Does not change this object's value. */
49+
void Finalize(unsigned char* hash384) noexcept;
50+
};
51+
52+
#endif // BITCOIN_CRYPTO_MUHASH_H

0 commit comments

Comments
 (0)