@@ -267,7 +267,7 @@ CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider,
267
267
const auto amount = fuzzed_data_provider.ConsumeIntegralInRange <CAmount>(-10 , 50 * COIN + 10 );
268
268
const auto script_pk = p2wsh_op_true ?
269
269
P2WSH_OP_TRUE :
270
- ConsumeScript (fuzzed_data_provider, /* max_length */ 128 , /* maybe_p2wsh */ true );
270
+ ConsumeScript (fuzzed_data_provider, /* maybe_p2wsh= */ true );
271
271
tx_mut.vout .emplace_back (amount, script_pk);
272
272
}
273
273
return tx_mut;
@@ -283,10 +283,63 @@ CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, co
283
283
return ret;
284
284
}
285
285
286
- CScript ConsumeScript (FuzzedDataProvider& fuzzed_data_provider, const std::optional< size_t >& max_length, const bool maybe_p2wsh) noexcept
286
+ CScript ConsumeScript (FuzzedDataProvider& fuzzed_data_provider, const bool maybe_p2wsh) noexcept
287
287
{
288
- const std::vector<uint8_t > b = ConsumeRandomLengthByteVector (fuzzed_data_provider, max_length);
289
- CScript r_script{b.begin (), b.end ()};
288
+ CScript r_script{};
289
+ {
290
+ // Keep a buffer of bytes to allow the fuzz engine to produce smaller
291
+ // inputs to generate CScripts with repeated data.
292
+ static constexpr unsigned MAX_BUFFER_SZ{128 };
293
+ std::vector<uint8_t > buffer (MAX_BUFFER_SZ, uint8_t {' a' });
294
+ while (fuzzed_data_provider.ConsumeBool ()) {
295
+ CallOneOf (
296
+ fuzzed_data_provider,
297
+ [&] {
298
+ // Insert byte vector directly to allow malformed or unparsable scripts
299
+ r_script.insert (r_script.end (), buffer.begin (), buffer.begin () + fuzzed_data_provider.ConsumeIntegralInRange (0U , MAX_BUFFER_SZ));
300
+ },
301
+ [&] {
302
+ // Push a byte vector from the buffer
303
+ r_script << std::vector<uint8_t >{buffer.begin (), buffer.begin () + fuzzed_data_provider.ConsumeIntegralInRange (0U , MAX_BUFFER_SZ)};
304
+ },
305
+ [&] {
306
+ // Push multisig
307
+ // There is a special case for this to aid the fuzz engine
308
+ // navigate the highly structured multisig format.
309
+ r_script << fuzzed_data_provider.ConsumeIntegralInRange <int64_t >(0 , 22 );
310
+ int num_data{fuzzed_data_provider.ConsumeIntegralInRange (1 , 22 )};
311
+ std::vector<uint8_t > pubkey_comp{buffer.begin (), buffer.begin () + CPubKey::COMPRESSED_SIZE};
312
+ pubkey_comp.front () = fuzzed_data_provider.ConsumeIntegralInRange (2 , 3 ); // Set first byte for GetLen() to pass
313
+ std::vector<uint8_t > pubkey_uncomp{buffer.begin (), buffer.begin () + CPubKey::SIZE};
314
+ pubkey_uncomp.front () = fuzzed_data_provider.ConsumeIntegralInRange (4 , 7 ); // Set first byte for GetLen() to pass
315
+ while (num_data--) {
316
+ auto & pubkey{fuzzed_data_provider.ConsumeBool () ? pubkey_uncomp : pubkey_comp};
317
+ if (fuzzed_data_provider.ConsumeBool ()) {
318
+ pubkey.back () = num_data; // Make each pubkey different
319
+ }
320
+ r_script << pubkey;
321
+ }
322
+ r_script << fuzzed_data_provider.ConsumeIntegralInRange <int64_t >(0 , 22 );
323
+ },
324
+ [&] {
325
+ // Mutate the buffer
326
+ const auto vec{ConsumeRandomLengthByteVector (fuzzed_data_provider, /* max_length=*/ MAX_BUFFER_SZ)};
327
+ std::copy (vec.begin (), vec.end (), buffer.begin ());
328
+ },
329
+ [&] {
330
+ // Push an integral
331
+ r_script << fuzzed_data_provider.ConsumeIntegral <int64_t >();
332
+ },
333
+ [&] {
334
+ // Push an opcode
335
+ r_script << ConsumeOpcodeType (fuzzed_data_provider);
336
+ },
337
+ [&] {
338
+ // Push a scriptnum
339
+ r_script << ConsumeScriptNum (fuzzed_data_provider);
340
+ });
341
+ }
342
+ }
290
343
if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool ()) {
291
344
uint256 script_hash;
292
345
CSHA256 ().Write (r_script.data (), r_script.size ()).Finalize (script_hash.begin ());
0 commit comments