Bitcoin ABC 0.30.5
P2P Digital Currency
muhash.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-2020 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 <crypto/muhash.h>
6
7#include <crypto/chacha20.h>
8#include <crypto/common.h>
9#include <hash.h>
10
11#include <cassert>
12#include <cstdio>
13#include <limits>
14
15namespace {
16
17using limb_t = Num3072::limb_t;
18using double_limb_t = Num3072::double_limb_t;
19constexpr int LIMB_SIZE = Num3072::LIMB_SIZE;
24constexpr limb_t MAX_PRIME_DIFF = 1103717;
25
30inline void extract3(limb_t &c0, limb_t &c1, limb_t &c2, limb_t &n) {
31 n = c0;
32 c0 = c1;
33 c1 = c2;
34 c2 = 0;
35}
36
38inline void mul(limb_t &c0, limb_t &c1, const limb_t &a, const limb_t &b) {
39 double_limb_t t = (double_limb_t)a * b;
40 c1 = t >> LIMB_SIZE;
41 c0 = t;
42}
43
44/* [c0,c1,c2] += n * [d0,d1,d2]. c2 is 0 initially */
45inline void mulnadd3(limb_t &c0, limb_t &c1, limb_t &c2, limb_t &d0, limb_t &d1,
46 limb_t &d2, const limb_t &n) {
47 double_limb_t t = (double_limb_t)d0 * n + c0;
48 c0 = t;
49 t >>= LIMB_SIZE;
50 t += (double_limb_t)d1 * n + c1;
51 c1 = t;
52 t >>= LIMB_SIZE;
53 c2 = t + d2 * n;
54}
55
56/* [c0,c1] *= n */
57inline void muln2(limb_t &c0, limb_t &c1, const limb_t &n) {
58 double_limb_t t = (double_limb_t)c0 * n;
59 c0 = t;
60 t >>= LIMB_SIZE;
61 t += (double_limb_t)c1 * n;
62 c1 = t;
63}
64
66inline void muladd3(limb_t &c0, limb_t &c1, limb_t &c2, const limb_t &a,
67 const limb_t &b) {
68 double_limb_t t = (double_limb_t)a * b;
69 limb_t th = t >> LIMB_SIZE;
70 limb_t tl = t;
71
72 c0 += tl;
73 th += (c0 < tl) ? 1 : 0;
74 c1 += th;
75 c2 += (c1 < th) ? 1 : 0;
76}
77
79inline void muldbladd3(limb_t &c0, limb_t &c1, limb_t &c2, const limb_t &a,
80 const limb_t &b) {
81 double_limb_t t = (double_limb_t)a * b;
82 limb_t th = t >> LIMB_SIZE;
83 limb_t tl = t;
84
85 c0 += tl;
86 limb_t tt = th + ((c0 < tl) ? 1 : 0);
87 c1 += tt;
88 c2 += (c1 < tt) ? 1 : 0;
89 c0 += tl;
90 th += (c0 < tl) ? 1 : 0;
91 c1 += th;
92 c2 += (c1 < th) ? 1 : 0;
93}
94
99inline void addnextract2(limb_t &c0, limb_t &c1, const limb_t &a, limb_t &n) {
100 limb_t c2 = 0;
101
102 // add
103 c0 += a;
104 if (c0 < a) {
105 c1 += 1;
106
107 // Handle case when c1 has overflown
108 if (c1 == 0) {
109 c2 = 1;
110 }
111 }
112
113 // extract
114 n = c0;
115 c0 = c1;
116 c1 = c2;
117}
118
120inline void square_n_mul(Num3072 &in_out, const int sq, const Num3072 &mul) {
121 for (int j = 0; j < sq; ++j) {
122 in_out.Square();
123 }
124 in_out.Multiply(mul);
125}
126
127} // namespace
128
131 if (this->limbs[0] <= std::numeric_limits<limb_t>::max() - MAX_PRIME_DIFF) {
132 return false;
133 }
134 for (int i = 1; i < LIMBS; ++i) {
135 if (this->limbs[i] != std::numeric_limits<limb_t>::max()) {
136 return false;
137 }
138 }
139 return true;
140}
141
143 limb_t c0 = MAX_PRIME_DIFF;
144 limb_t c1 = 0;
145 for (int i = 0; i < LIMBS; ++i) {
146 addnextract2(c0, c1, this->limbs[i], this->limbs[i]);
147 }
148}
149
151 // For fast exponentiation a sliding window exponentiation with repunit
152 // precomputation is utilized. See "Fast Point Decompression for Standard
153 // Elliptic Curves" (Brumley, Järvinen, 2008).
154
155 // p[i] = a^(2^(2^i)-1)
156 Num3072 p[12];
157
158 p[0] = *this;
159
160 for (int i = 0; i < 11; ++i) {
161 p[i + 1] = p[i];
162 for (int j = 0; j < (1 << i); ++j) {
163 p[i + 1].Square();
164 }
165 p[i + 1].Multiply(p[i]);
166 }
167
168 Num3072 out;
169
170 out = p[11];
171
172 square_n_mul(out, 512, p[9]);
173 square_n_mul(out, 256, p[8]);
174 square_n_mul(out, 128, p[7]);
175 square_n_mul(out, 64, p[6]);
176 square_n_mul(out, 32, p[5]);
177 square_n_mul(out, 8, p[3]);
178 square_n_mul(out, 2, p[1]);
179 square_n_mul(out, 1, p[0]);
180 square_n_mul(out, 5, p[2]);
181 square_n_mul(out, 3, p[0]);
182 square_n_mul(out, 2, p[0]);
183 square_n_mul(out, 4, p[0]);
184 square_n_mul(out, 4, p[1]);
185 square_n_mul(out, 3, p[0]);
186
187 return out;
188}
189
191 limb_t c0 = 0, c1 = 0, c2 = 0;
192 Num3072 tmp;
193
194 /* Compute limbs 0..N-2 of this*a into tmp, including one reduction. */
195 for (int j = 0; j < LIMBS - 1; ++j) {
196 limb_t d0 = 0, d1 = 0, d2 = 0;
197 mul(d0, d1, this->limbs[1 + j], a.limbs[LIMBS + j - (1 + j)]);
198 for (int i = 2 + j; i < LIMBS; ++i) {
199 muladd3(d0, d1, d2, this->limbs[i], a.limbs[LIMBS + j - i]);
200 }
201 mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
202 for (int i = 0; i < j + 1; ++i) {
203 muladd3(c0, c1, c2, this->limbs[i], a.limbs[j - i]);
204 }
205 extract3(c0, c1, c2, tmp.limbs[j]);
206 }
207
208 /* Compute limb N-1 of a*b into tmp. */
209 assert(c2 == 0);
210 for (int i = 0; i < LIMBS; ++i) {
211 muladd3(c0, c1, c2, this->limbs[i], a.limbs[LIMBS - 1 - i]);
212 }
213 extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
214
215 /* Perform a second reduction. */
216 muln2(c0, c1, MAX_PRIME_DIFF);
217 for (int j = 0; j < LIMBS; ++j) {
218 addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
219 }
220
221 assert(c1 == 0);
222 assert(c0 == 0 || c0 == 1);
223
229 if (this->IsOverflow()) {
230 this->FullReduce();
231 }
232 if (c0) {
233 this->FullReduce();
234 }
235}
236
238 limb_t c0 = 0, c1 = 0, c2 = 0;
239 Num3072 tmp;
240
241 /* Compute limbs 0..N-2 of this*this into tmp, including one reduction. */
242 for (int j = 0; j < LIMBS - 1; ++j) {
243 limb_t d0 = 0, d1 = 0, d2 = 0;
244 for (int i = 0; i < (LIMBS - 1 - j) / 2; ++i) {
245 muldbladd3(d0, d1, d2, this->limbs[i + j + 1],
246 this->limbs[LIMBS - 1 - i]);
247 }
248 if ((j + 1) & 1) {
249 muladd3(d0, d1, d2, this->limbs[(LIMBS - 1 - j) / 2 + j + 1],
250 this->limbs[LIMBS - 1 - (LIMBS - 1 - j) / 2]);
251 }
252 mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
253 for (int i = 0; i < (j + 1) / 2; ++i) {
254 muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[j - i]);
255 }
256 if ((j + 1) & 1) {
257 muladd3(c0, c1, c2, this->limbs[(j + 1) / 2],
258 this->limbs[j - (j + 1) / 2]);
259 }
260 extract3(c0, c1, c2, tmp.limbs[j]);
261 }
262
263 assert(c2 == 0);
264 for (int i = 0; i < LIMBS / 2; ++i) {
265 muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[LIMBS - 1 - i]);
266 }
267 extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
268
269 /* Perform a second reduction. */
270 muln2(c0, c1, MAX_PRIME_DIFF);
271 for (int j = 0; j < LIMBS; ++j) {
272 addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
273 }
274
275 assert(c1 == 0);
276 assert(c0 == 0 || c0 == 1);
277
283 if (this->IsOverflow()) {
284 this->FullReduce();
285 }
286 if (c0) {
287 this->FullReduce();
288 }
289}
290
292 this->limbs[0] = 1;
293 for (int i = 1; i < LIMBS; ++i) {
294 this->limbs[i] = 0;
295 }
296}
297
298void Num3072::Divide(const Num3072 &a) {
299 if (this->IsOverflow()) {
300 this->FullReduce();
301 }
302
303 Num3072 inv{};
304 if (a.IsOverflow()) {
305 Num3072 b = a;
306 b.FullReduce();
307 inv = b.GetInverse();
308 } else {
309 inv = a.GetInverse();
310 }
311
312 this->Multiply(inv);
313 if (this->IsOverflow()) {
314 this->FullReduce();
315 }
316}
317
318Num3072::Num3072(const uint8_t (&data)[BYTE_SIZE]) {
319 for (int i = 0; i < LIMBS; ++i) {
320 if (sizeof(limb_t) == 4) {
321 this->limbs[i] = ReadLE32(data + 4 * i);
322 } else if (sizeof(limb_t) == 8) {
323 this->limbs[i] = ReadLE64(data + 8 * i);
324 }
325 }
326}
327
328void Num3072::ToBytes(uint8_t (&out)[BYTE_SIZE]) {
329 for (int i = 0; i < LIMBS; ++i) {
330 if (sizeof(limb_t) == 4) {
331 WriteLE32(out + i * 4, this->limbs[i]);
332 } else if (sizeof(limb_t) == 8) {
333 WriteLE64(out + i * 8, this->limbs[i]);
334 }
335 }
336}
337
339 uint8_t tmp[Num3072::BYTE_SIZE];
340
341 uint256 hashed_in{(HashWriter{} << in).GetSHA256()};
342 ChaCha20(hashed_in.data(), hashed_in.size())
344 Num3072 out{tmp};
345
346 return out;
347}
348
350 m_numerator = ToNum3072(in);
351}
352
353void MuHash3072::Finalize(uint256 &out) noexcept {
354 m_numerator.Divide(m_denominator);
355 // Needed to keep the MuHash object valid
356 m_denominator.SetToOne();
357
358 uint8_t data[Num3072::BYTE_SIZE];
359 m_numerator.ToBytes(data);
360
361 out = (HashWriter{} << data).GetSHA256();
362}
363
365 m_numerator.Multiply(mul.m_numerator);
366 m_denominator.Multiply(mul.m_denominator);
367 return *this;
368}
369
371 m_numerator.Multiply(div.m_denominator);
372 m_denominator.Multiply(div.m_numerator);
373 return *this;
374}
375
377 m_numerator.Multiply(ToNum3072(in));
378 return *this;
379}
380
382 m_denominator.Multiply(ToNum3072(in));
383 return *this;
384}
A class for ChaCha20 256-bit stream cipher developed by Daniel J.
Definition: chacha20.h:15
void Keystream(uint8_t *c, size_t bytes)
outputs the keystream of size <bytes> into
Definition: chacha20.cpp:79
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:99
A class representing MuHash sets.
Definition: muhash.h:96
Num3072 ToNum3072(Span< const uint8_t > in)
Definition: muhash.cpp:338
MuHash3072 & Remove(Span< const uint8_t > in) noexcept
Definition: muhash.cpp:381
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:353
MuHash3072() noexcept
Definition: muhash.h:105
MuHash3072 & operator/=(const MuHash3072 &div) noexcept
Definition: muhash.cpp:370
MuHash3072 & Insert(Span< const uint8_t > in) noexcept
Definition: muhash.cpp:376
MuHash3072 & operator*=(const MuHash3072 &mul) noexcept
Definition: muhash.cpp:364
Definition: muhash.h:18
Num3072 GetInverse() const
Definition: muhash.cpp:150
void Square()
Definition: muhash.cpp:237
static constexpr int LIMBS
Definition: muhash.h:35
static constexpr size_t BYTE_SIZE
Definition: muhash.h:25
bool IsOverflow() const
Indicates whether d is larger than the modulus.
Definition: muhash.cpp:130
void ToBytes(uint8_t(&out)[BYTE_SIZE])
Definition: muhash.cpp:328
limb_t limbs[LIMBS]
Definition: muhash.h:38
void SetToOne()
Definition: muhash.cpp:291
static constexpr int LIMB_SIZE
Definition: muhash.h:36
void Divide(const Num3072 &a)
Definition: muhash.cpp:298
void FullReduce()
Definition: muhash.cpp:142
uint64_t double_limb_t
Definition: muhash.h:33
uint32_t limb_t
Definition: muhash.h:34
Num3072()
Definition: muhash.h:56
void Multiply(const Num3072 &a)
Definition: muhash.cpp:190
256-bit opaque blob.
Definition: uint256.h:129
static void WriteLE32(uint8_t *ptr, uint32_t x)
Definition: common.h:40
static uint64_t ReadLE64(const uint8_t *ptr)
Definition: common.h:29
static uint32_t ReadLE32(const uint8_t *ptr)
Definition: common.h:23
static void WriteLE64(uint8_t *ptr, uint64_t x)
Definition: common.h:45
assert(!tx.IsCoinBase())