# Differential Fuzzing of Bitcoin implementations

**URL:** <https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208>\
**Category:** Implementation\
**Tags:** lang:rust, fuzz, miniscript\
**Created:** [November 18, 2023, 3:06pm UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208 "2023-11-18T15:06:59Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![bruno](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/bruno/32/60_2.png) [@bruno](https://delvingbitcoin.org/u/bruno)\
**Post date:** [November 18, 2023, 3:06pm UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208/1 "2023-11-18T15:06:59Z")

</div>

Hi, all!

I’m working on differential fuzzing of Bitcoin implementations/libraries ([GitHub - brunoerg/bitcoinfuzz: Differential Fuzzing of Bitcoin implementations and libraries](https://github.com/brunoerg/bitcoinfuzz)). I’m starting it with miniscript, so at this moment it’s fuzzing Core’s and rust-miniscript.

I’m openning this topic to raise ideas and get feedbacks about it.

---

<div class="post-metadata">

**Author:** ![sipa](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/sipa/32/1100_2.png) [@sipa](https://delvingbitcoin.org/u/sipa)\
**Post date:** [November 29, 2023, 11:01pm UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208/2 "2023-11-29T23:01:43Z")

</div>

Nice, and it seems you’ve discovered something too ([bug: `pk()()` is considered a valid policy · Issue #140 · sipa/miniscript · GitHub](https://github.com/sipa/miniscript/issues/140))!

---

<div class="post-metadata">

**Author:** ![bruno](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/bruno/32/60_2.png) [@bruno](https://delvingbitcoin.org/u/bruno)\
**Post date:** [December 1, 2023, 7:30pm UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208/3 "2023-12-01T19:30:21Z")

</div>

Yes, I got more crashes but I’m analyzing them before publishing them.

---

<div class="post-metadata">

**Author:** ![bruno](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/bruno/32/60_2.png) [@bruno](https://delvingbitcoin.org/u/bruno)\
**Post date:** [December 18, 2023, 6:03pm UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208/4 "2023-12-18T18:03:14Z")

</div>

Another crash has been discussed in rust-miniscript repo: [bug: some miniscripts are being pointed as invalid, but are valid · Issue #633 · rust-bitcoin/rust-miniscript · GitHub](https://github.com/rust-bitcoin/rust-miniscript/issues/633#issuecomment-1856401701)

cc: @sipa

---

<div class="post-metadata">

**Author:** ![bruno](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/bruno/32/60_2.png) [@bruno](https://delvingbitcoin.org/u/bruno)\
**Post date:** [April 15, 2024, 9:37am UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208/5 "2024-04-15T09:37:33Z")

</div>

One more bug found by it!

> <https://github.com/rust-bitcoin/rust-bitcoin/issues/2681>
>
> By applying differential fuzzing (\[bitcoinfuzz\](https://github.com/brunoerg/bitc…oinfuzz)) with rust-bitcoin and Bitcoin Core for block deserialization, I found out a bug during the transaction verification step. Basically, it's illegal to have the witness flag present and all witness stacks empty. That is, it has inputs, they have empty witnesses, but the transaction is flagged as segwit. It seems this case is not being catched properly.
> 
> Base64 to reproduce (for block deserialization): //////////+puampqalJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJqampKak4ODg4ODg4qampqVdRqampAgICAgIB/QITAAICAgICAgICAAABAABRAgICAgH9AgICAgICAgICAgICAgICAgICAgICAACRAAIAAAAAAAAAAFECAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAAApECAAIAAAAAAAAAUQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAICRAAAAAAAAFv////8AAD0A/////y3/////////AP////8AAQAAAAD///8=

---

<div class="post-metadata">

**Author:** ![bruno](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/bruno/32/60_2.png) [@bruno](https://delvingbitcoin.org/u/bruno)\
**Post date:** [June 17, 2024, 4:15pm UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208/6 "2024-06-17T16:15:50Z")

</div>

Updates!

We recently added support for `btcd` and we discovered and could reproduce more bugs.

* * *

**rust-miniscript** : Some miniscripts were unexpectedly being rejected

> <https://github.com/rust-bitcoin/rust-miniscript/issues/633>
>
> Hi, recently I started developing \[bitcoinfuzz\](https://github.com/brunoerg/bitc…oinfuzz) - differential fuzzing of Bitcoin implementations and libraries. One of the targets gets a string and checks whether it's a valid miniscript. The code I'm using to check it with \`rust-miniscript\` is:
> \`\`\`rust
> \#\[no\_mangle\]
> pub extern "C" fn rust\_miniscript\_from\_str(input: \*const c\_char) -\> bool {
> if let Ok(data) = unsafe { CStr::from\_ptr(input) }.to\_str() {
> if let Ok(\_pol) = Miniscript::\<String, Segwitv0\>::from\_str\_insane(data) {
> return true
> } else if let Ok(\_pol) = Miniscript::\<String, Tap\>::from\_str\_insane(data) {
> return true
> }
> }
> false
> }
> \`\`\`
> 
> and \`bitcoinfuzz\` is crashing (rust-miniscript returning invalid) with the following miniscripts (and other ones):
> \`\`\`
> nnnnnnnnnnnnnnnln:1
> dv:0
> lll:0
> l:1
> \`\`\`
> 
> Could I be missing something in my code or is it a bug?

**rust-bitcoin** : During witness verification, `rust-bitcoin` doesn’t check if a transaction has the witness flag but empty witnesses.

> <https://github.com/rust-bitcoin/rust-bitcoin/issues/2681>
>
> By applying differential fuzzing (\[bitcoinfuzz\](https://github.com/brunoerg/bitc…oinfuzz)) with rust-bitcoin and Bitcoin Core for block deserialization, I found out a bug during the transaction verification step. Basically, it's illegal to have the witness flag present and all witness stacks empty. That is, it has inputs, they have empty witnesses, but the transaction is flagged as segwit. It seems this case is not being catched properly.
> 
> Base64 to reproduce (for block deserialization): //////////+puampqalJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJqampKak4ODg4ODg4qampqVdRqampAgICAgIB/QITAAICAgICAgICAAABAABRAgICAgH9AgICAgICAgICAgICAgICAgICAgICAACRAAIAAAAAAAAAAFECAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAAApECAAIAAAAAAAAAUQICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAICRAAAAAAAAFv////8AAD0A/////y3/////////AP////8AAQAAAAD///8=

**btcd** : Not a bug but an API mismatch with Bitcoin Core. When decoding a transaction, Bitcoin Core fails if the input was not entirely consumed, btcd doesn’t.

> <https://github.com/btcsuite/btcd/issues/2195>
>
> Using the \`decoderawtransaction\` command (\`btcDecode\` function?) we noticed that… it does not check if the entire input was successfully consumed when decoding which is important to keep it consistent. 
> 
> To reproduce:
> \`\`\`
> decoderawtransaction "0a9a9e0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100000000010001010101a09a"
> \`\`\`
> 
> Obs.: Running same command on Bitcoin Core fails.

**Bitcoin Core/rust-miniscript** : When validating miniscripts from string, there is an inconsistence between rust-miniscript and Bitcoin Core. We noticed that Bitcoin Core accepts the usage of the `+` sign, e.g. (`l:older(+1)` , `u:after(+1)` ), because of `ParseInt64` function. However, `rust-miniscript` checks the character itself, so it only accepts “1”, “2”, “3”…“9”.

> <https://github.com/brunoerg/bitcoinfuzz/issues/34>
>
> We got a crash on \`miniscript\_string\` target due to validation of numbers. For \`…older()\`, \`after()\`, \`thresh()\` and maybe other fragments, Bitcoin Core accept the usage of the \`+\` sign, e.g. (\`l:older(+1)\`, \`u:after(+1)\`), because of \`ParseInt64\` function. However, \`rust-miniscript\` checks the character itself, so it only accepts "1", "2", "3"..."9". 
> 
> \`\`\`rs
> if !('1'..='9').contains(&ch) {
> return Err(Error::Unexpected("Number must start with a digit 1-9".to\_string()));
> }
> \`\`\`
> 
> There is a test to ensure it doesn't accept those ones:
> \`\`\`rs
> fn test\_parse\_num() {
> assert!(parse\_num("0").is\_ok());
> assert!(parse\_num("00").is\_err());
> assert!(parse\_num("0000").is\_err());
> assert!(parse\_num("06").is\_err());
> assert!(parse\_num("+6").is\_err());
> assert!(parse\_num("-6").is\_err());
> }
> \`\`\`

**rust-miniscript** : The parser function is still recursive while Core isn’t anymore. It makes some miniscripts valid for Core but rejected by rust-miniscript due to the max recursion depth. (We didn’t find this, we just could reproduce by running the harness with the seed corpus from Core)

> <https://github.com/rust-bitcoin/rust-miniscript/issues/696>
>
> Sorry if it's a dumb question, as far as I understand there is a recursion depth… limit on \`from\_slice\_delim\` to avoid running out of stack space (based on https://github.com/sipa/miniscript/pull/5) when parsing an expression with round brackets. However, the parse function from sipa/miniscript is not recursive anymore (https://github.com/sipa/miniscript/pull/68). Worths make it non-recursive here as well? I noticed that some miniscripts that can be parsed on Core fails here because of this limit. 
> 
> \`\`\`rs
> // https://github.com/sipa/miniscript/pull/5 for discussion on this number
> const MAX\_RECURSION\_DEPTH: u32 = 402;
> \`\`\`
> 
> \`\`\`rs
> impl\<'a\> Tree\<'a\> {
> /// Parse an expression with round brackets
> pub fn from\_slice(sl: &'a str) -\> Result\<(Tree\<'a\>, &'a str), Error\> {
> // Parsing TapTree or just miniscript
> Self::from\_slice\_delim(sl, 0u32, '(')
> }
> 
> pub(crate) fn from\_slice\_delim(
> mut sl: &'a str,
> depth: u32,
> delim: char,
> ) -\> Result\<(Tree\<'a\>, &'a str), Error\> {
> if depth \>= MAX\_RECURSION\_DEPTH {
> return Err(Error::MaxRecursiveDepthExceeded);
> }
> \`\`\`

---

<div class="post-metadata">

**Author:** ![bruno](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/bruno/32/60_2.png) [@bruno](https://delvingbitcoin.org/u/bruno)\
**Post date:** [June 18, 2024, 12:37pm UTC](https://delvingbitcoin.org/t/differential-fuzzing-of-bitcoin-implementations/208/7 "2024-06-18T12:37:11Z")

</div>

> <https://github.com/brunoerg/bitcoinfuzz/issues/39>
>
> \`or\_d(dv:0,0)\` is sane for Bitcoin Core (\`IsSane()\` returns true) but fails for …rust-miniscript due to "fragment «or\_d(dv:0,0)» requires its left child be a unit (outputs exactly 1 given a satisfying input)".
