Skip to content

Commit f2a76cb

Browse files
committed
Merge branch 'hash160-rust'
2 parents f08682d + 3f8bd17 commit f2a76cb

File tree

19 files changed

+224
-394
lines changed

19 files changed

+224
-394
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,13 @@ add_custom_target(rust-bindgen
317317
--allowlist-function keystore_secp256k1_sign
318318
--allowlist-function keystore_secp256k1_schnorr_bip86_sign
319319
--allowlist-function keystore_bip39_mnemonic_to_seed
320-
--allowlist-function keystore_get_root_fingerprint
321320
--allowlist-function keystore_mock_unlocked
322-
--allowlist-function keystore_secp256k1_pubkey_hash160
323321
--allowlist-var EC_PUBLIC_KEY_UNCOMPRESSED_LEN
324322
--allowlist-var EC_PUBLIC_KEY_LEN
325323
--allowlist-function keystore_encode_xpub_at_keypath
326324
--allowlist-function keystore_encrypt_and_store_seed
327-
--rustified-enum xpub_type_t
328325
--allowlist-var XPUB_ENCODED_LEN
326+
--allowlist-var BIP32_SERIALIZED_LEN
329327
--allowlist-function lock_animation_start
330328
--allowlist-function lock_animation_stop
331329
--allowlist-function delay_us

src/keystore.c

Lines changed: 3 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -466,18 +466,6 @@ static bool _get_xprv(const uint32_t* keypath, const size_t keypath_len, struct
466466
return true;
467467
}
468468

469-
bool keystore_get_root_fingerprint(uint8_t* fingerprint)
470-
{
471-
struct ext_key derived_xpub __attribute__((__cleanup__(keystore_zero_xkey))) = {0};
472-
if (!keystore_get_xpub(NULL, 0, &derived_xpub)) {
473-
return false;
474-
}
475-
if (bip32_key_get_fingerprint(&derived_xpub, fingerprint, 4) != WALLY_OK) {
476-
return false;
477-
}
478-
return true;
479-
}
480-
481469
static bool _ext_key_equal(struct ext_key* one, struct ext_key* two)
482470
{
483471
if (!MEMEQ(one->chain_code, two->chain_code, sizeof(one->chain_code))) {
@@ -569,19 +557,6 @@ static bool _compressed_to_uncompressed(const uint8_t* pubkey_bytes, uint8_t* un
569557
return true;
570558
}
571559

572-
bool keystore_secp256k1_pubkey_hash160(
573-
const uint32_t* keypath,
574-
size_t keypath_len,
575-
uint8_t* hash160_out)
576-
{
577-
struct ext_key xpub __attribute__((__cleanup__(keystore_zero_xkey))) = {0};
578-
if (!keystore_get_xpub(keypath, keypath_len, &xpub)) {
579-
return false;
580-
}
581-
memcpy(hash160_out, xpub.hash160, sizeof(xpub.hash160));
582-
return true;
583-
}
584-
585560
bool keystore_secp256k1_pubkey_uncompressed(
586561
const uint32_t* keypath,
587562
size_t keypath_len,
@@ -706,82 +681,17 @@ bool keystore_get_ed25519_seed(uint8_t* seed_out)
706681
return true;
707682
}
708683

709-
static const uint8_t _xpub_version[4] = {0x04, 0x88, 0xb2, 0x1e};
710-
static const uint8_t _ypub_version[4] = {0x04, 0x9d, 0x7c, 0xb2};
711-
static const uint8_t _zpub_version[4] = {0x04, 0xb2, 0x47, 0x46};
712-
static const uint8_t _tpub_version[4] = {0x04, 0x35, 0x87, 0xcf};
713-
static const uint8_t _vpub_version[4] = {0x04, 0x5f, 0x1c, 0xf6};
714-
static const uint8_t _upub_version[4] = {0x04, 0x4a, 0x52, 0x62};
715-
static const uint8_t _capital_vpub_version[4] = {0x02, 0x57, 0x54, 0x83};
716-
static const uint8_t _capital_zpub_version[4] = {0x02, 0xaa, 0x7e, 0xd3};
717-
static const uint8_t _capital_upub_version[4] = {0x02, 0x42, 0x89, 0xef};
718-
static const uint8_t _capital_ypub_version[4] = {0x02, 0x95, 0xb4, 0x3f};
719-
720-
bool keystore_encode_xpub(
721-
const struct ext_key* xpub,
722-
xpub_type_t xpub_type,
723-
char* out,
724-
size_t out_len)
725-
{
726-
uint8_t bytes[BIP32_SERIALIZED_LEN] = {0};
727-
if (bip32_key_serialize(xpub, BIP32_FLAG_KEY_PUBLIC, bytes, sizeof(bytes)) != WALLY_OK) {
728-
return false;
729-
}
730-
731-
const uint8_t* version;
732-
switch (xpub_type) {
733-
case XPUB:
734-
version = _xpub_version;
735-
break;
736-
case YPUB:
737-
version = _ypub_version;
738-
break;
739-
case ZPUB:
740-
version = _zpub_version;
741-
break;
742-
case TPUB:
743-
version = _tpub_version;
744-
break;
745-
case VPUB:
746-
version = _vpub_version;
747-
break;
748-
case UPUB:
749-
version = _upub_version;
750-
break;
751-
case CAPITAL_VPUB:
752-
version = _capital_vpub_version;
753-
break;
754-
case CAPITAL_ZPUB:
755-
version = _capital_zpub_version;
756-
break;
757-
case CAPITAL_UPUB:
758-
version = _capital_upub_version;
759-
break;
760-
case CAPITAL_YPUB:
761-
version = _capital_ypub_version;
762-
break;
763-
default:
764-
return false;
765-
}
766-
767-
// Overwrite bip32 version.
768-
memcpy(bytes, version, 4);
769-
return rust_base58_encode_check(
770-
rust_util_bytes(bytes, sizeof(bytes)), rust_util_cstr_mut(out, out_len));
771-
}
772-
773684
USE_RESULT bool keystore_encode_xpub_at_keypath(
774685
const uint32_t* keypath,
775686
size_t keypath_len,
776-
xpub_type_t xpub_type,
777-
char* out,
778-
size_t out_len)
687+
uint8_t* out)
779688
{
780689
struct ext_key derived_xpub __attribute__((__cleanup__(keystore_zero_xkey))) = {0};
781690
if (!keystore_get_xpub(keypath, keypath_len, &derived_xpub)) {
782691
return false;
783692
}
784-
return keystore_encode_xpub(&derived_xpub, xpub_type, out, out_len);
693+
return bip32_key_serialize(&derived_xpub, BIP32_FLAG_KEY_PUBLIC, out, BIP32_SERIALIZED_LEN) ==
694+
WALLY_OK;
785695
}
786696

787697
static void _tagged_hash(const char* tag, const uint8_t* msg, size_t msg_len, uint8_t* hash_out)

src/keystore.h

Lines changed: 4 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,6 @@ USE_RESULT bool keystore_bip39_mnemonic_to_seed(
142142
uint8_t* seed_out,
143143
size_t* seed_len_out);
144144

145-
/**
146-
* Fills a uint8_t buffer with a fingerprint of the root public key at m/, which are the first four
147-
* bytes of its hash160 according to:
148-
* https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format
149-
* @param[out] fingerprint, buffer of the fingerprint that is supposed to be filled, has to be size
150-
* 4
151-
*/
152-
USE_RESULT bool keystore_get_root_fingerprint(uint8_t* fingerprint);
153-
154145
/**
155146
* Can be used only if the keystore is unlocked. Returns the derived xpub,
156147
* using bip32 derivation. Derivation is done from the xprv master, so hardened
@@ -175,18 +166,6 @@ void keystore_zero_xkey(struct ext_key* xkey);
175166
*/
176167
USE_RESULT bool keystore_get_bip39_word(uint16_t idx, char** word_out);
177168

178-
/**
179-
* Return the hash160 of the secp256k1 public key at the keypath.
180-
* @param[in] keypath derivation keypath
181-
* @param[in] keypath_len size of keypath buffer
182-
* @param[out] hash160_out serialized output. Must be HASH160_LEN bytes.
183-
* @return true on success, false if the keystore is locked or the input is invalid.
184-
*/
185-
USE_RESULT bool keystore_secp256k1_pubkey_hash160(
186-
const uint32_t* keypath,
187-
size_t keypath_len,
188-
uint8_t* hash160_out);
189-
190169
/**
191170
* Return the serialized secp256k1 public key at the keypath, in uncompressed format.
192171
* @param[in] keypath derivation keypath
@@ -269,44 +248,15 @@ USE_RESULT bool keystore_get_u2f_seed(uint8_t* seed_out);
269248
*/
270249
USE_RESULT bool keystore_get_ed25519_seed(uint8_t* seed_out);
271250

272-
typedef enum {
273-
XPUB,
274-
YPUB,
275-
ZPUB,
276-
TPUB,
277-
VPUB,
278-
UPUB,
279-
CAPITAL_VPUB,
280-
CAPITAL_ZPUB,
281-
CAPITAL_UPUB,
282-
CAPITAL_YPUB,
283-
} xpub_type_t;
284-
/**
285-
* Encode an xpub as a base58 string.
286-
* @param[in] xpub the xpub to encode.
287-
* @param[in] xpub_type determines the xpub format.
288-
* etc.
289-
* @param[out] out resulting string, must be at least of size `XPUB_ENCODED_LEN` (including the null
290-
* terminator).
291-
* @param[in] out_len size of `out`.
292-
* @return false on failure, true on success.
293-
*/
294-
USE_RESULT bool keystore_encode_xpub(
295-
const struct ext_key* xpub,
296-
xpub_type_t xpub_type,
297-
char* out,
298-
size_t out_len);
299-
300251
/**
301-
* Encode an xpub as a base58 string at the given `keypath`.
302-
* Args the same as `keystore_encode_xpub`.
252+
* Encode an xpub at the given `keypath` as 78 bytes according to BIP32. The version bytes are
253+
* the ones corresponding to `xpub`, i.e. 0x0488B21E.
254+
* `out` must be `BIP32_SERIALIZED_LEN` long.
303255
*/
304256
USE_RESULT bool keystore_encode_xpub_at_keypath(
305257
const uint32_t* keypath,
306258
size_t keypath_len,
307-
xpub_type_t xpub_type,
308-
char* out,
309-
size_t out_len);
259+
uint8_t* out);
310260

311261
/**
312262
* Return the tweaked taproot pubkey at the given keypath.

src/rust/bitbox02-rust/Cargo.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ zeroize = "1.5.5"
3838
num-bigint = { version = "0.4.3", default-features = false, optional = true }
3939
num-traits = { version = "0.2", default-features = false, optional = true }
4040
bip32-ed25519 = { git = "https://github.com/digitalbitbox/rust-bip32-ed25519", tag = "v0.1.0", optional = true }
41-
bs58 = { version = "0.4.0", default-features = false, features = ["alloc", "check"], optional = true }
41+
bs58 = { version = "0.4.0", default-features = false, features = ["alloc", "check"] }
4242
bech32 = { version = "0.8.1", default-features = false, optional = true }
4343
blake2 = { version = "0.10.5", default-features = false, optional = true }
4444
minicbor = { version = "0.18.0", default-features = false, features = ["alloc"], optional = true }
@@ -78,14 +78,12 @@ app-ethereum = [
7878

7979
app-bitcoin = [
8080
# enable these dependencies
81-
"bs58",
8281
"bech32",
8382
# enable this feature in the deps
8483
"bitbox02/app-bitcoin",
8584
]
8685
app-litecoin = [
8786
# enable these dependencies
88-
"bs58",
8987
"bech32",
9088
# enable this feature in the deps
9189
"bitbox02/app-litecoin",
@@ -100,7 +98,6 @@ app-cardano = [
10098
# enable these deps
10199
"bech32",
102100
"blake2",
103-
"bs58",
104101
"minicbor",
105102
"crc",
106103

src/rust/bitbox02-rust/src/bip32.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,28 @@ pub fn serialize_xpub_str(xpub: &pb::XPub, xpub_type: XPubType) -> Result<String
6161
.into_string())
6262
}
6363

64-
#[cfg(test)]
65-
pub fn parse_xpub(xpub: &str) -> Result<pb::XPub, ()> {
66-
let decoded = bs58::decode(xpub).into_vec().or(Err(()))?;
64+
/// Parses an 78-ytes xpub bytestring, encoded according to BIP32. The 4 version bytes are not
65+
/// checked and discarded.
66+
pub fn parse_xpub_bytes(xpub: &[u8]) -> Result<pb::XPub, ()> {
67+
if xpub.len() != 78 {
68+
return Err(());
69+
}
6770
Ok(pb::XPub {
68-
depth: decoded[4..5].to_vec(),
69-
parent_fingerprint: decoded[5..9].to_vec(),
70-
child_num: u32::from_be_bytes(core::convert::TryInto::try_into(&decoded[9..13]).unwrap()),
71-
chain_code: decoded[13..45].to_vec(),
72-
public_key: decoded[45..78].to_vec(),
71+
depth: xpub[4..5].to_vec(),
72+
parent_fingerprint: xpub[5..9].to_vec(),
73+
child_num: u32::from_be_bytes(core::convert::TryInto::try_into(&xpub[9..13]).unwrap()),
74+
chain_code: xpub[13..45].to_vec(),
75+
public_key: xpub[45..78].to_vec(),
7376
})
7477
}
7578

79+
/// Parses a Base58Check-encoded xpub string. The 4 version bytes are not checked and discarded.
80+
#[cfg(test)]
81+
pub fn parse_xpub(xpub: &str) -> Result<pb::XPub, ()> {
82+
let decoded = bs58::decode(xpub).with_check(None).into_vec().or(Err(()))?;
83+
parse_xpub_bytes(&decoded)
84+
}
85+
7686
#[cfg(test)]
7787
mod tests {
7888
use super::*;

src/rust/bitbox02-rust/src/hww/api/bitcoin.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::workflow::confirm;
3232

3333
use util::bip32::HARDENED;
3434

35-
use bitbox02::keystore::{encode_xpub_at_keypath, xpub_type_t};
35+
use crate::keystore;
3636

3737
use pb::btc_pub_request::{Output, XPubType};
3838
use pb::btc_request::Request;
@@ -105,21 +105,12 @@ async fn xpub(
105105
) -> Result<Response, Error> {
106106
let params = params::get(coin);
107107
keypath::validate_xpub(keypath, params.bip44_coin, params.taproot_support)?;
108-
let xpub_type = match xpub_type {
109-
XPubType::Tpub => xpub_type_t::TPUB,
110-
XPubType::Xpub => xpub_type_t::XPUB,
111-
XPubType::Ypub => xpub_type_t::YPUB,
112-
XPubType::Zpub => xpub_type_t::ZPUB,
113-
XPubType::Vpub => xpub_type_t::VPUB,
114-
XPubType::Upub => xpub_type_t::UPUB,
115-
XPubType::CapitalVpub => xpub_type_t::CAPITAL_VPUB,
116-
XPubType::CapitalZpub => xpub_type_t::CAPITAL_ZPUB,
117-
XPubType::CapitalUpub => xpub_type_t::CAPITAL_UPUB,
118-
XPubType::CapitalYpub => xpub_type_t::CAPITAL_YPUB,
119-
};
120-
let xpub = encode_xpub_at_keypath(keypath, xpub_type).or(Err(Error::InvalidInput))?;
108+
let xpub = crate::bip32::serialize_xpub_str(
109+
&keystore::get_xpub(keypath).or(Err(Error::InvalidInput))?,
110+
xpub_type,
111+
)?;
121112
if display {
122-
let title = format!("{}\naccount #{}", params.name, keypath[2] - HARDENED + 1,);
113+
let title = format!("{}\naccount #{}", params.name, keypath[2] - HARDENED + 1);
123114
let confirm_params = confirm::Params {
124115
title: &title,
125116
body: &xpub,

src/rust/bitbox02-rust/src/hww/api/bitcoin/common.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ impl Payload {
7777
) -> Result<Self, Error> {
7878
match simple_type {
7979
SimpleType::P2wpkh => Ok(Payload {
80-
data: keystore::secp256k1_pubkey_hash160(keypath)?.to_vec(),
80+
data: crate::keystore::secp256k1_pubkey_hash160(keypath)?,
8181
output_type: BtcOutputType::P2wpkh,
8282
}),
8383
SimpleType::P2wpkhP2sh => {
8484
let payload_p2wpkh = Payload::from_simple(params, SimpleType::P2wpkh, keypath)?;
8585
let pkscript_p2wpkh = payload_p2wpkh.pk_script(params)?;
8686
Ok(Payload {
87-
data: bitbox02::app_btc::hash160(&pkscript_p2wpkh).to_vec(),
87+
data: bitbox02::hash160(&pkscript_p2wpkh).to_vec(),
8888
output_type: BtcOutputType::P2sh,
8989
})
9090
}
@@ -134,7 +134,7 @@ impl Payload {
134134
pb::btc_script_config::multisig::ScriptType::P2wshP2sh => {
135135
let pkscript_p2wsh = payload_p2wsh.pk_script(params)?;
136136
Ok(Payload {
137-
data: bitbox02::app_btc::hash160(&pkscript_p2wsh).to_vec(),
137+
data: bitbox02::hash160(&pkscript_p2wsh).to_vec(),
138138
output_type: BtcOutputType::P2sh,
139139
})
140140
}

0 commit comments

Comments
 (0)