Skip to content

Commit f588328

Browse files
committed
Add a fuzz test for Num3072 multiplication and inversion
1 parent a26ce62 commit f588328

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

src/arith_uint256.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,7 @@ arith_uint256 UintToArith256(const uint256 &a)
229229
b.pn[x] = ReadLE32(a.begin() + x*4);
230230
return b;
231231
}
232+
233+
// Explicit instantiations for base_uint<6144> (used in test/fuzz/muhash.cpp).
234+
template base_uint<6144>& base_uint<6144>::operator*=(const base_uint<6144>& b);
235+
template base_uint<6144>& base_uint<6144>::operator/=(const base_uint<6144>& b);

src/test/fuzz/muhash.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,169 @@
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

5+
#include <arith_uint256.h>
56
#include <crypto/muhash.h>
7+
#include <span.h>
8+
#include <uint256.h>
69
#include <test/fuzz/FuzzedDataProvider.h>
710
#include <test/fuzz/fuzz.h>
811
#include <test/fuzz/util.h>
912

13+
#include <algorithm>
14+
#include <array>
1015
#include <vector>
1116

17+
namespace {
18+
19+
/** Class to represent 6144-bit numbers using arith_uint256 code.
20+
*
21+
* 6144 is sufficient to represent the product of two 3072-bit numbers. */
22+
class arith_uint6144 : public base_uint<6144> {
23+
public:
24+
arith_uint6144(uint64_t x) : base_uint{x} {}
25+
26+
/** Construct an arith_uint6144 from any multiple of 4 bytes in LE notation,
27+
* up to 768 bytes. */
28+
arith_uint6144(Span<const uint8_t> bytes) : base_uint{}
29+
{
30+
assert(bytes.size() % 4 == 0);
31+
assert(bytes.size() <= 768);
32+
for (unsigned i = 0; i * 4 < bytes.size(); ++i) {
33+
pn[i] = ReadLE32(bytes.data() + 4 * i);
34+
}
35+
}
36+
37+
/** Serialize an arithm_uint6144 to any multiply of 4 bytes in LE notation,
38+
* on the condition that the represented number fits. */
39+
void Serialize(Span<uint8_t> bytes) {
40+
assert(bytes.size() % 4 == 0);
41+
assert(bytes.size() <= 768);
42+
for (unsigned i = 0; i * 4 < bytes.size(); ++i) {
43+
WriteLE32(bytes.data() + 4 * i, pn[i]);
44+
}
45+
for (unsigned i = bytes.size() / 4; i * 4 < 768; ++i) {
46+
assert(pn[i] == 0);
47+
}
48+
};
49+
};
50+
51+
/** The MuHash3072 modulus (2**3072 - 1103717) as 768 LE8 bytes. */
52+
constexpr std::array<const uint8_t, 768> MODULUS_BYTES = {
53+
155, 40, 239, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
54+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
55+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
56+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
57+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
58+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
59+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
60+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
61+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
62+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
63+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
64+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
65+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
66+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
67+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
68+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
69+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
70+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
71+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
72+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
73+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
74+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
75+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
76+
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
77+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
89+
};
90+
91+
const arith_uint6144 ZERO{0};
92+
const arith_uint6144 ONE{1};
93+
const arith_uint6144 MODULUS{MODULUS_BYTES};
94+
95+
/** Update value to be the modulus of the input modulo MODULUS. */
96+
void Reduce(arith_uint6144& value)
97+
{
98+
arith_uint6144 tmp = value;
99+
tmp /= MODULUS;
100+
tmp *= MODULUS;
101+
value -= tmp;
102+
}
103+
104+
} // namespace
105+
106+
FUZZ_TARGET(num3072_mul)
107+
{
108+
// Test multiplication
109+
FuzzedDataProvider provider{buffer.data(), buffer.size()};
110+
111+
// Read two 3072-bit numbers from fuzz input, and construct arith_uint6144
112+
// and Num3072 objects with the read values.
113+
uint16_t data_a_len = provider.ConsumeIntegralInRange(0, 384);
114+
uint8_t data_a[384] = {0};
115+
provider.ConsumeData(data_a, data_a_len);
116+
arith_uint6144 a_uint{data_a};
117+
Num3072 a_num{data_a};
118+
119+
uint8_t data_b[384] = {0};
120+
provider.ConsumeData(data_b, 384);
121+
arith_uint6144 b_uint{data_b};
122+
Num3072 b_num{data_b};
123+
124+
// Multiply the first number with the second, in both representations.
125+
a_num.Multiply(b_num);
126+
a_uint *= b_uint;
127+
Reduce(a_uint);
128+
129+
// Serialize both to bytes and compare.
130+
uint8_t buf_num[384], buf_uint[384];
131+
a_num.ToBytes(buf_num);
132+
a_uint.Serialize(buf_uint);
133+
assert(std::ranges::equal(buf_num, buf_uint));
134+
}
135+
136+
FUZZ_TARGET(num3072_inv)
137+
{
138+
// Test inversion
139+
140+
FuzzedDataProvider provider{buffer.data(), buffer.size()};
141+
142+
// Read a 3072-bit number from fuzz input, and construct arith_uint6144
143+
// and Num3072 objects with the read values.
144+
uint8_t data[384] = {0};
145+
provider.ConsumeData(data, 384);
146+
Num3072 num{data};
147+
arith_uint6144 uint{data};
148+
149+
// Bail out if the number has no inverse.
150+
if ((uint == ZERO) || (uint == MODULUS)) return;
151+
152+
// Compute the inverse of the Num3072 object.
153+
Num3072 inv;
154+
inv.SetToOne();
155+
inv.Divide(num);
156+
157+
// Convert the computed inverse to arith_uint6144.
158+
uint8_t buf[384];
159+
inv.ToBytes(buf);
160+
arith_uint6144 uint_inv{buf};
161+
162+
// Multiply the original and the inverse, and expect 1.
163+
uint *= uint_inv;
164+
Reduce(uint);
165+
assert(uint == ONE);
166+
}
167+
12168
FUZZ_TARGET(muhash)
13169
{
14170
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};

0 commit comments

Comments
 (0)