@@ -261,8 +261,6 @@ template<typename... Args> NodeRef MakeNodeRef(Args&&... args) {
261
261
struct NodeInfo {
262
262
// ! The type of this node
263
263
Fragment fragment;
264
- // ! Number of subs of this node
265
- uint8_t n_subs;
266
264
// ! The timelock value for older() and after(), the threshold value for multi() and thresh()
267
265
uint32_t k;
268
266
// ! Keys for this node, if it has some
@@ -272,15 +270,13 @@ struct NodeInfo {
272
270
// ! The type requirements for the children of this node.
273
271
std::vector<Type> subtypes;
274
272
275
- NodeInfo (Fragment frag): fragment(frag), n_subs(0 ), k(0 ) {}
276
- NodeInfo (Fragment frag, CPubKey key): fragment(frag), n_subs(0 ), k(0 ), keys({key}) {}
277
- NodeInfo (Fragment frag, uint32_t _k): fragment(frag), n_subs(0 ), k(_k) {}
278
- NodeInfo (Fragment frag, std::vector<unsigned char > h): fragment(frag), n_subs(0 ), k(0 ), hash(std::move(h)) {}
279
- NodeInfo (uint8_t subs, Fragment frag): fragment(frag), n_subs(subs), k(0 ), subtypes(subs, " " _mst) {}
280
- NodeInfo (uint8_t subs, Fragment frag, uint32_t _k): fragment(frag), n_subs(subs), k(_k), subtypes(subs, " " _mst) {}
281
- NodeInfo (std::vector<Type> subt, Fragment frag): fragment(frag), n_subs(subt.size()), k(0 ), subtypes(std::move(subt)) {}
282
- NodeInfo (std::vector<Type> subt, Fragment frag, uint32_t _k): fragment(frag), n_subs(subt.size()), k(_k), subtypes(std::move(subt)) {}
283
- NodeInfo (Fragment frag, uint32_t _k, std::vector<CPubKey> _keys): fragment(frag), n_subs(0 ), k(_k), keys(std::move(_keys)) {}
273
+ NodeInfo (Fragment frag): fragment(frag), k(0 ) {}
274
+ NodeInfo (Fragment frag, CPubKey key): fragment(frag), k(0 ), keys({key}) {}
275
+ NodeInfo (Fragment frag, uint32_t _k): fragment(frag), k(_k) {}
276
+ NodeInfo (Fragment frag, std::vector<unsigned char > h): fragment(frag), k(0 ), hash(std::move(h)) {}
277
+ NodeInfo (std::vector<Type> subt, Fragment frag): fragment(frag), k(0 ), subtypes(std::move(subt)) {}
278
+ NodeInfo (std::vector<Type> subt, Fragment frag, uint32_t _k): fragment(frag), k(_k), subtypes(std::move(subt)) {}
279
+ NodeInfo (Fragment frag, uint32_t _k, std::vector<CPubKey> _keys): fragment(frag), k(_k), keys(std::move(_keys)) {}
284
280
};
285
281
286
282
/* * Pick an index in a collection from a single byte in the fuzzer's output. */
@@ -329,54 +325,111 @@ std::optional<uint32_t> ConsumeTimeLock(FuzzedDataProvider& provider) {
329
325
* bytes as the number of keys define the index of each key in the test data.
330
326
* - For thresh(), the next byte defines the threshold value and the following one the number of subs.
331
327
*/
332
- std::optional<NodeInfo> ConsumeNodeStable (FuzzedDataProvider& provider) {
328
+ std::optional<NodeInfo> ConsumeNodeStable (FuzzedDataProvider& provider, Type type_needed) {
329
+ bool allow_B = (type_needed == " " _mst) || (type_needed << " B" _mst);
330
+ bool allow_K = (type_needed == " " _mst) || (type_needed << " K" _mst);
331
+ bool allow_V = (type_needed == " " _mst) || (type_needed << " V" _mst);
332
+ bool allow_W = (type_needed == " " _mst) || (type_needed << " W" _mst);
333
+
333
334
switch (provider.ConsumeIntegral <uint8_t >()) {
334
- case 0 : return {{Fragment::JUST_0}};
335
- case 1 : return {{Fragment::JUST_1}};
336
- case 2 : return {{Fragment::PK_K, ConsumePubKey (provider)}};
337
- case 3 : return {{Fragment::PK_H, ConsumePubKey (provider)}};
335
+ case 0 :
336
+ if (!allow_B) return {};
337
+ return {{Fragment::JUST_0}};
338
+ case 1 :
339
+ if (!allow_B) return {};
340
+ return {{Fragment::JUST_1}};
341
+ case 2 :
342
+ if (!allow_K) return {};
343
+ return {{Fragment::PK_K, ConsumePubKey (provider)}};
344
+ case 3 :
345
+ if (!allow_K) return {};
346
+ return {{Fragment::PK_H, ConsumePubKey (provider)}};
338
347
case 4 : {
348
+ if (!allow_B) return {};
339
349
const auto k = ConsumeTimeLock (provider);
340
350
if (!k) return {};
341
351
return {{Fragment::OLDER, *k}};
342
352
}
343
353
case 5 : {
354
+ if (!allow_B) return {};
344
355
const auto k = ConsumeTimeLock (provider);
345
356
if (!k) return {};
346
357
return {{Fragment::AFTER, *k}};
347
358
}
348
- case 6 : return {{Fragment::SHA256, ConsumeSha256 (provider)}};
349
- case 7 : return {{Fragment::HASH256, ConsumeHash256 (provider)}};
350
- case 8 : return {{Fragment::RIPEMD160, ConsumeRipemd160 (provider)}};
351
- case 9 : return {{Fragment::HASH160, ConsumeHash160 (provider)}};
359
+ case 6 :
360
+ if (!allow_B) return {};
361
+ return {{Fragment::SHA256, ConsumeSha256 (provider)}};
362
+ case 7 :
363
+ if (!allow_B) return {};
364
+ return {{Fragment::HASH256, ConsumeHash256 (provider)}};
365
+ case 8 :
366
+ if (!allow_B) return {};
367
+ return {{Fragment::RIPEMD160, ConsumeRipemd160 (provider)}};
368
+ case 9 :
369
+ if (!allow_B) return {};
370
+ return {{Fragment::HASH160, ConsumeHash160 (provider)}};
352
371
case 10 : {
372
+ if (!allow_B) return {};
353
373
const auto k = provider.ConsumeIntegral <uint8_t >();
354
374
const auto n_keys = provider.ConsumeIntegral <uint8_t >();
355
375
if (n_keys > 20 || k == 0 || k > n_keys) return {};
356
376
std::vector<CPubKey> keys{n_keys};
357
377
for (auto & key: keys) key = ConsumePubKey (provider);
358
378
return {{Fragment::MULTI, k, std::move (keys)}};
359
379
}
360
- case 11 : return {{3 , Fragment::ANDOR}};
361
- case 12 : return {{2 , Fragment::AND_V}};
362
- case 13 : return {{2 , Fragment::AND_B}};
363
- case 15 : return {{2 , Fragment::OR_B}};
364
- case 16 : return {{2 , Fragment::OR_C}};
365
- case 17 : return {{2 , Fragment::OR_D}};
366
- case 18 : return {{2 , Fragment::OR_I}};
380
+ case 11 :
381
+ if (!(allow_B || allow_K || allow_V)) return {};
382
+ return {{{" B" _mst, type_needed, type_needed}, Fragment::ANDOR}};
383
+ case 12 :
384
+ if (!(allow_B || allow_K || allow_V)) return {};
385
+ return {{{" V" _mst, type_needed}, Fragment::AND_V}};
386
+ case 13 :
387
+ if (!allow_B) return {};
388
+ return {{{" B" _mst, " W" _mst}, Fragment::AND_B}};
389
+ case 15 :
390
+ if (!allow_B) return {};
391
+ return {{{" B" _mst, " W" _mst}, Fragment::OR_B}};
392
+ case 16 :
393
+ if (!allow_V) return {};
394
+ return {{{" B" _mst, " V" _mst}, Fragment::OR_C}};
395
+ case 17 :
396
+ if (!allow_B) return {};
397
+ return {{{" B" _mst, " B" _mst}, Fragment::OR_D}};
398
+ case 18 :
399
+ if (!(allow_B || allow_K || allow_V)) return {};
400
+ return {{{type_needed, type_needed}, Fragment::OR_I}};
367
401
case 19 : {
402
+ if (!allow_B) return {};
368
403
auto k = provider.ConsumeIntegral <uint8_t >();
369
404
auto n_subs = provider.ConsumeIntegral <uint8_t >();
370
405
if (k == 0 || k > n_subs) return {};
371
- return {{n_subs, Fragment::THRESH, k}};
406
+ std::vector<Type> subtypes;
407
+ subtypes.reserve (n_subs);
408
+ subtypes.emplace_back (" B" _mst);
409
+ for (size_t i = 1 ; i < n_subs; ++i) subtypes.emplace_back (" W" _mst);
410
+ return {{std::move (subtypes), Fragment::THRESH, k}};
372
411
}
373
- case 20 : return {{1 , Fragment::WRAP_A}};
374
- case 21 : return {{1 , Fragment::WRAP_S}};
375
- case 22 : return {{1 , Fragment::WRAP_C}};
376
- case 23 : return {{1 , Fragment::WRAP_D}};
377
- case 24 : return {{1 , Fragment::WRAP_V}};
378
- case 25 : return {{1 , Fragment::WRAP_J}};
379
- case 26 : return {{1 , Fragment::WRAP_N}};
412
+ case 20 :
413
+ if (!allow_W) return {};
414
+ return {{{" B" _mst}, Fragment::WRAP_A}};
415
+ case 21 :
416
+ if (!allow_W) return {};
417
+ return {{{" B" _mst}, Fragment::WRAP_S}};
418
+ case 22 :
419
+ if (!allow_B) return {};
420
+ return {{{" K" _mst}, Fragment::WRAP_C}};
421
+ case 23 :
422
+ if (!allow_B) return {};
423
+ return {{{" V" _mst}, Fragment::WRAP_D}};
424
+ case 24 :
425
+ if (!allow_V) return {};
426
+ return {{{" B" _mst}, Fragment::WRAP_V}};
427
+ case 25 :
428
+ if (!allow_B) return {};
429
+ return {{{" B" _mst}, Fragment::WRAP_J}};
430
+ case 26 :
431
+ if (!allow_B) return {};
432
+ return {{{" B" _mst}, Fragment::WRAP_N}};
380
433
default :
381
434
break ;
382
435
}
@@ -709,11 +762,16 @@ std::optional<NodeInfo> ConsumeNodeSmart(FuzzedDataProvider& provider, Type type
709
762
* a NodeRef whose Type() matches the type fed to ConsumeNode.
710
763
*/
711
764
template <typename F>
712
- NodeRef GenNode (F ConsumeNode, Type root_type = " " _mst , bool strict_valid = false ) {
765
+ NodeRef GenNode (F ConsumeNode, Type root_type, bool strict_valid = false ) {
713
766
/* * A stack of miniscript Nodes being built up. */
714
767
std::vector<NodeRef> stack;
715
768
/* * The queue of instructions. */
716
769
std::vector<std::pair<Type, std::optional<NodeInfo>>> todo{{root_type, {}}};
770
+ /* * Predict the number of (static) script ops. */
771
+ uint32_t ops{0 };
772
+ /* * Predict the total script size (every unexplored subnode is counted as one, as every leaf is
773
+ * at least one script byte). */
774
+ uint32_t scriptsize{1 };
717
775
718
776
while (!todo.empty ()) {
719
777
// The expected type we have to construct.
@@ -722,6 +780,78 @@ NodeRef GenNode(F ConsumeNode, Type root_type = ""_mst, bool strict_valid = fals
722
780
// Fragment/children have not been decided yet. Decide them.
723
781
auto node_info = ConsumeNode (type_needed);
724
782
if (!node_info) return {};
783
+ // Update predicted resource limits. Since every leaf Miniscript node is at least one
784
+ // byte long, we move one byte from each child to their parent. A similar technique is
785
+ // used in the miniscript::internal::Parse function to prevent runaway string parsing.
786
+ scriptsize += miniscript::internal::ComputeScriptLen (node_info->fragment , " " _mst, node_info->subtypes .size (), node_info->k , node_info->subtypes .size (), node_info->keys .size ()) - 1 ;
787
+ if (scriptsize > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return {};
788
+ switch (node_info->fragment ) {
789
+ case Fragment::JUST_0:
790
+ case Fragment::JUST_1:
791
+ break ;
792
+ case Fragment::PK_K:
793
+ break ;
794
+ case Fragment::PK_H:
795
+ ops += 3 ;
796
+ break ;
797
+ case Fragment::OLDER:
798
+ case Fragment::AFTER:
799
+ ops += 1 ;
800
+ break ;
801
+ case Fragment::RIPEMD160:
802
+ case Fragment::SHA256:
803
+ case Fragment::HASH160:
804
+ case Fragment::HASH256:
805
+ ops += 4 ;
806
+ break ;
807
+ case Fragment::ANDOR:
808
+ ops += 3 ;
809
+ break ;
810
+ case Fragment::AND_V:
811
+ break ;
812
+ case Fragment::AND_B:
813
+ case Fragment::OR_B:
814
+ ops += 1 ;
815
+ break ;
816
+ case Fragment::OR_C:
817
+ ops += 2 ;
818
+ break ;
819
+ case Fragment::OR_D:
820
+ ops += 3 ;
821
+ break ;
822
+ case Fragment::OR_I:
823
+ ops += 3 ;
824
+ break ;
825
+ case Fragment::THRESH:
826
+ ops += node_info->subtypes .size ();
827
+ break ;
828
+ case Fragment::MULTI:
829
+ ops += 1 ;
830
+ break ;
831
+ case Fragment::WRAP_A:
832
+ ops += 2 ;
833
+ break ;
834
+ case Fragment::WRAP_S:
835
+ ops += 1 ;
836
+ break ;
837
+ case Fragment::WRAP_C:
838
+ ops += 1 ;
839
+ break ;
840
+ case Fragment::WRAP_D:
841
+ ops += 3 ;
842
+ break ;
843
+ case Fragment::WRAP_V:
844
+ // We don't account for OP_VERIFY here; that will be corrected for when the actual
845
+ // node is constructed below.
846
+ break ;
847
+ case Fragment::WRAP_J:
848
+ ops += 4 ;
849
+ break ;
850
+ case Fragment::WRAP_N:
851
+ ops += 1 ;
852
+ break ;
853
+ }
854
+ if (ops > MAX_OPS_PER_SCRIPT) return {};
725
855
auto subtypes = node_info->subtypes ;
726
856
todo.back ().second = std::move (node_info);
727
857
todo.reserve (todo.size () + subtypes.size ());
@@ -738,11 +868,11 @@ NodeRef GenNode(F ConsumeNode, Type root_type = ""_mst, bool strict_valid = fals
738
868
NodeInfo& info = *todo.back ().second ;
739
869
// Gather children from the back of stack.
740
870
std::vector<NodeRef> sub;
741
- sub.reserve (info.n_subs );
742
- for (size_t i = 0 ; i < info.n_subs ; ++i) {
743
- sub.push_back (std::move (*(stack.end () - info.n_subs + i)));
871
+ sub.reserve (info.subtypes . size () );
872
+ for (size_t i = 0 ; i < info.subtypes . size () ; ++i) {
873
+ sub.push_back (std::move (*(stack.end () - info.subtypes . size () + i)));
744
874
}
745
- stack.erase (stack.end () - info.n_subs , stack.end ());
875
+ stack.erase (stack.end () - info.subtypes . size () , stack.end ());
746
876
// Construct new NodeRef.
747
877
NodeRef node;
748
878
if (info.keys .empty ()) {
@@ -753,17 +883,29 @@ NodeRef GenNode(F ConsumeNode, Type root_type = ""_mst, bool strict_valid = fals
753
883
node = MakeNodeRef (info.fragment , std::move (info.keys ), info.k );
754
884
}
755
885
// Verify acceptability.
756
- if (!node || ! (node->GetType () << type_needed) ) {
886
+ if (!node || (node->GetType () & " KVWB " _mst) == " " _mst ) {
757
887
assert (!strict_valid);
758
888
return {};
759
889
}
890
+ if (!(type_needed == " " _mst)) {
891
+ assert (node->GetType () << type_needed);
892
+ }
760
893
if (!node->IsValid ()) return {};
894
+ // Update resource predictions.
895
+ if (node->fragment == Fragment::WRAP_V && node->subs [0 ]->GetType () << " x" _mst) {
896
+ ops += 1 ;
897
+ scriptsize += 1 ;
898
+ }
899
+ if (ops > MAX_OPS_PER_SCRIPT) return {};
900
+ if (scriptsize > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return {};
761
901
// Move it to the stack.
762
902
stack.push_back (std::move (node));
763
903
todo.pop_back ();
764
904
}
765
905
}
766
906
assert (stack.size () == 1 );
907
+ assert (stack[0 ]->GetStaticOps () == ops);
908
+ assert (stack[0 ]->ScriptSize () == scriptsize);
767
909
stack[0 ]->DuplicateKeyCheck (KEY_COMP);
768
910
return std::move (stack[0 ]);
769
911
}
@@ -921,9 +1063,9 @@ void FuzzInitSmart()
921
1063
FUZZ_TARGET_INIT (miniscript_stable, FuzzInit)
922
1064
{
923
1065
FuzzedDataProvider provider (buffer.data (), buffer.size ());
924
- TestNode (GenNode ([&](Type) {
925
- return ConsumeNodeStable (provider);
926
- }), provider);
1066
+ TestNode (GenNode ([&](Type needed_type ) {
1067
+ return ConsumeNodeStable (provider, needed_type );
1068
+ }, " " _mst ), provider);
927
1069
}
928
1070
929
1071
/* * Fuzz target that runs TestNode on nodes generated using ConsumeNodeSmart. */
0 commit comments