aboutsummaryrefslogtreecommitdiff
path: root/src/test/fuzz/miniscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fuzz/miniscript.cpp')
-rw-r--r--src/test/fuzz/miniscript.cpp61
1 files changed, 35 insertions, 26 deletions
diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp
index 1c4596b6fc..8c73edfa9d 100644
--- a/src/test/fuzz/miniscript.cpp
+++ b/src/test/fuzz/miniscript.cpp
@@ -70,6 +70,7 @@ struct TestData {
sig.push_back(1); // SIGHASH_ALL
dummy_sigs.insert({pubkey, {sig, i & 1}});
assert(privkey.SignSchnorr(MESSAGE_HASH, schnorr_sig, nullptr, EMPTY_AUX));
+ schnorr_sig.push_back(1); // Maximally-sized signature has sighash byte
schnorr_sigs.emplace(XOnlyPubKey{pubkey}, std::make_pair(std::move(schnorr_sig), i & 1));
std::vector<unsigned char> hash;
@@ -113,7 +114,9 @@ struct TestData {
struct ParserContext {
typedef CPubKey Key;
- MsCtx script_ctx{MsCtx::P2WSH};
+ const MsCtx script_ctx;
+
+ constexpr ParserContext(MsCtx ctx) noexcept : script_ctx(ctx) {}
bool KeyCompare(const Key& a, const Key& b) const {
return a < b;
@@ -178,11 +181,13 @@ struct ParserContext {
MsCtx MsContext() const {
return script_ctx;
}
-} PARSER_CTX;
+};
//! Context that implements naive conversion from/to script only, for roundtrip testing.
struct ScriptParserContext {
- MsCtx script_ctx{MsCtx::P2WSH};
+ const MsCtx script_ctx;
+
+ constexpr ScriptParserContext(MsCtx ctx) noexcept : script_ctx(ctx) {}
//! For Script roundtrip we never need the key from a key hash.
struct Key {
@@ -228,10 +233,13 @@ struct ScriptParserContext {
MsCtx MsContext() const {
return script_ctx;
}
-} SCRIPT_PARSER_CONTEXT;
+};
//! Context to produce a satisfaction for a Miniscript node using the pre-computed data.
-struct SatisfierContext: ParserContext {
+struct SatisfierContext : ParserContext {
+
+ constexpr SatisfierContext(MsCtx ctx) noexcept : ParserContext(ctx) {}
+
// Timelock challenges satisfaction. Make the value (deterministically) vary to explore different
// paths.
bool CheckAfter(uint32_t value) const { return value % 2; }
@@ -267,12 +275,10 @@ struct SatisfierContext: ParserContext {
miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {
return LookupHash(hash, preimage, TEST_DATA.hash160_preimages);
}
-} SATISFIER_CTX;
+};
//! Context to check a satisfaction against the pre-computed data.
-struct CheckerContext: BaseSignatureChecker {
- TestData *test_data;
-
+const struct CheckerContext: BaseSignatureChecker {
// Signature checker methods. Checks the right dummy signature is used.
bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& vchPubKey,
const CScript& scriptCode, SigVersion sigversion) const override
@@ -294,7 +300,7 @@ struct CheckerContext: BaseSignatureChecker {
} CHECKER_CTX;
//! Context to check for duplicates when instancing a Node.
-struct KeyComparator {
+const struct KeyComparator {
bool KeyCompare(const CPubKey& a, const CPubKey& b) const {
return a < b;
}
@@ -1027,15 +1033,15 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p
if (!node) return;
// Check that it roundtrips to text representation
- PARSER_CTX.script_ctx = script_ctx;
- std::optional<std::string> str{node->ToString(PARSER_CTX)};
+ const ParserContext parser_ctx{script_ctx};
+ std::optional<std::string> str{node->ToString(parser_ctx)};
assert(str);
- auto parsed = miniscript::FromString(*str, PARSER_CTX);
+ auto parsed = miniscript::FromString(*str, parser_ctx);
assert(parsed);
assert(*parsed == *node);
// Check consistency between script size estimation and real size.
- auto script = node->ToScript(PARSER_CTX);
+ auto script = node->ToScript(parser_ctx);
assert(node->ScriptSize() == script.size());
// Check consistency of "x" property with the script (type K is excluded, because it can end
@@ -1049,12 +1055,12 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p
if (!node->IsValidTopLevel()) return;
// Check roundtrip to script
- auto decoded = miniscript::FromScript(script, PARSER_CTX);
+ auto decoded = miniscript::FromScript(script, parser_ctx);
assert(decoded);
// Note we can't use *decoded == *node because the miniscript representation may differ, so we check that:
// - The script corresponding to that decoded form matches exactly
// - The type matches exactly
- assert(decoded->ToScript(PARSER_CTX) == script);
+ assert(decoded->ToScript(parser_ctx) == script);
assert(decoded->GetType() == node->GetType());
// Optionally pad the script or the witness in order to increase the sensitivity of the tests of
@@ -1091,7 +1097,7 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p
}
}
- SATISFIER_CTX.script_ctx = script_ctx;
+ const SatisfierContext satisfier_ctx{script_ctx};
// Get the ScriptPubKey for this script, filling spend data if it's Taproot.
TaprootBuilder builder;
@@ -1099,11 +1105,11 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p
// Run malleable satisfaction algorithm.
std::vector<std::vector<unsigned char>> stack_mal;
- const bool mal_success = node->Satisfy(SATISFIER_CTX, stack_mal, false) == miniscript::Availability::YES;
+ const bool mal_success = node->Satisfy(satisfier_ctx, stack_mal, false) == miniscript::Availability::YES;
// Run non-malleable satisfaction algorithm.
std::vector<std::vector<unsigned char>> stack_nonmal;
- const bool nonmal_success = node->Satisfy(SATISFIER_CTX, stack_nonmal, true) == miniscript::Availability::YES;
+ const bool nonmal_success = node->Satisfy(satisfier_ctx, stack_nonmal, true) == miniscript::Availability::YES;
if (nonmal_success) {
// Non-malleable satisfactions are bounded by the satisfaction size plus:
@@ -1114,6 +1120,9 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p
// If a non-malleable satisfaction exists, the malleable one must also exist, and be identical to it.
assert(mal_success);
assert(stack_nonmal == stack_mal);
+ // Compute witness size (excluding script push, control block, and witness count encoding).
+ const size_t wit_size = GetSerializeSize(stack_nonmal, PROTOCOL_VERSION) - GetSizeOfCompactSize(stack_nonmal.size());
+ assert(wit_size <= *node->GetWitnessSize());
// Test non-malleable satisfaction.
witness_nonmal.stack.insert(witness_nonmal.stack.end(), std::make_move_iterator(stack_nonmal.begin()), std::make_move_iterator(stack_nonmal.end()));
@@ -1229,13 +1238,13 @@ FUZZ_TARGET(miniscript_string, .init = FuzzInit)
if (buffer.empty()) return;
FuzzedDataProvider provider(buffer.data(), buffer.size());
auto str = provider.ConsumeBytesAsString(provider.remaining_bytes() - 1);
- PARSER_CTX.script_ctx = (MsCtx)provider.ConsumeBool();
- auto parsed = miniscript::FromString(str, PARSER_CTX);
+ const ParserContext parser_ctx{(MsCtx)provider.ConsumeBool()};
+ auto parsed = miniscript::FromString(str, parser_ctx);
if (!parsed) return;
- const auto str2 = parsed->ToString(PARSER_CTX);
+ const auto str2 = parsed->ToString(parser_ctx);
assert(str2);
- auto parsed2 = miniscript::FromString(*str2, PARSER_CTX);
+ auto parsed2 = miniscript::FromString(*str2, parser_ctx);
assert(parsed2);
assert(*parsed == *parsed2);
}
@@ -1247,9 +1256,9 @@ FUZZ_TARGET(miniscript_script)
const std::optional<CScript> script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
if (!script) return;
- SCRIPT_PARSER_CONTEXT.script_ctx = (MsCtx)fuzzed_data_provider.ConsumeBool();
- const auto ms = miniscript::FromScript(*script, SCRIPT_PARSER_CONTEXT);
+ const ScriptParserContext script_parser_ctx{(MsCtx)fuzzed_data_provider.ConsumeBool()};
+ const auto ms = miniscript::FromScript(*script, script_parser_ctx);
if (!ms) return;
- assert(ms->ToScript(SCRIPT_PARSER_CONTEXT) == *script);
+ assert(ms->ToScript(script_parser_ctx) == *script);
}