Skip to content

Commit

Permalink
btc: move unit tests of pkscript_from_multisig to Rust
Browse files Browse the repository at this point in the history
In preparation of converting the whole function to Rust.
  • Loading branch information
benma committed Oct 25, 2023
1 parent 6e83767 commit 8f61406
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 242 deletions.
6 changes: 1 addition & 5 deletions src/rust/bitbox02-rust/src/hww/api/bitcoin/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,7 @@ impl Payload {
let script_type =
pb::btc_script_config::multisig::ScriptType::from_i32(multisig.script_type)
.ok_or(Error::InvalidInput)?;
let script = bitbox02::app_btc::pkscript_from_multisig(
&multisig::convert_multisig(multisig)?,
keypath_change,
keypath_address,
)?;
let script = multisig::pkscript(multisig, keypath_change, keypath_address)?;
let payload_p2wsh = Payload {
data: Sha256::digest(&script).to_vec(),
output_type: BtcOutputType::P2wsh,
Expand Down
177 changes: 177 additions & 0 deletions src/rust/bitbox02-rust/src/hww/api/bitcoin/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,22 @@ pub fn validate(multisig: &Multisig, keypath: &[u32], expected_coin: u32) -> Res
Ok(())
}

/// Creates a n-of-m multisig script based on OP_CHECKMULTISIG. 0<n<=m<=15.
/// Note that the multisig config and keypaths are *not* validated, this must be done before calling.
/// keypath_change is 0 for receive addresses, 1 for change addresses.
/// keypath_address is the receive address index.
pub fn pkscript(
multisig: &Multisig,
keypath_change: u32,
keypath_address: u32,
) -> Result<Vec<u8>, Error> {
Ok(bitbox02::app_btc::pkscript_from_multisig(
&convert_multisig(multisig)?,
keypath_change,
keypath_address,
)?)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -684,4 +700,165 @@ mod tests {
assert!(validate(&invalid, keypath, expected_coin).is_err());
}
}

#[test]
fn test_pkscript() {
struct Test<'a> {
threshold: u32,
xpubs: &'a [&'a str],
keypath_change: u32,
keypath_address: u32,
expected_script_hex: &'a str,
}

let tests = [
Test {
threshold: 1,
xpubs: &[
"xpub6FEZ9Bv73h1vnE4TJG4QFj2RPXJhhsPbnXgFyH3ErLvpcZrDcynY65bhWga8PazWHLSLi23PoBhGcLcYW6JRiJ12zXZ9Aop4LbAqsS3gtcy",
"xpub6EGAio99SxruuNxoBtG4fbYx3xM8fs7wjYJLRNcUg7UQin3LTANQiUYyb3RLjZ2EAyLsQBrtbNENUGh3oWzjHtgfQ3mtjPNFgNMronzTTVR",
],
keypath_change: 0,
keypath_address: 1,
expected_script_hex: "51210217fb1e3415108fee2b004c932dc5a89eabf3587e3e7b21165c123de1f37a3a612102ae0826124c98c4e255c1a6cc404ff6d2448a0d9f853e6d72d6b02d9ad2d3565052ae",
},
// different xpub order should have the same result.
Test {
threshold: 1,
xpubs: &[
"xpub6EGAio99SxruuNxoBtG4fbYx3xM8fs7wjYJLRNcUg7UQin3LTANQiUYyb3RLjZ2EAyLsQBrtbNENUGh3oWzjHtgfQ3mtjPNFgNMronzTTVR",
"xpub6FEZ9Bv73h1vnE4TJG4QFj2RPXJhhsPbnXgFyH3ErLvpcZrDcynY65bhWga8PazWHLSLi23PoBhGcLcYW6JRiJ12zXZ9Aop4LbAqsS3gtcy",
],
keypath_change: 0,
keypath_address: 1,
expected_script_hex: "51210217fb1e3415108fee2b004c932dc5a89eabf3587e3e7b21165c123de1f37a3a612102ae0826124c98c4e255c1a6cc404ff6d2448a0d9f853e6d72d6b02d9ad2d3565052ae",
},
Test {
threshold: 1,
xpubs: &[
"xpub6FEZ9Bv73h1vnE4TJG4QFj2RPXJhhsPbnXgFyH3ErLvpcZrDcynY65bhWga8PazWHLSLi23PoBhGcLcYW6JRiJ12zXZ9Aop4LbAqsS3gtcy",
"xpub6EGAio99SxruuNxoBtG4fbYx3xM8fs7wjYJLRNcUg7UQin3LTANQiUYyb3RLjZ2EAyLsQBrtbNENUGh3oWzjHtgfQ3mtjPNFgNMronzTTVR",
],
keypath_change: 1,
keypath_address: 10,
expected_script_hex: "512102b6da3d9e33c3bcee679ef3bb2fca8e60c4a8ade06519146c77b007778756b2c92103f42b45d0d91039df309ff5d10d0a044fb4eb6595d015281be2d56c288524d68f52ae",
},
Test {
threshold: 2,
xpubs: &[
"xpub6FEZ9Bv73h1vnE4TJG4QFj2RPXJhhsPbnXgFyH3ErLvpcZrDcynY65bhWga8PazWHLSLi23PoBhGcLcYW6JRiJ12zXZ9Aop4LbAqsS3gtcy",
"xpub6EGAio99SxruuNxoBtG4fbYx3xM8fs7wjYJLRNcUg7UQin3LTANQiUYyb3RLjZ2EAyLsQBrtbNENUGh3oWzjHtgfQ3mtjPNFgNMronzTTVR",
],
keypath_change: 0,
keypath_address: 1,
expected_script_hex: "52210217fb1e3415108fee2b004c932dc5a89eabf3587e3e7b21165c123de1f37a3a612102ae0826124c98c4e255c1a6cc404ff6d2448a0d9f853e6d72d6b02d9ad2d3565052ae",
},
Test {
threshold: 15,
xpubs: &[
"xpub6FEZ9Bv73h1vnE4TJG4QFj2RPXJhhsPbnXgFyH3ErLvpcZrDcynY65bhWga8PazWHLSLi23PoBhGcLcYW6JRiJ12zXZ9Aop4LbAqsS3gtcy",
"xpub6EGAio99SxruuNxoBtG4fbYx3xM8fs7wjYJLRNcUg7UQin3LTANQiUYyb3RLjZ2EAyLsQBrtbNENUGh3oWzjHtgfQ3mtjPNFgNMronzTTVR",
"xpub6E9Qk6G1PAZPqheZ85sySQc9fxS8mp2muF9dNaXpnCGvW2NB13rCm4TKLo9vJaCyxcXBJPF2yBSkKuivLGA5fxuXhbRSL2Sp8HfgxEMFYD3",
"xpub6DxHJ5evyWcSBrG9zCauY1zrh3J6HkiBGLzgG4wvuRaDQYxF6suuPNh1hD2VktphRhEwWXECaWLXo1PkVkGn7hW6vq6AN3ZgqFUrQ7boHqs",
"xpub6EdCXJqHFRVqVCZpain6TMzkpmcU6pLU5jSzjUUouumdkzKUAmvBiTsVeJSwxdBzH5mLU1FEFka7jsrs1JeRbqJnwHE31bVF26gkJQ5SCs3",
"xpub6EG6LDy2hGg7NBUKyPzqe8k57Jm6H9WmH85MKKWGVTCbr5tVDt8oaKSAArXga4LbYy6Aawfzr324kXq4ia4vSkRBzPCktDv5XJbPRg3sXsz",
"xpub6EVoeT8mm6jfq5mtG3Kuv2ozffH1oRaLYsq88N1x7225QBzfBeZxbdx6sGYpFpkcJohzLHXhM7GjqqyrvxzkfvZjydSCGPbaDxWirKH3TRp",
"xpub6FNtqhDqFmHJxZsocfd2LftXzZAcDXK2ijhzcscsrsu46Ccz3uv7rrZYbFEvA98svjzkD49x8K2Mi2BuJuhyZHfTtBfdgeUc66JdCez8KG8",
"xpub6F1behqQRigaf5gbFbbdjrNV4M64UTQTrzEU535dURgBMJakSFpiZkXveqEscL6Y6gyveFwxp8PGKn3q9MLtwk1UmyRRkFCQb2X6hfvGYWt",
"xpub6FG3mVwCkRmtmFuCKZa6MXc4kCPEd5bKrjrNAPgwcmekysnsHBaadhuzo2jV2AjYyg4QjGmu3LgyEUAw4bUXPUsQJG61ZtKM7MVkBxbxcVj",
"xpub6DoEJEeUNBkLF7zmKKu8YewqK1PcXWfuek2J2Y8USdGh2McQStsGbVn2oqv521KdJiESeRW4mBBtpBamKHNaD6yZhAbyPwy51VyqHS4EFq6",
"xpub6EzUjWSuWk7kBKZTKsdXkFMUropKFLq1iWabRtQpXckxf6s9NMR8UrmY6aYQUuvHyXpYo78RJhyZ1sK9Re4ZbdzpG4Awm6yW221N2AQM6ZU",
"xpub6DeznbrZVRaZ4P5Xr79JBs8dNyBMamFmAgAX52o73Pap5RLkMmUi9oQH1sopigbSr6gwUoDMd3EhpoB5tBZXzu4HWJiGETKQGneYtRpjaJB",
"xpub6EYf1KXzjaTgcNZFq7pVXGtGDkqHFPvEGBDygkDodz94ZpDazWppGe57hDhTA94z6zeGEubqyLqUMP67ubdd8hf6BbKYA9qtdDf3yM5wdJX",
"xpub6ELR9CAGqxwbKcCh591AfKs74neEY9UjtNbvLjrpsxH2FakqE238J1DmsFHePtXXyYhkZshW3qTWWwhENTQgWb6KHaf7SQnVovsKxtvZQaG",
],
keypath_change: 0,
keypath_address: 1,
expected_script_hex: "5f210210e4a9e6d84a7d4b88d5f0450ade30de2046f824374f9b4954a6f03bd37b7269210217fb1e341\
5108fee2b004c932dc5a89eabf3587e3e7b21165c123de1f37a3a61210219ad58aa89a3e1669b0757b7\
b87d72350cd94675421365a9b7ae781fabeb04ec210230a8551d874b4a3633195c1ba80d0fd5d4e6cf7\
917b07f00379893490f795fbe210242f82d15933cf3487567405699910eae5c4b5b24821eeaceeac0ea\
da231a760421024be1e5f4fd6c4248b05df752d19754aad4ca663f62f20fd7ac54616899870ebc21024\
d5cae14247c53ec7943a78ddb016a939e98756526587ec4bb72789334e698292102ae0826124c98c4e2\
55c1a6cc404ff6d2448a0d9f853e6d72d6b02d9ad2d356502102cd014c5921c2f40c0b8de3cf32f9b67\
89737e2a06677c4da7325623bcb0af89421033f63c02d09195b9c7efb7b75e18da8b768b5c3e0517082\
98d6580634284c28122103410a5da3477482eea7be703bd81d00d4498b7babfbd25f7c930a137a5025c\
0b721035b0322eeec4356d59edf4b6213cf78409c6f2e05c26e65b04c503f98a38ec78b21037ff295f8\
45fabf9eb4ada869bfa62bde1ede38f074b12bf12a2a2f214282cef82103aef77f1780440ba2445aef6\
d3ecf5d0b8dae3b6f22abc44734e1d4c257dc631f2103cd01c7cd59d6956bf07f1e7acba7c41a126ba5\
49c07d0c88988c94846ecd88005fae",
},
];

for test in tests {
assert_eq!(
hex::encode(
pkscript(
&Multisig {
threshold: test.threshold,
xpubs: test
.xpubs
.iter()
.map(|xpub| parse_xpub(xpub).unwrap())
.collect(),
our_xpub_index: 0,
script_type: ScriptType::P2wsh as _
},
test.keypath_change,
test.keypath_address
)
.unwrap()
)
.as_str(),
test.expected_script_hex
);
}
}

#[test]
fn test_pkscript_unhappy() {
struct Test<'a> {
threshold: u32,
xpubs: &'a [&'a str],
}

let tests = [
Test {
threshold: 1,
xpubs: &[],
},
Test {
threshold: 0,
xpubs: &[
"xpub6EMfjyGVUvwhpc3WKN1zXhMFGKJGMaSBPqbja4tbGoYvRBSXeTBCaqrRDjcuGTcaY95JrrAnQvDG3pdQPdtnYUCugjeksHSbyZT7rq38VQF",
"xpub6ERxBysTYfQyY4USv6c6J1HNVv9hpZFN9LHVPu47Ac4rK8fLy6NnAeeAHyEsMvG4G66ay5aFZii2VM7wT3KxLKX8Q8keZPd67kRGmrD1WJj",
],
},
Test {
threshold: 3,
xpubs: &[
"xpub6EMfjyGVUvwhpc3WKN1zXhMFGKJGMaSBPqbja4tbGoYvRBSXeTBCaqrRDjcuGTcaY95JrrAnQvDG3pdQPdtnYUCugjeksHSbyZT7rq38VQF",
"xpub6ERxBysTYfQyY4USv6c6J1HNVv9hpZFN9LHVPu47Ac4rK8fLy6NnAeeAHyEsMvG4G66ay5aFZii2VM7wT3KxLKX8Q8keZPd67kRGmrD1WJj",
],
},
];

for test in tests {
assert!(pkscript(
&Multisig {
threshold: test.threshold,
xpubs: test
.xpubs
.iter()
.map(|xpub| parse_xpub(xpub).unwrap())
.collect(),
our_xpub_index: 0,
script_type: ScriptType::P2wsh as _
},
1,
2,
)
.is_err());
}
}
}
4 changes: 2 additions & 2 deletions src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ fn sighash_script(
config: Some(pb::btc_script_config::Config::Multisig(multisig)),
}),
..
} => Ok(bitbox02::app_btc::pkscript_from_multisig(
&super::multisig::convert_multisig(multisig)?,
} => Ok(super::multisig::pkscript(
multisig,
keypath[keypath.len() - 2],
keypath[keypath.len() - 1],
)?),
Expand Down
2 changes: 0 additions & 2 deletions test/unit-test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,6 @@ set(TEST_LIST
""
random
"-Wl,--wrap=rand,--wrap=wally_sha256"
app_btc_common
""
ui_components
""
ui_util
Expand Down
Loading

0 comments on commit 8f61406

Please sign in to comment.