gui: prune bip32 derivations when signing with BitBox02
It can otherwise lead to the BitBox02 not signing for the correct public key. See https://github.com/wizardsardine/liana/pull/706#issuecomment-1744705808 for details.
This commit is contained in:
parent
b8d6be82a7
commit
99bbb76228
@ -1,7 +1,7 @@
|
|||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
|
||||||
use liana::config::ConfigError;
|
use liana::{config::ConfigError, descriptors::LianaDescError};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{settings::SettingsError, wallet::WalletError},
|
app::{settings::SettingsError, wallet::WalletError},
|
||||||
@ -15,6 +15,7 @@ pub enum Error {
|
|||||||
Daemon(DaemonError),
|
Daemon(DaemonError),
|
||||||
Unexpected(String),
|
Unexpected(String),
|
||||||
HardwareWallet(async_hwi::Error),
|
HardwareWallet(async_hwi::Error),
|
||||||
|
Desc(LianaDescError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
@ -48,6 +49,7 @@ impl std::fmt::Display for Error {
|
|||||||
},
|
},
|
||||||
Self::Unexpected(e) => write!(f, "Unexpected error: {}", e),
|
Self::Unexpected(e) => write!(f, "Unexpected error: {}", e),
|
||||||
Self::HardwareWallet(e) => write!(f, "{}", e),
|
Self::HardwareWallet(e) => write!(f, "{}", e),
|
||||||
|
Self::Desc(e) => write!(f, "Liana descriptor error: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -365,7 +365,7 @@ impl Action for SignAction {
|
|||||||
self.processing = true;
|
self.processing = true;
|
||||||
let psbt = tx.psbt.clone();
|
let psbt = tx.psbt.clone();
|
||||||
return Command::perform(
|
return Command::perform(
|
||||||
sign_psbt(device.clone(), *fingerprint, psbt),
|
sign_psbt(self.wallet.clone(), device.clone(), *fingerprint, psbt),
|
||||||
Message::Signed,
|
Message::Signed,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -449,11 +449,39 @@ async fn sign_psbt_with_hot_signer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn sign_psbt(
|
async fn sign_psbt(
|
||||||
|
wallet: Arc<Wallet>,
|
||||||
hw: std::sync::Arc<dyn async_hwi::HWI + Send + Sync>,
|
hw: std::sync::Arc<dyn async_hwi::HWI + Send + Sync>,
|
||||||
fingerprint: Fingerprint,
|
fingerprint: Fingerprint,
|
||||||
mut psbt: Psbt,
|
mut psbt: Psbt,
|
||||||
) -> Result<(Psbt, Fingerprint), Error> {
|
) -> Result<(Psbt, Fingerprint), Error> {
|
||||||
hw.sign_tx(&mut psbt).await.map_err(Error::from)?;
|
// The BitBox02 is only going to produce a signature for a single key in the Script. In order
|
||||||
|
// to make sure it doesn't sign for a public key from another spending path we remove the BIP32
|
||||||
|
// derivation for the other paths.
|
||||||
|
if matches!(hw.device_kind(), async_hwi::DeviceKind::BitBox02) {
|
||||||
|
// We need to make sure we don't prune the BIP32 derivations from the original PSBT (which
|
||||||
|
// would end up being updated in the daemon's database and erase the previously unpruned
|
||||||
|
// one). To this end we create a new, pruned, psbt we use for signing and then merge its
|
||||||
|
// signatures back into the original PSBT.
|
||||||
|
let mut pruned_psbt = wallet
|
||||||
|
.main_descriptor
|
||||||
|
.prune_bip32_derivs_last_avail(psbt.clone())
|
||||||
|
.map_err(Error::Desc)?;
|
||||||
|
hw.sign_tx(&mut pruned_psbt).await.map_err(Error::from)?;
|
||||||
|
for (i, psbt_in) in psbt.inputs.iter_mut().enumerate() {
|
||||||
|
if let Some(pruned_psbt_in) = pruned_psbt.inputs.get_mut(i) {
|
||||||
|
psbt_in
|
||||||
|
.partial_sigs
|
||||||
|
.append(&mut pruned_psbt_in.partial_sigs);
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"Not all PSBT inputs are present in the pruned psbt. Pruned psbt: '{}'.",
|
||||||
|
&pruned_psbt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hw.sign_tx(&mut psbt).await.map_err(Error::from)?;
|
||||||
|
}
|
||||||
Ok((psbt, fingerprint))
|
Ok((psbt, fingerprint))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@ impl From<&Error> for WarningMessage {
|
|||||||
},
|
},
|
||||||
Error::Unexpected(_) => WarningMessage("Unknown error".to_string()),
|
Error::Unexpected(_) => WarningMessage("Unknown error".to_string()),
|
||||||
Error::HardwareWallet(_) => WarningMessage("Hardware wallet error".to_string()),
|
Error::HardwareWallet(_) => WarningMessage("Hardware wallet error".to_string()),
|
||||||
|
Error::Desc(e) => WarningMessage(format!("Descriptor analysis error: '{}'.", e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user