/ src / test / fuzz / muhash.cpp
muhash.cpp
  1  // Copyright (c) 2020-present 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 <arith_uint256.h>
  6  #include <crypto/muhash.h>
  7  #include <span.h>
  8  #include <uint256.h>
  9  #include <test/fuzz/FuzzedDataProvider.h>
 10  #include <test/fuzz/fuzz.h>
 11  #include <test/fuzz/util.h>
 12  
 13  #include <algorithm>
 14  #include <array>
 15  #include <vector>
 16  
 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(std::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(std::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  
168  FUZZ_TARGET(muhash)
169  {
170      FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
171      std::vector<uint8_t> data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
172      std::vector<uint8_t> data2{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
173  
174      MuHash3072 muhash;
175  
176      muhash.Insert(data);
177      muhash.Insert(data2);
178  
179      constexpr uint256 initial_state_hash{"dd5ad2a105c2d29495f577245c357409002329b9f4d6182c0af3dc2f462555c8"};
180      uint256 out;
181      uint256 out2;
182      CallOneOf(
183          fuzzed_data_provider,
184          [&] {
185              // Test that MuHash result is consistent independent of order of operations
186              muhash.Finalize(out);
187  
188              muhash = MuHash3072();
189              muhash.Insert(data2);
190              muhash.Insert(data);
191              muhash.Finalize(out2);
192          },
193          [&] {
194              // Test that multiplication with the initial state never changes the finalized result
195              muhash.Finalize(out);
196              MuHash3072 muhash3;
197              muhash3 *= muhash;
198              muhash3.Finalize(out2);
199          },
200          [&] {
201              // Test that dividing a MuHash by itself brings it back to its initial state
202              muhash /= muhash;
203              muhash.Finalize(out);
204              out2 = initial_state_hash;
205          },
206          [&] {
207              // Test that removing all added elements brings the object back to its initial state
208              muhash.Remove(data);
209              muhash.Remove(data2);
210              muhash.Finalize(out);
211              out2 = initial_state_hash;
212          });
213      assert(out == out2);
214  }