|
14 | 14 |
|
15 | 15 | namespace {
|
16 | 16 |
|
| 17 | +//! Some pre-computed data for more efficient string roundtrips. |
| 18 | +struct TestData { |
| 19 | + typedef CPubKey Key; |
| 20 | + |
| 21 | + // Precomputed public keys. |
| 22 | + std::vector<Key> dummy_keys; |
| 23 | + std::map<Key, int> dummy_key_idx_map; |
| 24 | + std::map<CKeyID, Key> dummy_keys_map; |
| 25 | + |
| 26 | + //! Set the precomputed data. |
| 27 | + void Init() { |
| 28 | + unsigned char keydata[32] = {1}; |
| 29 | + for (size_t i = 0; i < 256; i++) { |
| 30 | + keydata[31] = i; |
| 31 | + CKey privkey; |
| 32 | + privkey.Set(keydata, keydata + 32, true); |
| 33 | + const Key pubkey = privkey.GetPubKey(); |
| 34 | + |
| 35 | + dummy_keys.push_back(pubkey); |
| 36 | + dummy_key_idx_map.emplace(pubkey, i); |
| 37 | + dummy_keys_map.insert({pubkey.GetID(), pubkey}); |
| 38 | + } |
| 39 | + } |
| 40 | +} TEST_DATA; |
| 41 | + |
| 42 | +/** |
| 43 | + * Context to parse a Miniscript node to and from Script or text representation. |
| 44 | + * Uses an integer (an index in the dummy keys array from the test data) as keys in order |
| 45 | + * to focus on fuzzing the Miniscript nodes' test representation, not the key representation. |
| 46 | + */ |
| 47 | +struct ParserContext { |
| 48 | + typedef CPubKey Key; |
| 49 | + |
| 50 | + std::optional<std::string> ToString(const Key& key) const |
| 51 | + { |
| 52 | + auto it = TEST_DATA.dummy_key_idx_map.find(key); |
| 53 | + if (it == TEST_DATA.dummy_key_idx_map.end()) return {}; |
| 54 | + uint8_t idx = it->second; |
| 55 | + return HexStr(Span{&idx, 1}); |
| 56 | + } |
| 57 | + |
| 58 | + template<typename I> |
| 59 | + std::optional<Key> FromString(I first, I last) const { |
| 60 | + if (last - first != 2) return {}; |
| 61 | + auto idx = ParseHex(std::string(first, last)); |
| 62 | + if (idx.size() != 1) return {}; |
| 63 | + return TEST_DATA.dummy_keys[idx[0]]; |
| 64 | + } |
| 65 | + |
| 66 | + template<typename I> |
| 67 | + std::optional<Key> FromPKBytes(I first, I last) const { |
| 68 | + Key key; |
| 69 | + key.Set(first, last); |
| 70 | + if (!key.IsValid()) return {}; |
| 71 | + return key; |
| 72 | + } |
| 73 | + |
| 74 | + template<typename I> |
| 75 | + std::optional<Key> FromPKHBytes(I first, I last) const { |
| 76 | + assert(last - first == 20); |
| 77 | + CKeyID keyid; |
| 78 | + std::copy(first, last, keyid.begin()); |
| 79 | + const auto it = TEST_DATA.dummy_keys_map.find(keyid); |
| 80 | + if (it == TEST_DATA.dummy_keys_map.end()) return {}; |
| 81 | + return it->second; |
| 82 | + } |
| 83 | +} PARSER_CTX; |
| 84 | + |
17 | 85 | //! Context that implements naive conversion from/to script only, for roundtrip testing.
|
18 | 86 | struct ScriptParserContext {
|
19 | 87 | //! For Script roundtrip we never need the key from a key hash.
|
@@ -54,6 +122,27 @@ struct ScriptParserContext {
|
54 | 122 | }
|
55 | 123 | } SCRIPT_PARSER_CONTEXT;
|
56 | 124 |
|
| 125 | +} // namespace |
| 126 | + |
| 127 | +void FuzzInit() |
| 128 | +{ |
| 129 | + ECC_Start(); |
| 130 | + TEST_DATA.Init(); |
| 131 | +} |
| 132 | + |
| 133 | +/* Fuzz tests that test parsing from a string, and roundtripping via string. */ |
| 134 | +FUZZ_TARGET_INIT(miniscript_string, FuzzInit) |
| 135 | +{ |
| 136 | + FuzzedDataProvider provider(buffer.data(), buffer.size()); |
| 137 | + auto str = provider.ConsumeRemainingBytesAsString(); |
| 138 | + auto parsed = miniscript::FromString(str, PARSER_CTX); |
| 139 | + if (!parsed) return; |
| 140 | + |
| 141 | + const auto str2 = parsed->ToString(PARSER_CTX); |
| 142 | + assert(str2); |
| 143 | + auto parsed2 = miniscript::FromString(*str2, PARSER_CTX); |
| 144 | + assert(parsed2); |
| 145 | + assert(*parsed == *parsed2); |
57 | 146 | }
|
58 | 147 |
|
59 | 148 | /* Fuzz tests that test parsing from a script, and roundtripping via script. */
|
|
0 commit comments