@@ -337,6 +337,15 @@ struct StackSize {
337337 StackSize (MaxInt<uint32_t > in_sat, MaxInt<uint32_t > in_dsat) : sat(in_sat), dsat(in_dsat) {};
338338};
339339
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+
340349struct NoDupCheck {};
341350
342351} // namespace internal
@@ -360,6 +369,8 @@ struct Node {
360369 const internal::Ops ops;
361370 // ! Cached stack size bounds.
362371 const internal::StackSize ss;
372+ // ! Cached witness size bounds.
373+ const internal::WitnessSize ws;
363374 // ! Cached expression type (computed by CalcType and fed through SanitizeType).
364375 const Type typ;
365376 // ! Cached script length (computed by CalcScriptLen).
@@ -846,6 +857,56 @@ struct Node {
846857 assert (false );
847858 }
848859
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+
849910 template <typename Ctx>
850911 internal::InputResult ProduceInput (const Ctx& ctx) const {
851912 using namespace internal ;
@@ -1164,6 +1225,13 @@ struct Node {
11641225 // ! Whether no satisfaction exists for this node.
11651226 bool IsNotSatisfiable () const { return !GetStackSize (); }
11661227
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+
11671235 // ! Return the expression type.
11681236 Type GetType () const { return typ; }
11691237
@@ -1260,12 +1328,12 @@ struct Node {
12601328 bool operator ==(const Node<Key>& arg) const { return Compare (*this , arg) == 0 ; }
12611329
12621330 // 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()) {}
12691337
12701338 // Constructors with various argument combinations, which do perform the duplicate key check.
12711339 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