3.10 Remove use of Network::Bitcoin

All uses were safe due to addresses being converted to script_pubkeys which
don't embed their network. The only risk of there being an issue is if a
future address spec did embed the net ID into the script_pubkey and that was
moved to.

This resolves the audit note and does offer that tightening.
This commit is contained in:
Luke Parker 2023-07-20 00:00:20 -04:00
parent 6f9d02fdf8
commit f66fe3c1cb
No known key found for this signature in database
4 changed files with 28 additions and 22 deletions

View file

@ -15,7 +15,8 @@ use frost::{
use bitcoin::{ use bitcoin::{
consensus::encode::{Decodable, serialize}, consensus::encode::{Decodable, serialize},
key::TweakedPublicKey, key::TweakedPublicKey,
OutPoint, ScriptBuf, TxOut, Transaction, Block, Network, Address, address::Payload,
OutPoint, ScriptBuf, TxOut, Transaction, Block,
}; };
use crate::crypto::{x_only, make_even}; use crate::crypto::{x_only, make_even};
@ -32,15 +33,15 @@ pub fn tweak_keys(keys: &ThresholdKeys<Secp256k1>) -> ThresholdKeys<Secp256k1> {
keys.offset(Scalar::from(offset)) keys.offset(Scalar::from(offset))
} }
/// Return the Taproot address for a public key. /// Return the Taproot address payload for a public key.
/// ///
/// If the key is odd, this will return None. /// If the key is odd, this will return None.
pub fn address(network: Network, key: ProjectivePoint) -> Option<Address> { pub fn address_payload(key: ProjectivePoint) -> Option<Payload> {
if key.to_encoded_point(true).tag() != Tag::CompressedEvenY { if key.to_encoded_point(true).tag() != Tag::CompressedEvenY {
return None; return None;
} }
Some(Address::p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked(x_only(&key)), network)) Some(Payload::p2tr_tweaked(TweakedPublicKey::dangerous_assume_tweaked(x_only(&key))))
} }
/// A spendable output. /// A spendable output.
@ -109,8 +110,7 @@ impl Scanner {
/// Returns None if this key can't be scanned for. /// Returns None if this key can't be scanned for.
pub fn new(key: ProjectivePoint) -> Option<Scanner> { pub fn new(key: ProjectivePoint) -> Option<Scanner> {
let mut scripts = HashMap::new(); let mut scripts = HashMap::new();
// Uses Network::Bitcoin since network is irrelevant here scripts.insert(address_payload(key)?.script_pubkey(), Scalar::ZERO);
scripts.insert(address(Network::Bitcoin, key)?.script_pubkey(), Scalar::ZERO);
Some(Scanner { key, scripts }) Some(Scanner { key, scripts })
} }
@ -127,7 +127,7 @@ impl Scanner {
// chance of being even // chance of being even
// That means this should terminate within a very small amount of iterations // That means this should terminate within a very small amount of iterations
loop { loop {
match address(Network::Bitcoin, self.key + (ProjectivePoint::GENERATOR * offset)) { match address_payload(self.key + (ProjectivePoint::GENERATOR * offset)) {
Some(address) => { Some(address) => {
let script = address.script_pubkey(); let script = address.script_pubkey();
if self.scripts.contains_key(&script) { if self.scripts.contains_key(&script) {

View file

@ -16,12 +16,12 @@ use bitcoin::{
sighash::{TapSighashType, SighashCache, Prevouts}, sighash::{TapSighashType, SighashCache, Prevouts},
absolute::LockTime, absolute::LockTime,
script::{PushBytesBuf, ScriptBuf}, script::{PushBytesBuf, ScriptBuf},
OutPoint, Sequence, Witness, TxIn, TxOut, Transaction, Network, Address, OutPoint, Sequence, Witness, TxIn, TxOut, Transaction, Address,
}; };
use crate::{ use crate::{
crypto::Schnorr, crypto::Schnorr,
wallet::{address, ReceivedOutput}, wallet::{ReceivedOutput, address_payload},
}; };
#[rustfmt::skip] #[rustfmt::skip]
@ -226,9 +226,7 @@ impl SignableTransaction {
transcript.append_message(b"signing_input", u32::try_from(i).unwrap().to_le_bytes()); transcript.append_message(b"signing_input", u32::try_from(i).unwrap().to_le_bytes());
let offset = keys.clone().offset(self.offsets[i]); let offset = keys.clone().offset(self.offsets[i]);
if address(Network::Bitcoin, offset.group_key())?.script_pubkey() != if address_payload(offset.group_key())?.script_pubkey() != self.prevouts[i].script_pubkey {
self.prevouts[i].script_pubkey
{
None?; None?;
} }

View file

@ -22,9 +22,12 @@ use bitcoin_serai::{
hashes::Hash as HashTrait, hashes::Hash as HashTrait,
blockdata::opcodes::all::OP_RETURN, blockdata::opcodes::all::OP_RETURN,
script::{PushBytesBuf, Instruction, Instructions, Script}, script::{PushBytesBuf, Instruction, Instructions, Script},
address::NetworkChecked,
OutPoint, TxOut, Transaction, Network, Address, OutPoint, TxOut, Transaction, Network, Address,
}, },
wallet::{tweak_keys, address, ReceivedOutput, Scanner, TransactionError, SignableTransaction}, wallet::{
tweak_keys, address_payload, ReceivedOutput, Scanner, TransactionError, SignableTransaction,
},
rpc::Rpc, rpc::Rpc,
}; };
@ -43,7 +46,10 @@ async fn send_and_get_output(rpc: &Rpc, scanner: &Scanner, key: ProjectivePoint)
rpc rpc
.rpc_call::<Vec<String>>( .rpc_call::<Vec<String>>(
"generatetoaddress", "generatetoaddress",
serde_json::json!([1, address(Network::Regtest, key).unwrap()]), serde_json::json!([
1,
Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap())
]),
) )
.await .await
.unwrap(); .unwrap();
@ -187,7 +193,7 @@ async_sequential! {
assert_eq!(output.offset(), Scalar::ZERO); assert_eq!(output.offset(), Scalar::ZERO);
let inputs = vec![output]; let inputs = vec![output];
let addr = || address(Network::Regtest, key).unwrap(); let addr = || Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap());
let payments = vec![(addr(), 1000)]; let payments = vec![(addr(), 1000)];
assert!(SignableTransaction::new(inputs.clone(), &payments, None, None, FEE).is_ok()); assert!(SignableTransaction::new(inputs.clone(), &payments, None, None, FEE).is_ok());
@ -250,13 +256,14 @@ async_sequential! {
// Declare payments, change, fee // Declare payments, change, fee
let payments = [ let payments = [
(address(Network::Regtest, key).unwrap(), 1005), (Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap()), 1005),
(address(Network::Regtest, offset_key).unwrap(), 1007) (Address::<NetworkChecked>::new(Network::Regtest, address_payload(offset_key).unwrap()), 1007)
]; ];
let change_offset = scanner.register_offset(Scalar::random(&mut OsRng)).unwrap(); let change_offset = scanner.register_offset(Scalar::random(&mut OsRng)).unwrap();
let change_key = key + (ProjectivePoint::GENERATOR * change_offset); let change_key = key + (ProjectivePoint::GENERATOR * change_offset);
let change_addr = address(Network::Regtest, change_key).unwrap(); let change_addr =
Address::<NetworkChecked>::new(Network::Regtest, address_payload(change_key).unwrap());
// Create and sign the TX // Create and sign the TX
let tx = SignableTransaction::new( let tx = SignableTransaction::new(
@ -327,7 +334,7 @@ async_sequential! {
SignableTransaction::new( SignableTransaction::new(
vec![output], vec![output],
&[], &[],
address(Network::Regtest, key), Some(Address::<NetworkChecked>::new(Network::Regtest, address_payload(key).unwrap())),
Some(data.clone()), Some(data.clone()),
FEE FEE
).unwrap() ).unwrap()

View file

@ -17,10 +17,11 @@ use bitcoin_serai::{
hashes::Hash as HashTrait, hashes::Hash as HashTrait,
consensus::{Encodable, Decodable}, consensus::{Encodable, Decodable},
script::Instruction, script::Instruction,
address::{NetworkChecked, Address as BAddress},
OutPoint, Transaction, Block, Network, OutPoint, Transaction, Block, Network,
}, },
wallet::{ wallet::{
tweak_keys, address, ReceivedOutput, Scanner, TransactionError, tweak_keys, address_payload, ReceivedOutput, Scanner, TransactionError,
SignableTransaction as BSignableTransaction, TransactionMachine, SignableTransaction as BSignableTransaction, TransactionMachine,
}, },
rpc::{RpcError, Rpc}, rpc::{RpcError, Rpc},
@ -33,7 +34,7 @@ use bitcoin_serai::bitcoin::{
sighash::{EcdsaSighashType, SighashCache}, sighash::{EcdsaSighashType, SighashCache},
script::{PushBytesBuf, Builder}, script::{PushBytesBuf, Builder},
absolute::LockTime, absolute::LockTime,
Sequence, Script, Witness, TxIn, TxOut, Address as BAddress, Sequence, Script, Witness, TxIn, TxOut,
}; };
use serai_client::{ use serai_client::{
@ -326,7 +327,7 @@ impl Coin for Bitcoin {
} }
fn address(key: ProjectivePoint) -> Address { fn address(key: ProjectivePoint) -> Address {
Address(address(Network::Bitcoin, key).unwrap()) Address(BAddress::<NetworkChecked>::new(Network::Bitcoin, address_payload(key).unwrap()))
} }
fn branch_address(key: ProjectivePoint) -> Self::Address { fn branch_address(key: ProjectivePoint) -> Self::Address {