aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Poinsot <darosior@protonmail.com>2022-04-13 14:30:26 +0200
committerAntoine Poinsot <darosior@protonmail.com>2022-04-28 16:44:43 +0200
commit8c0f8bf7bc3750fad648af1a548517a272114bca (patch)
tree0a8ce3fc46b3534457a81f97dd156b2b3fd8941d
parentbe34d5077b2fede7404de7706362f5858c443525 (diff)
fuzz: add a Miniscript target for string representation roundtripping
Co-authored-by: Pieter Wuille <pieter.wuille@gmail.com>
-rw-r--r--src/test/fuzz/miniscript.cpp89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp
index 0788f37e55..65346a44a9 100644
--- a/src/test/fuzz/miniscript.cpp
+++ b/src/test/fuzz/miniscript.cpp
@@ -14,6 +14,74 @@
namespace {
+//! Some pre-computed data for more efficient string roundtrips.
+struct TestData {
+ typedef CPubKey Key;
+
+ // Precomputed public keys.
+ std::vector<Key> dummy_keys;
+ std::map<Key, int> dummy_key_idx_map;
+ std::map<CKeyID, Key> dummy_keys_map;
+
+ //! Set the precomputed data.
+ void Init() {
+ unsigned char keydata[32] = {1};
+ for (size_t i = 0; i < 256; i++) {
+ keydata[31] = i;
+ CKey privkey;
+ privkey.Set(keydata, keydata + 32, true);
+ const Key pubkey = privkey.GetPubKey();
+
+ dummy_keys.push_back(pubkey);
+ dummy_key_idx_map.emplace(pubkey, i);
+ dummy_keys_map.insert({pubkey.GetID(), pubkey});
+ }
+ }
+} TEST_DATA;
+
+/**
+ * Context to parse a Miniscript node to and from Script or text representation.
+ * Uses an integer (an index in the dummy keys array from the test data) as keys in order
+ * to focus on fuzzing the Miniscript nodes' test representation, not the key representation.
+ */
+struct ParserContext {
+ typedef CPubKey Key;
+
+ std::optional<std::string> ToString(const Key& key) const
+ {
+ auto it = TEST_DATA.dummy_key_idx_map.find(key);
+ if (it == TEST_DATA.dummy_key_idx_map.end()) return {};
+ uint8_t idx = it->second;
+ return HexStr(Span{&idx, 1});
+ }
+
+ template<typename I>
+ std::optional<Key> FromString(I first, I last) const {
+ if (last - first != 2) return {};
+ auto idx = ParseHex(std::string(first, last));
+ if (idx.size() != 1) return {};
+ return TEST_DATA.dummy_keys[idx[0]];
+ }
+
+ template<typename I>
+ std::optional<Key> FromPKBytes(I first, I last) const {
+ Key key;
+ key.Set(first, last);
+ if (!key.IsValid()) return {};
+ return key;
+ }
+
+ template<typename I>
+ std::optional<Key> FromPKHBytes(I first, I last) const {
+ assert(last - first == 20);
+ CKeyID keyid;
+ std::copy(first, last, keyid.begin());
+ const auto it = TEST_DATA.dummy_keys_map.find(keyid);
+ if (it == TEST_DATA.dummy_keys_map.end()) return {};
+ return it->second;
+ }
+} PARSER_CTX;
+
//! Context that implements naive conversion from/to script only, for roundtrip testing.
struct ScriptParserContext {
//! For Script roundtrip we never need the key from a key hash.
@@ -54,6 +122,27 @@ struct ScriptParserContext {
}
} SCRIPT_PARSER_CONTEXT;
+} // namespace
+
+void FuzzInit()
+{
+ ECC_Start();
+ TEST_DATA.Init();
+}
+
+/* Fuzz tests that test parsing from a string, and roundtripping via string. */
+FUZZ_TARGET_INIT(miniscript_string, FuzzInit)
+{
+ FuzzedDataProvider provider(buffer.data(), buffer.size());
+ auto str = provider.ConsumeRemainingBytesAsString();
+ auto parsed = miniscript::FromString(str, PARSER_CTX);
+ if (!parsed) return;
+
+ const auto str2 = parsed->ToString(PARSER_CTX);
+ assert(str2);
+ auto parsed2 = miniscript::FromString(*str2, PARSER_CTX);
+ assert(parsed2);
+ assert(*parsed == *parsed2);
}
/* Fuzz tests that test parsing from a script, and roundtripping via script. */