Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
fuzz_target: [deser_net_msg, deserialize_address, deserialize_amount, deserialize_block, deserialize_psbt, deserialize_script, deserialize_transaction, outpoint_string, uint128_fuzz, script_bytes_to_asm_fmt]
fuzz_target: [deser_net_msg, deserialize_address, deserialize_amount, deserialize_block, deserialize_psbt, deserialize_script, deserialize_transaction, deserialize_witness, outpoint_string, uint128_fuzz, script_bytes_to_asm_fmt]
steps:
- name: Install test dependencies
run: sudo apt-get update -y && sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc libiberty-dev
Expand Down
4 changes: 4 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,7 @@ path = "fuzz_targets/uint128_fuzz.rs"
[[bin]]
name = "script_bytes_to_asm_fmt"
path = "fuzz_targets/script_bytes_to_asm_fmt.rs"

[[bin]]
name = "deserialize_witness"
path = "fuzz_targets/deserialize_witness.rs"
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/deserialize_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn do_test(data: &[u8]) {
let len = ser.len();
let calculated_weight = tx.get_weight();
for input in &mut tx.input {
input.witness = vec![];
input.witness = bitcoin::blockdata::witness::Witness::default();
}
let no_witness_len = bitcoin::consensus::encode::serialize(&tx).len();
// For 0-input transactions, `no_witness_len` will be incorrect because
Expand Down
59 changes: 59 additions & 0 deletions fuzz/fuzz_targets/deserialize_witness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
extern crate bitcoin;

use bitcoin::consensus::{serialize, deserialize};
use bitcoin::blockdata::witness::Witness;

fn do_test(data: &[u8]) {
let w: Result<Witness, _> = deserialize(data);
if let Ok(witness) = w {
let serialized = serialize(&witness);
assert_eq!(data, serialized);
}
}

#[cfg(feature = "afl")]
#[macro_use] extern crate afl;
#[cfg(feature = "afl")]
fn main() {
fuzz!(|data| {
do_test(&data);
});
}

#[cfg(feature = "honggfuzz")]
#[macro_use] extern crate honggfuzz;
#[cfg(feature = "honggfuzz")]
fn main() {
loop {
fuzz!(|data| {
do_test(data);
});
}
}

#[cfg(test)]
mod tests {
fn extend_vec_from_hex(hex: &str, out: &mut Vec<u8>) {
let mut b = 0;
for (idx, c) in hex.as_bytes().iter().enumerate() {
b <<= 4;
match *c {
b'A'..=b'F' => b |= c - b'A' + 10,
b'a'..=b'f' => b |= c - b'a' + 10,
b'0'..=b'9' => b |= c - b'0',
_ => panic!("Bad hex"),
}
if (idx & 1) == 1 {
out.push(b);
b = 0;
}
}
}

#[test]
fn duplicate_crash() {
let mut a = Vec::new();
extend_vec_from_hex("00", &mut a);
super::do_test(&a);
}
}
5 changes: 3 additions & 2 deletions src/blockdata/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,10 @@ impl Block {
o.script_pubkey[0..6] == [0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed] }) {
let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap();
// witness reserved value is in coinbase input witness
if coinbase.input[0].witness.len() == 1 && coinbase.input[0].witness[0].len() == 32 {
let witness_vec: Vec<_> = coinbase.input[0].witness.iter().collect();
if witness_vec.len() == 1 && witness_vec[0].len() == 32 {
match self.witness_root() {
Some(witness_root) => return commitment == Self::compute_witness_commitment(&witness_root, coinbase.input[0].witness[0].as_slice()),
Some(witness_root) => return commitment == Self::compute_witness_commitment(&witness_root, witness_vec[0]),
None => return false,
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/blockdata/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use blockdata::opcodes;
use blockdata::script;
use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
use blockdata::block::{Block, BlockHeader};
use blockdata::witness::Witness;
use network::constants::Network;
use util::uint::Uint256;

Expand Down Expand Up @@ -93,7 +94,7 @@ fn bitcoin_genesis_tx() -> Transaction {
previous_output: OutPoint::null(),
script_sig: in_script,
sequence: MAX_SEQUENCE,
witness: vec![],
witness: Witness::default(),
});

// Outputs
Expand Down
1 change: 1 addition & 0 deletions src/blockdata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ pub mod opcodes;
pub mod script;
pub mod transaction;
pub mod block;
pub mod witness;

22 changes: 11 additions & 11 deletions src/blockdata/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use util::endian;
use blockdata::constants::WITNESS_SCALE_FACTOR;
#[cfg(feature="bitcoinconsensus")] use blockdata::script;
use blockdata::script::Script;
use blockdata::witness::Witness;
use consensus::{encode, Decodable, Encodable};
use consensus::encode::MAX_VEC_SIZE;
use hash_types::{SigHash, Txid, Wtxid};
Expand Down Expand Up @@ -197,7 +198,7 @@ pub struct TxIn {
/// Encodable/Decodable, as it is (de)serialized at the end of the full
/// Transaction. It *is* (de)serialized with the rest of the TxIn in other
/// (de)serialization routines.
pub witness: Vec<Vec<u8>>
pub witness: Witness
}

impl Default for TxIn {
Expand All @@ -206,7 +207,7 @@ impl Default for TxIn {
previous_output: OutPoint::default(),
script_sig: Script::new(),
sequence: u32::max_value(),
witness: Vec::new(),
witness: Witness::default(),
}
}
}
Expand Down Expand Up @@ -280,7 +281,7 @@ impl Transaction {
let cloned_tx = Transaction {
version: self.version,
lock_time: self.lock_time,
input: self.input.iter().map(|txin| TxIn { script_sig: Script::new(), witness: vec![], .. *txin }).collect(),
input: self.input.iter().map(|txin| TxIn { script_sig: Script::new(), witness: Witness::default(), .. *txin }).collect(),
output: self.output.clone(),
};
cloned_tx.txid().into()
Expand Down Expand Up @@ -357,7 +358,7 @@ impl Transaction {
previous_output: self.input[input_index].previous_output,
script_sig: script_pubkey.clone(),
sequence: self.input[input_index].sequence,
witness: vec![],
witness: Witness::default(),
}];
} else {
tx.input = Vec::with_capacity(self.input.len());
Expand All @@ -366,7 +367,7 @@ impl Transaction {
previous_output: input.previous_output,
script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() },
sequence: if n != input_index && (sighash == EcdsaSigHashType::Single || sighash == EcdsaSigHashType::None) { 0 } else { input.sequence },
witness: vec![],
witness: Witness::default(),
});
}
}
Expand Down Expand Up @@ -473,10 +474,7 @@ impl Transaction {
input.script_sig.len());
if !input.witness.is_empty() {
inputs_with_witnesses += 1;
input_weight += VarInt(input.witness.len() as u64).len();
for elem in &input.witness {
input_weight += VarInt(elem.len() as u64).len() + elem.len();
}
input_weight += input.witness.serialized_len();
}
}
let mut output_size = 0;
Expand Down Expand Up @@ -578,7 +576,7 @@ impl Decodable for TxIn {
previous_output: Decodable::consensus_decode(&mut d)?,
script_sig: Decodable::consensus_decode(&mut d)?,
sequence: Decodable::consensus_decode(d)?,
witness: vec![],
witness: Witness::default(),
})
}
}
Expand Down Expand Up @@ -1471,7 +1469,9 @@ mod tests {
}).is_err());

// test that we get a failure if we corrupt a signature
spending.input[1].witness[0][10] = 42;
let mut witness: Vec<_> = spending.input[1].witness.iter().map(|el| el.to_vec()).collect();
witness[0][10] = 42;
spending.input[1].witness = witness.into();
match spending.verify(|point: &OutPoint| {
if let Some(tx) = spent3.remove(&point.txid) {
return tx.output.get(point.vout as usize).cloned();
Expand Down
Loading