Differential fuzzing between rustreexo and utreexo found a mismatch on accumulator states when adding an all zero UTXO hash to the stump via Update. I've pinned the issue to the parentHash function, which takes in the left and right hashes. Due to Rust's enum capability, we can define an empty hash as just BitcoinNodeHash::Empty, but Go lacks this functionality, so if the left/right hash is all zeroes utreexo interprets it as empty and just returns right/left.
| parent hash inputs |
utreexo output |
rustreexo output |
outputs match |
left = [0;32]
right != [0;32] |
left |
SHA512/256([0;32] || right) |
❌ |
left != [0;32]
right = [0;32] |
right |
SHA512/256(left || [0;32]) |
❌ |
left != [0;32]
right != [0;32] |
SHA512/256(left || right) |
SHA512/256(left || right) |
✅ |
This happens because rustreexo' BitcoinNodeHash::Empty dereferences to [0; 32] and utreexo lacks this capability due to no enums in Go.
See bitcoinfuzz#477 for reference.
Differential fuzzing between
rustreexoandutreexofound a mismatch on accumulator states when adding an all zero UTXO hash to the stump viaUpdate. I've pinned the issue to theparentHashfunction, which takes in the left and right hashes. Due to Rust's enum capability, we can define an empty hash as justBitcoinNodeHash::Empty, but Go lacks this functionality, so if the left/right hash is all zeroesutreexointerprets it as empty and just returns right/left.utreexooutputrustreexooutputleft = [0;32]right != [0;32]leftSHA512/256([0;32] || right)left != [0;32]right = [0;32]rightSHA512/256(left || [0;32])left != [0;32]right != [0;32]SHA512/256(left || right)SHA512/256(left || right)This happens because
rustreexo'BitcoinNodeHash::Emptydereferences to[0; 32]andutreexolacks this capability due to no enums in Go.See
bitcoinfuzz#477for reference.