Skip to content

Commit 8678bda

Browse files
committed
Ensure Message always unwraps in fuzztarget
Hashes cant be all-0s, so we can normally unwrap, but fuzztarget can generate all-0 hashes, so we have to handle it and swap for something else.
1 parent f109d13 commit 8678bda

File tree

6 files changed

+48
-28
lines changed

6 files changed

+48
-28
lines changed

src/ln/channel.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use bitcoin_hashes::sha256::Hash as Sha256;
1111
use bitcoin_hashes::hash160::Hash as Hash160;
1212

1313
use secp256k1::key::{PublicKey,SecretKey};
14-
use secp256k1::{Secp256k1,Message,Signature};
14+
use secp256k1::{Secp256k1,Signature};
1515
use secp256k1;
1616

1717
use ln::msgs;
@@ -1067,7 +1067,7 @@ impl Channel {
10671067

10681068
let funding_redeemscript = self.get_funding_redeemscript();
10691069

1070-
let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
1070+
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
10711071
let our_sig = self.secp_ctx.sign(&sighash, &self.local_keys.funding_key);
10721072

10731073
tx.input[0].witness.push(Vec::new()); // First is the multisig dummy
@@ -1104,7 +1104,7 @@ impl Channel {
11041104
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys);
11051105

11061106
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
1107-
let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
1107+
let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
11081108
let is_local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key) == keys.a_htlc_key;
11091109
Ok((htlc_redeemscript, self.secp_ctx.sign(&sighash, &our_htlc_key), is_local_tx))
11101110
}
@@ -1408,7 +1408,7 @@ impl Channel {
14081408

14091409
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
14101410
let mut local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, self.feerate_per_kw).0;
1411-
let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
1411+
let local_sighash = hash_to_message!(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
14121412

14131413
// They sign the "local" commitment transaction...
14141414
secp_check!(self.secp_ctx.verify(&local_sighash, &sig, &self.their_funding_pubkey.unwrap()), "Invalid funding_created signature from peer");
@@ -1418,7 +1418,7 @@ impl Channel {
14181418

14191419
let remote_keys = self.build_remote_transaction_keys()?;
14201420
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
1421-
let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
1421+
let remote_sighash = hash_to_message!(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
14221422

14231423
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
14241424
Ok((remote_initial_commitment_tx, local_initial_commitment_tx, self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key), local_keys))
@@ -1487,7 +1487,7 @@ impl Channel {
14871487

14881488
let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?;
14891489
let mut local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, self.feerate_per_kw).0;
1490-
let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
1490+
let local_sighash = hash_to_message!(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
14911491

14921492
// They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish.
14931493
secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid funding_signed signature from peer");
@@ -1699,7 +1699,7 @@ impl Channel {
16991699
(commitment_tx.0, commitment_tx.1, htlcs_cloned)
17001700
};
17011701
let local_commitment_txid = local_commitment_tx.0.txid();
1702-
let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
1702+
let local_sighash = hash_to_message!(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]);
17031703
secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid commitment tx signature from peer");
17041704

17051705
//If channel fee was updated by funder confirm funder can afford the new fee rate when applied to the current local commitment transaction
@@ -1725,7 +1725,7 @@ impl Channel {
17251725
if let Some(_) = htlc.transaction_output_index {
17261726
let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, &htlc, true, &local_keys, feerate_per_kw);
17271727
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys);
1728-
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
1728+
let htlc_sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
17291729
secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer");
17301730
let htlc_sig = if htlc.offered {
17311731
let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, &htlc, &local_keys)?;
@@ -2456,7 +2456,7 @@ impl Channel {
24562456

24572457
let (closing_tx, total_fee_satoshis) = self.build_closing_transaction(proposed_total_fee_satoshis, false);
24582458
let funding_redeemscript = self.get_funding_redeemscript();
2459-
let sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
2459+
let sighash = hash_to_message!(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
24602460

24612461
self.last_sent_closing_fee = Some((proposed_feerate, total_fee_satoshis));
24622462
Some(msgs::ClosingSigned {
@@ -2558,15 +2558,15 @@ impl Channel {
25582558
if used_total_fee != msg.fee_satoshis {
25592559
return Err(ChannelError::Close("Remote sent us a closing_signed with a fee greater than the value they can claim"));
25602560
}
2561-
let mut sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
2561+
let mut sighash = hash_to_message!(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
25622562

25632563
match self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey.unwrap()) {
25642564
Ok(_) => {},
25652565
Err(_e) => {
25662566
// The remote end may have decided to revoke their output due to inconsistent dust
25672567
// limits, so check for that case by re-checking the signature here.
25682568
closing_tx = self.build_closing_transaction(msg.fee_satoshis, true).0;
2569-
sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
2569+
sighash = hash_to_message!(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
25702570
secp_check!(self.secp_ctx.verify(&sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid closing tx signature from peer");
25712571
},
25722572
};
@@ -2584,7 +2584,7 @@ impl Channel {
25842584
($new_feerate: expr) => {
25852585
let closing_tx_max_weight = Self::get_closing_transaction_weight(&self.get_closing_scriptpubkey(), self.their_shutdown_scriptpubkey.as_ref().unwrap());
25862586
let (closing_tx, used_total_fee) = self.build_closing_transaction($new_feerate * closing_tx_max_weight / 1000, false);
2587-
sighash = Message::from_slice(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]).unwrap();
2587+
sighash = hash_to_message!(&bip143::SighashComponents::new(&closing_tx).sighash_all(&closing_tx.input[0], &funding_redeemscript, self.channel_value_satoshis)[..]);
25882588
let our_sig = self.secp_ctx.sign(&sighash, &self.local_keys.funding_key);
25892589
self.last_sent_closing_fee = Some(($new_feerate, used_total_fee));
25902590
return Ok((Some(msgs::ClosingSigned {
@@ -2993,7 +2993,7 @@ impl Channel {
29932993

29942994
let remote_keys = self.build_remote_transaction_keys()?;
29952995
let remote_initial_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, false, self.feerate_per_kw).0;
2996-
let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
2996+
let remote_sighash = hash_to_message!(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]);
29972997

29982998
// We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish.
29992999
Ok((self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key), remote_initial_commitment_tx))
@@ -3080,7 +3080,7 @@ impl Channel {
30803080
excess_data: Vec::new(),
30813081
};
30823082

3083-
let msghash = Message::from_slice(&Sha256dHash::from_data(&msg.encode()[..])[..]).unwrap();
3083+
let msghash = hash_to_message!(&Sha256dHash::from_data(&msg.encode()[..])[..]);
30843084
let sig = self.secp_ctx.sign(&msghash, &self.local_keys.funding_key);
30853085

30863086
Ok((msg, sig))
@@ -3295,15 +3295,15 @@ impl Channel {
32953295
let remote_keys = self.build_remote_transaction_keys()?;
32963296
let remote_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true, feerate_per_kw);
32973297
let remote_commitment_txid = remote_commitment_tx.0.txid();
3298-
let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap();
3298+
let remote_sighash = hash_to_message!(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]);
32993299
let our_sig = self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key);
33003300

33013301
let mut htlc_sigs = Vec::with_capacity(remote_commitment_tx.1);
33023302
for &(ref htlc, _) in remote_commitment_tx.2.iter() {
33033303
if let Some(_) = htlc.transaction_output_index {
33043304
let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw);
33053305
let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys);
3306-
let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap();
3306+
let htlc_sighash = hash_to_message!(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]);
33073307
let our_htlc_key = secp_check!(chan_utils::derive_private_key(&self.secp_ctx, &remote_keys.per_commitment_point, &self.local_keys.htlc_base_key), "Derived invalid key, peer is maliciously selecting parameters");
33083308
htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key));
33093309
}

src/ln/channelmanager.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use bitcoin_hashes::sha256::Hash as Sha256;
2020
use bitcoin_hashes::cmp::fixed_time_eq;
2121

2222
use secp256k1::key::{SecretKey,PublicKey};
23-
use secp256k1::{Secp256k1,Message};
23+
use secp256k1::Secp256k1;
2424
use secp256k1::ecdh::SharedSecret;
2525
use secp256k1;
2626

@@ -937,7 +937,7 @@ impl ChannelManager {
937937
};
938938

939939
let msg_hash = Sha256dHash::from_data(&unsigned.encode()[..]);
940-
let sig = self.secp_ctx.sign(&Message::from_slice(&msg_hash[..]).unwrap(), &self.our_network_key);
940+
let sig = self.secp_ctx.sign(&hash_to_message!(&msg_hash[..]), &self.our_network_key);
941941

942942
Ok(msgs::ChannelUpdate {
943943
signature: sig,
@@ -1130,7 +1130,7 @@ impl ChannelManager {
11301130
Ok(res) => res,
11311131
Err(_) => return None, // Only in case of state precondition violations eg channel is closing
11321132
};
1133-
let msghash = Message::from_slice(&Sha256dHash::from_data(&announcement.encode()[..])[..]).unwrap();
1133+
let msghash = hash_to_message!(&Sha256dHash::from_data(&announcement.encode()[..])[..]);
11341134
let our_node_sig = self.secp_ctx.sign(&msghash, &self.our_network_key);
11351135

11361136
Some(msgs::AnnouncementSignatures {
@@ -2101,7 +2101,7 @@ impl ChannelManager {
21012101
try_chan_entry!(self, chan.get_mut().get_channel_announcement(our_node_id.clone(), self.genesis_hash.clone()), channel_state, chan);
21022102

21032103
let were_node_one = announcement.node_id_1 == our_node_id;
2104-
let msghash = Message::from_slice(&Sha256dHash::from_data(&announcement.encode()[..])[..]).unwrap();
2104+
let msghash = hash_to_message!(&Sha256dHash::from_data(&announcement.encode()[..])[..]);
21052105
if self.secp_ctx.verify(&msghash, &msg.node_signature, if were_node_one { &announcement.node_id_2 } else { &announcement.node_id_1 }).is_err() ||
21062106
self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, if were_node_one { &announcement.bitcoin_key_2 } else { &announcement.bitcoin_key_1 }).is_err() {
21072107
try_chan_entry!(self, Err(ChannelError::Close("Bad announcement_signatures node_signature")), channel_state, chan);

src/ln/channelmonitor.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use bitcoin_hashes::Hash;
2424
use bitcoin_hashes::sha256::Hash as Sha256;
2525
use bitcoin_hashes::hash160::Hash as Hash160;
2626

27-
use secp256k1::{Secp256k1,Message,Signature};
27+
use secp256k1::{Secp256k1,Signature};
2828
use secp256k1::key::{SecretKey,PublicKey};
2929
use secp256k1;
3030

@@ -1105,7 +1105,7 @@ impl ChannelMonitor {
11051105
let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()].0;
11061106
chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey)
11071107
};
1108-
let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
1108+
let sighash = hash_to_message!(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]);
11091109
let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
11101110
(self.secp_ctx.sign(&sighash, &revocation_key), redeemscript)
11111111
},
@@ -1327,7 +1327,7 @@ impl ChannelMonitor {
13271327
Storage::Local { ref htlc_base_key, .. } => {
13281328
let htlc = &per_commitment_option.unwrap()[$input.sequence as usize].0;
13291329
let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
1330-
let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
1330+
let sighash = hash_to_message!(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]);
13311331
let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key));
13321332
(self.secp_ctx.sign(&sighash, &htlc_key), redeemscript)
13331333
},
@@ -1512,7 +1512,7 @@ impl ChannelMonitor {
15121512

15131513
let sig = match self.key_storage {
15141514
Storage::Local { ref revocation_base_key, .. } => {
1515-
let sighash = ignore_error!(Message::from_slice(&sighash_parts.sighash_all(&spend_tx.input[0], &redeemscript, amount)[..]));
1515+
let sighash = hash_to_message!(&sighash_parts.sighash_all(&spend_tx.input[0], &redeemscript, amount)[..]);
15161516
let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
15171517
self.secp_ctx.sign(&sighash, &revocation_key)
15181518
}

src/ln/router.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! interrogate it to get routes for your own payments.
55
66
use secp256k1::key::PublicKey;
7-
use secp256k1::{Secp256k1,Message};
7+
use secp256k1::Secp256k1;
88
use secp256k1;
99

1010
use bitcoin::util::hash::Sha256dHash;
@@ -239,7 +239,7 @@ macro_rules! secp_verify_sig {
239239

240240
impl RoutingMessageHandler for Router {
241241
fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, HandleError> {
242-
let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap();
242+
let msg_hash = hash_to_message!(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]);
243243
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id);
244244

245245
if msg.contents.features.requires_unknown_bits() {
@@ -272,7 +272,7 @@ impl RoutingMessageHandler for Router {
272272
return Err(HandleError{err: "Channel announcement node had a channel with itself", action: Some(ErrorAction::IgnoreError)});
273273
}
274274

275-
let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap();
275+
let msg_hash = hash_to_message!(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]);
276276
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1);
277277
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2);
278278
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1);
@@ -448,7 +448,7 @@ impl RoutingMessageHandler for Router {
448448
};
449449
}
450450
}
451-
let msg_hash = Message::from_slice(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]).unwrap();
451+
let msg_hash = hash_to_message!(&Sha256dHash::from_data(&msg.contents.encode()[..])[..]);
452452
if msg.contents.flags & 1 == 1 {
453453
dest_node_id = channel.one_to_two.src_node_id.clone();
454454
secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &channel.two_to_one.src_node_id);

src/util/fuzz_wrappers.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
macro_rules! hash_to_message {
2+
($slice: expr) => {
3+
{
4+
#[cfg(not(feature = "fuzztarget"))]
5+
{
6+
::secp256k1::Message::from_slice($slice).unwrap()
7+
}
8+
#[cfg(feature = "fuzztarget")]
9+
{
10+
match ::secp256k1::Message::from_slice($slice) {
11+
Ok(msg) => msg,
12+
Err(_) => ::secp256k1::Message::from_slice(&[1; 32]).unwrap()
13+
}
14+
}
15+
}
16+
}
17+
}

src/util/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ pub use self::rng::{reset_rng_state, fill_bytes};
2727

2828
#[cfg(test)]
2929
pub(crate) mod test_utils;
30+
31+
#[macro_use]
32+
pub(crate) mod fuzz_wrappers;

0 commit comments

Comments
 (0)