@@ -337,6 +337,15 @@ struct StackSize {
337
337
StackSize (MaxInt<uint32_t > in_sat, MaxInt<uint32_t > in_dsat) : sat(in_sat), dsat(in_dsat) {};
338
338
};
339
339
340
+ struct WitnessSize {
341
+ // ! Maximum witness size to satisfy;
342
+ MaxInt<uint32_t > sat;
343
+ // ! Maximum witness size to dissatisfy;
344
+ MaxInt<uint32_t > dsat;
345
+
346
+ WitnessSize (MaxInt<uint32_t > in_sat, MaxInt<uint32_t > in_dsat) : sat(in_sat), dsat(in_dsat) {};
347
+ };
348
+
340
349
struct NoDupCheck {};
341
350
342
351
} // namespace internal
@@ -360,6 +369,8 @@ struct Node {
360
369
const internal::Ops ops;
361
370
// ! Cached stack size bounds.
362
371
const internal::StackSize ss;
372
+ // ! Cached witness size bounds.
373
+ const internal::WitnessSize ws;
363
374
// ! Cached expression type (computed by CalcType and fed through SanitizeType).
364
375
const Type typ;
365
376
// ! Cached script length (computed by CalcScriptLen).
@@ -846,6 +857,56 @@ struct Node {
846
857
assert (false );
847
858
}
848
859
860
+ internal::WitnessSize CalcWitnessSize () const {
861
+ switch (fragment) {
862
+ case Fragment::JUST_0: return {{}, 0 };
863
+ case Fragment::JUST_1:
864
+ case Fragment::OLDER:
865
+ case Fragment::AFTER: return {0 , {}};
866
+ case Fragment::PK_K: return {1 + 72 , 1 };
867
+ case Fragment::PK_H: return {1 + 72 + 1 + 33 , 1 + 1 + 33 };
868
+ case Fragment::SHA256:
869
+ case Fragment::RIPEMD160:
870
+ case Fragment::HASH256:
871
+ case Fragment::HASH160: return {1 + 32 , {}};
872
+ case Fragment::ANDOR: {
873
+ const auto sat{(subs[0 ]->ws .sat + subs[1 ]->ws .sat ) | (subs[0 ]->ws .dsat + subs[2 ]->ws .sat )};
874
+ const auto dsat{subs[0 ]->ws .dsat + subs[2 ]->ws .dsat };
875
+ return {sat, dsat};
876
+ }
877
+ case Fragment::AND_V: return {subs[0 ]->ws .sat + subs[1 ]->ws .sat , {}};
878
+ case Fragment::AND_B: return {subs[0 ]->ws .sat + subs[1 ]->ws .sat , subs[0 ]->ws .dsat + subs[1 ]->ws .dsat };
879
+ case Fragment::OR_B: {
880
+ const auto sat{(subs[0 ]->ws .dsat + subs[1 ]->ws .sat ) | (subs[0 ]->ws .sat + subs[1 ]->ws .dsat )};
881
+ const auto dsat{subs[0 ]->ws .dsat + subs[1 ]->ws .dsat };
882
+ return {sat, dsat};
883
+ }
884
+ case Fragment::OR_C: return {subs[0 ]->ws .sat | (subs[0 ]->ws .dsat + subs[1 ]->ws .sat ), {}};
885
+ case Fragment::OR_D: return {subs[0 ]->ws .sat | (subs[0 ]->ws .dsat + subs[1 ]->ws .sat ), subs[0 ]->ws .dsat + subs[1 ]->ws .dsat };
886
+ case Fragment::OR_I: return {(subs[0 ]->ws .sat + 1 + 1 ) | (subs[1 ]->ws .sat + 1 ), (subs[0 ]->ws .dsat + 1 + 1 ) | (subs[1 ]->ws .dsat + 1 )};
887
+ case Fragment::MULTI: return {k * (1 + 72 ) + 1 , k + 1 };
888
+ case Fragment::WRAP_A:
889
+ case Fragment::WRAP_N:
890
+ case Fragment::WRAP_S:
891
+ case Fragment::WRAP_C: return subs[0 ]->ws ;
892
+ case Fragment::WRAP_D: return {1 + 1 + subs[0 ]->ws .sat , 1 };
893
+ case Fragment::WRAP_V: return {subs[0 ]->ws .sat , {}};
894
+ case Fragment::WRAP_J: return {subs[0 ]->ws .sat , 1 };
895
+ case Fragment::THRESH: {
896
+ auto sats = Vector (internal::MaxInt<uint32_t >(0 ));
897
+ for (const auto & sub : subs) {
898
+ auto next_sats = Vector (sats[0 ] + sub->ws .dsat );
899
+ for (size_t j = 1 ; j < sats.size (); ++j) next_sats.push_back ((sats[j] + sub->ws .dsat ) | (sats[j - 1 ] + sub->ws .sat ));
900
+ next_sats.push_back (sats[sats.size () - 1 ] + sub->ws .sat );
901
+ sats = std::move (next_sats);
902
+ }
903
+ assert (k <= sats.size ());
904
+ return {sats[k], sats[0 ]};
905
+ }
906
+ }
907
+ assert (false );
908
+ }
909
+
849
910
template <typename Ctx>
850
911
internal::InputResult ProduceInput (const Ctx& ctx) const {
851
912
using namespace internal ;
@@ -1164,6 +1225,13 @@ struct Node {
1164
1225
// ! Whether no satisfaction exists for this node.
1165
1226
bool IsNotSatisfiable () const { return !GetStackSize (); }
1166
1227
1228
+ /* * Return the maximum size in bytes of a witness to satisfy this script non-malleably. Note this does
1229
+ * not include the witness script push. */
1230
+ std::optional<uint32_t > GetWitnessSize () const {
1231
+ if (!ws.sat .valid ) return {};
1232
+ return ws.sat .value ;
1233
+ }
1234
+
1167
1235
// ! Return the expression type.
1168
1236
Type GetType () const { return typ; }
1169
1237
@@ -1260,12 +1328,12 @@ struct Node {
1260
1328
bool operator ==(const Node<Key>& arg) const { return Compare (*this , arg) == 0 ; }
1261
1329
1262
1330
// Constructors with various argument combinations, which bypass the duplicate key check.
1263
- Node (internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<unsigned char > arg, uint32_t val = 0 ) : fragment(nt), k(val), data(std::move(arg)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1264
- Node (internal::NoDupCheck, Fragment nt, std::vector<unsigned char > arg, uint32_t val = 0 ) : fragment(nt), k(val), data(std::move(arg)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1265
- Node (internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<Key> key, uint32_t val = 0 ) : fragment(nt), k(val), keys(std::move(key)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1266
- Node (internal::NoDupCheck, Fragment nt, std::vector<Key> key, uint32_t val = 0 ) : fragment(nt), k(val), keys(std::move(key)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1267
- Node (internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, uint32_t val = 0 ) : fragment(nt), k(val), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1268
- Node (internal::NoDupCheck, Fragment nt, uint32_t val = 0 ) : fragment(nt), k(val), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1331
+ Node (internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<unsigned char > arg, uint32_t val = 0 ) : fragment(nt), k(val), data(std::move(arg)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1332
+ Node (internal::NoDupCheck, Fragment nt, std::vector<unsigned char > arg, uint32_t val = 0 ) : fragment(nt), k(val), data(std::move(arg)), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1333
+ Node (internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<Key> key, uint32_t val = 0 ) : fragment(nt), k(val), keys(std::move(key)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1334
+ Node (internal::NoDupCheck, Fragment nt, std::vector<Key> key, uint32_t val = 0 ) : fragment(nt), k(val), keys(std::move(key)), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1335
+ Node (internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, uint32_t val = 0 ) : fragment(nt), k(val), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1336
+ Node (internal::NoDupCheck, Fragment nt, uint32_t val = 0 ) : fragment(nt), k(val), ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
1269
1337
1270
1338
// Constructors with various argument combinations, which do perform the duplicate key check.
1271
1339
template <typename Ctx> Node (const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<unsigned char > arg, uint32_t val = 0 ) : Node(internal::NoDupCheck{}, nt, std::move(sub), std::move(arg), val) { DuplicateKeyCheck (ctx); }
0 commit comments