Skip to content

Commit

Permalink
btc: convert pkscript_from_multisig() to Rust
Browse files Browse the repository at this point in the history
Alternative implementation of this function based on rust-miniscript:

```
pub fn pkscript(
    multisig: &Multisig,
    keypath_change: u32,
    keypath_address: u32,
) -> Result<Vec<u8>, Error> {
    let pubkeys: Vec<bitcoin::PublicKey> = multisig
        .xpubs
        .iter()
        .map(|xpub| -> Result<bitcoin::PublicKey, ()> {
            bitcoin::PublicKey::from_slice(
                bip32::Xpub::from(xpub)
                    .derive(&[keypath_change, keypath_address])?
                    .public_key(),
            )
            .map_err(|_| ())
        })
        .collect::<Result<_, _>>()?;
    let sorted_multi = miniscript::descriptor::SortedMultiVec::<
        bitcoin::PublicKey,
        miniscript::Legacy,
    >::new(multisig.threshold as _, pubkeys)
    .map_err(|_| Error::InvalidInput)?;
    Ok(sorted_multi.encode().into_bytes())
}
```

This cost about 10kB of binary space. The manual implementation of
this commit costs nearly nothing.
  • Loading branch information
benma committed Oct 25, 2023
1 parent 8f61406 commit 4f7a1e3
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 202 deletions.
3 changes: 0 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ set(DBB-FIRMWARE-SOURCES
${CMAKE_SOURCE_DIR}/src/workflow/blocking.c
${CMAKE_SOURCE_DIR}/src/workflow/idle_workflow.c
${CMAKE_SOURCE_DIR}/src/workflow/orientation_screen.c
${CMAKE_SOURCE_DIR}/src/apps/btc/btc_common.c
${CMAKE_SOURCE_DIR}/src/queue.c
${CMAKE_SOURCE_DIR}/src/usb/usb_processing.c
)
Expand Down Expand Up @@ -389,8 +388,6 @@ add_custom_target(rust-bindgen
--rustified-enum simple_type_t
--rustified-enum multisig_script_type_t
--rustified-enum output_type_t
--allowlist-function btc_common_pkscript_from_payload
--allowlist-function btc_common_pkscript_from_multisig
--allowlist-var MAX_VARINT_SIZE
--allowlist-var MAX_PK_SCRIPT_SIZE
--allowlist-function reboot
Expand Down
71 changes: 0 additions & 71 deletions src/apps/btc/btc_common.c

This file was deleted.

61 changes: 0 additions & 61 deletions src/apps/btc/btc_common.h

This file was deleted.

53 changes: 29 additions & 24 deletions src/rust/bitbox02-rust/src/hww/api/bitcoin/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,6 @@ use sha2::{Digest, Sha256};

pub const MAX_SIGNERS: usize = 15;

/// Converts a Rust protobuf multisig to a representation suitable to be passed to C functions.
pub fn convert_multisig(multisig: &Multisig) -> Result<bitbox02::app_btc::Multisig, Error> {
Ok(bitbox02::app_btc::Multisig {
xpubs_count: multisig.xpubs.len() as _,
xpubs: {
let mut xpubs = [[0u8; 78]; MAX_SIGNERS];
for (i, xpub) in multisig.xpubs.iter().enumerate() {
xpubs[i] = bip32::Xpub::from(xpub)
.serialize(Some(bip32::XPubType::Xpub))
.or(Err(Error::InvalidInput))?
.try_into()
.or(Err(Error::Generic))?;
}
xpubs
},
threshold: multisig.threshold,
})
}

pub enum SortXpubs {
No,
Yes,
Expand Down Expand Up @@ -311,11 +292,35 @@ pub fn pkscript(
keypath_change: u32,
keypath_address: u32,
) -> Result<Vec<u8>, Error> {
Ok(bitbox02::app_btc::pkscript_from_multisig(
&convert_multisig(multisig)?,
keypath_change,
keypath_address,
)?)
if multisig.xpubs.len() < 2 || multisig.xpubs.len() > MAX_SIGNERS {
return Err(Error::InvalidInput);
}
if multisig.threshold == 0 || multisig.threshold > multisig.xpubs.len() as _ {
return Err(Error::InvalidInput);
}
let mut pubkeys: Vec<Vec<u8>> = multisig
.xpubs
.iter()
.map(|xpub| -> Result<Vec<u8>, ()> {
Ok(bip32::Xpub::from(xpub)
.derive(&[keypath_change, keypath_address])?
.public_key()
.to_vec())
})
.collect::<Result<_, _>>()?;
pubkeys.sort();

let mut script_builder = bitcoin::script::Builder::new().push_int(multisig.threshold as _);
for pk in pubkeys.iter() {
let pk: &bitcoin::script::PushBytes =
pk.as_slice().try_into().map_err(|_| Error::Generic)?;
script_builder = script_builder.push_slice(pk);
}
script_builder = script_builder
.push_int(pubkeys.len() as _)
.push_opcode(bitcoin::opcodes::all::OP_CHECKMULTISIG);

Ok(script_builder.into_bytes())
}

#[cfg(test)]
Expand Down
1 change: 0 additions & 1 deletion src/rust/bitbox02-sys/wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <apps/btc/btc_common.h>
#include <apps/eth/eth_params.h>
#include <bip32.h>
#include <keystore.h>
Expand Down
39 changes: 0 additions & 39 deletions src/rust/bitbox02/src/app_btc.rs

This file was deleted.

2 changes: 0 additions & 2 deletions src/rust/bitbox02/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ extern crate lazy_static;
#[cfg(feature = "testing")]
pub mod testing;

#[cfg(any(feature = "app-bitcoin", feature = "app-litecoin"))]
pub mod app_btc;
#[cfg(feature = "app-ethereum")]
pub mod app_eth;
pub mod bip32;
Expand Down
1 change: 0 additions & 1 deletion test/unit-test/test_keystore_functional.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

#include <keystore.h>

#include <apps/btc/btc_common.h>
#include <memory/bitbox02_smarteeprom.h>
#include <memory/smarteeprom.h>
#include <mock_memory.h>
Expand Down

0 comments on commit 4f7a1e3

Please sign in to comment.