lianad: DesKeyChecker.check() => check the change multipath is not hardened

This commit is contained in:
pythcoiner 2024-07-19 13:00:21 +02:00
parent 0de58cf3b7
commit 8d495579e1

View File

@ -116,11 +116,10 @@ impl DescKeyChecker {
// without origin entirely.
if let Some(ref origin) = xpub.origin {
let der_paths = xpub.derivation_paths.paths();
let first_der_path = der_paths.first().expect("Cannot be empty");
// We also rule out xpubs with hardened derivation steps (non-normalized xpubs).
let valid = xpub.wildcard == descriptor::Wildcard::Unhardened
&& der_paths.len() == 2
&& first_der_path.into_iter().all(|step| step.is_normal());
&& der_paths.iter().flatten().all(|step| step.is_normal());
if valid {
return Ok(origin.0);
}
@ -776,3 +775,70 @@ impl PartialSpendInfo {
&self.recovery_paths
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn valid_key() {
let xpub_str =
"[8c3ffb6e/48'/1'/0'/2']tpubDEMt3bpQMa99W81K9h8f2FJH1C81eSd6bbSkBP8tcqQHAfSKvuGp2fz6xiVpfShzT9sKPx7DVBphChjxvNd15WcbsCca5oVz1AcUTWHxkdS/<0;1>/*";
let key = descriptor::DescriptorPublicKey::from_str(xpub_str).unwrap();
let mut checker = DescKeyChecker::new();
assert!(checker.check(&key).is_ok());
}
#[test]
fn invalid_key() {
// Multipath of size 3
let xpub_str =
"[8c3ffb6e/48'/1'/0'/2']tpubDEMt3bpQMa99W81K9h8f2FJH1C81eSd6bbSkBP8tcqQHAfSKvuGp2fz6xiVpfShzT9sKPx7DVBphChjxvNd15WcbsCca5oVz1AcUTWHxkdS/<0;1;2>/*";
let key = descriptor::DescriptorPublicKey::from_str(xpub_str).unwrap();
let mut checker = DescKeyChecker::new();
assert!(matches!(
checker.check(&key),
Err(LianaPolicyError::InvalidKey(k)) if k == key.into()
));
// No multipath
let xpub_str =
"[8c3ffb6e/48'/1'/0'/2']tpubDEMt3bpQMa99W81K9h8f2FJH1C81eSd6bbSkBP8tcqQHAfSKvuGp2fz6xiVpfShzT9sKPx7DVBphChjxvNd15WcbsCca5oVz1AcUTWHxkdS/0/*";
let key = descriptor::DescriptorPublicKey::from_str(xpub_str).unwrap();
let mut checker = DescKeyChecker::new();
assert!(matches!(
checker.check(&key),
Err(LianaPolicyError::InvalidKey(k)) if k == key.into()
));
// Hardened receive path
let xpub_str =
"[8c3ffb6e/48'/1'/0'/2']tpubDEMt3bpQMa99W81K9h8f2FJH1C81eSd6bbSkBP8tcqQHAfSKvuGp2fz6xiVpfShzT9sKPx7DVBphChjxvNd15WcbsCca5oVz1AcUTWHxkdS/<0';1>/*";
let key = descriptor::DescriptorPublicKey::from_str(xpub_str).unwrap();
let mut checker = DescKeyChecker::new();
assert!(matches!(
checker.check(&key),
Err(LianaPolicyError::InvalidKey(k)) if k == key.into()
));
// Hardened change path
let xpub_str =
"[8c3ffb6e/48'/1'/0'/2']tpubDEMt3bpQMa99W81K9h8f2FJH1C81eSd6bbSkBP8tcqQHAfSKvuGp2fz6xiVpfShzT9sKPx7DVBphChjxvNd15WcbsCca5oVz1AcUTWHxkdS/<0;1'>/*";
let key = descriptor::DescriptorPublicKey::from_str(xpub_str).unwrap();
let mut checker = DescKeyChecker::new();
assert!(matches!(
checker.check(&key),
Err(LianaPolicyError::InvalidKey(k)) if k == key.into()
));
// Hardened wildcard
let xpub_str =
"[8c3ffb6e/48'/1'/0'/2']tpubDEMt3bpQMa99W81K9h8f2FJH1C81eSd6bbSkBP8tcqQHAfSKvuGp2fz6xiVpfShzT9sKPx7DVBphChjxvNd15WcbsCca5oVz1AcUTWHxkdS/<0;1>/*'";
let key = descriptor::DescriptorPublicKey::from_str(xpub_str).unwrap();
let mut checker = DescKeyChecker::new();
assert!(matches!(
checker.check(&key),
Err(LianaPolicyError::InvalidKey(k)) if k == key.into()
));
}
}