Skip to content

Commit 57add1e

Browse files
committed
keystore: simplify xpub encoding
Encoding with different versions (xpub, ypub, zpub, etc.) is already implemented in Rust. No need to have the same in C.
1 parent 1ebe611 commit 57add1e

File tree

11 files changed

+33
-202
lines changed

11 files changed

+33
-202
lines changed

src/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@ add_custom_target(rust-bindgen
322322
--allowlist-var EC_PUBLIC_KEY_LEN
323323
--allowlist-function keystore_encode_xpub_at_keypath
324324
--allowlist-function keystore_encrypt_and_store_seed
325-
--rustified-enum xpub_type_t
326325
--allowlist-var XPUB_ENCODED_LEN
327326
--allowlist-function lock_animation_start
328327
--allowlist-function lock_animation_stop

src/keystore.c

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -681,82 +681,27 @@ bool keystore_get_ed25519_seed(uint8_t* seed_out)
681681
return true;
682682
}
683683

684-
static const uint8_t _xpub_version[4] = {0x04, 0x88, 0xb2, 0x1e};
685-
static const uint8_t _ypub_version[4] = {0x04, 0x9d, 0x7c, 0xb2};
686-
static const uint8_t _zpub_version[4] = {0x04, 0xb2, 0x47, 0x46};
687-
static const uint8_t _tpub_version[4] = {0x04, 0x35, 0x87, 0xcf};
688-
static const uint8_t _vpub_version[4] = {0x04, 0x5f, 0x1c, 0xf6};
689-
static const uint8_t _upub_version[4] = {0x04, 0x4a, 0x52, 0x62};
690-
static const uint8_t _capital_vpub_version[4] = {0x02, 0x57, 0x54, 0x83};
691-
static const uint8_t _capital_zpub_version[4] = {0x02, 0xaa, 0x7e, 0xd3};
692-
static const uint8_t _capital_upub_version[4] = {0x02, 0x42, 0x89, 0xef};
693-
static const uint8_t _capital_ypub_version[4] = {0x02, 0x95, 0xb4, 0x3f};
694-
695-
bool keystore_encode_xpub(
696-
const struct ext_key* xpub,
697-
xpub_type_t xpub_type,
698-
char* out,
699-
size_t out_len)
684+
bool keystore_encode_xpub(const struct ext_key* xpub, char* out, size_t out_len)
700685
{
701686
uint8_t bytes[BIP32_SERIALIZED_LEN] = {0};
702687
if (bip32_key_serialize(xpub, BIP32_FLAG_KEY_PUBLIC, bytes, sizeof(bytes)) != WALLY_OK) {
703688
return false;
704689
}
705-
706-
const uint8_t* version;
707-
switch (xpub_type) {
708-
case XPUB:
709-
version = _xpub_version;
710-
break;
711-
case YPUB:
712-
version = _ypub_version;
713-
break;
714-
case ZPUB:
715-
version = _zpub_version;
716-
break;
717-
case TPUB:
718-
version = _tpub_version;
719-
break;
720-
case VPUB:
721-
version = _vpub_version;
722-
break;
723-
case UPUB:
724-
version = _upub_version;
725-
break;
726-
case CAPITAL_VPUB:
727-
version = _capital_vpub_version;
728-
break;
729-
case CAPITAL_ZPUB:
730-
version = _capital_zpub_version;
731-
break;
732-
case CAPITAL_UPUB:
733-
version = _capital_upub_version;
734-
break;
735-
case CAPITAL_YPUB:
736-
version = _capital_ypub_version;
737-
break;
738-
default:
739-
return false;
740-
}
741-
742-
// Overwrite bip32 version.
743-
memcpy(bytes, version, 4);
744690
return rust_base58_encode_check(
745691
rust_util_bytes(bytes, sizeof(bytes)), rust_util_cstr_mut(out, out_len));
746692
}
747693

748694
USE_RESULT bool keystore_encode_xpub_at_keypath(
749695
const uint32_t* keypath,
750696
size_t keypath_len,
751-
xpub_type_t xpub_type,
752697
char* out,
753698
size_t out_len)
754699
{
755700
struct ext_key derived_xpub __attribute__((__cleanup__(keystore_zero_xkey))) = {0};
756701
if (!keystore_get_xpub(keypath, keypath_len, &derived_xpub)) {
757702
return false;
758703
}
759-
return keystore_encode_xpub(&derived_xpub, xpub_type, out, out_len);
704+
return keystore_encode_xpub(&derived_xpub, out, out_len);
760705
}
761706

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

src/keystore.h

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -248,33 +248,15 @@ USE_RESULT bool keystore_get_u2f_seed(uint8_t* seed_out);
248248
*/
249249
USE_RESULT bool keystore_get_ed25519_seed(uint8_t* seed_out);
250250

251-
typedef enum {
252-
XPUB,
253-
YPUB,
254-
ZPUB,
255-
TPUB,
256-
VPUB,
257-
UPUB,
258-
CAPITAL_VPUB,
259-
CAPITAL_ZPUB,
260-
CAPITAL_UPUB,
261-
CAPITAL_YPUB,
262-
} xpub_type_t;
263251
/**
264252
* Encode an xpub as a base58 string.
265253
* @param[in] xpub the xpub to encode.
266-
* @param[in] xpub_type determines the xpub format.
267-
* etc.
268254
* @param[out] out resulting string, must be at least of size `XPUB_ENCODED_LEN` (including the null
269255
* terminator).
270256
* @param[in] out_len size of `out`.
271257
* @return false on failure, true on success.
272258
*/
273-
USE_RESULT bool keystore_encode_xpub(
274-
const struct ext_key* xpub,
275-
xpub_type_t xpub_type,
276-
char* out,
277-
size_t out_len);
259+
USE_RESULT bool keystore_encode_xpub(const struct ext_key* xpub, char* out, size_t out_len);
278260

279261
/**
280262
* Encode an xpub as a base58 string at the given `keypath`.
@@ -283,7 +265,6 @@ USE_RESULT bool keystore_encode_xpub(
283265
USE_RESULT bool keystore_encode_xpub_at_keypath(
284266
const uint32_t* keypath,
285267
size_t keypath_len,
286-
xpub_type_t xpub_type,
287268
char* out,
288269
size_t out_len);
289270

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/multisig.rs

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -287,21 +287,9 @@ pub fn validate(multisig: &Multisig, keypath: &[u32], expected_coin: u32) -> Res
287287
)
288288
.or(Err(Error::InvalidInput))?;
289289

290-
let our_xpub = {
291-
let our_xpub_str = bitbox02::keystore::encode_xpub_at_keypath(
292-
keypath,
293-
bitbox02::keystore::xpub_type_t::XPUB,
294-
)?;
295-
296-
bs58::decode(&our_xpub_str)
297-
.with_check(None)
298-
.into_vec()
299-
.or(Err(Error::Generic))?
300-
};
301-
let maybe_our_xpub = bip32::serialize_xpub(
302-
&multisig.xpubs[multisig.our_xpub_index as usize],
303-
Some(bip32::XPubType::Xpub),
304-
)?;
290+
let our_xpub = bip32::serialize_xpub(&crate::keystore::get_xpub(keypath)?, None)?;
291+
let maybe_our_xpub =
292+
bip32::serialize_xpub(&multisig.xpubs[multisig.our_xpub_index as usize], None)?;
305293
if our_xpub != maybe_our_xpub {
306294
return Err(Error::InvalidInput);
307295
}
@@ -786,14 +774,7 @@ mod tests {
786774
// invalid keypath, wrong purpose
787775
let mut invalid = multisig.clone();
788776
let keypath = &[49 + HARDENED, expected_coin, 0 + HARDENED, 2 + HARDENED];
789-
invalid.xpubs[1] = parse_xpub(
790-
&bitbox02::keystore::encode_xpub_at_keypath(
791-
keypath,
792-
bitbox02::keystore::xpub_type_t::XPUB,
793-
)
794-
.unwrap(),
795-
)
796-
.unwrap();
777+
invalid.xpubs[1] = crate::keystore::get_xpub(keypath).unwrap();
797778
assert!(validate(&invalid, keypath, expected_coin).is_err());
798779
}
799780

@@ -802,14 +783,7 @@ mod tests {
802783

803784
let mut invalid = multisig.clone();
804785
let keypath = &[48 + HARDENED, expected_coin + 1, 0 + HARDENED, 2 + HARDENED];
805-
invalid.xpubs[1] = parse_xpub(
806-
&bitbox02::keystore::encode_xpub_at_keypath(
807-
keypath,
808-
bitbox02::keystore::xpub_type_t::XPUB,
809-
)
810-
.unwrap(),
811-
)
812-
.unwrap();
786+
invalid.xpubs[1] = crate::keystore::get_xpub(keypath).unwrap();
813787
assert!(validate(&invalid, keypath, expected_coin).is_err());
814788
}
815789

@@ -818,14 +792,7 @@ mod tests {
818792

819793
let mut invalid = multisig.clone();
820794
let keypath = &[48 + HARDENED, expected_coin, 100 + HARDENED, 2 + HARDENED];
821-
invalid.xpubs[1] = parse_xpub(
822-
&bitbox02::keystore::encode_xpub_at_keypath(
823-
keypath,
824-
bitbox02::keystore::xpub_type_t::XPUB,
825-
)
826-
.unwrap(),
827-
)
828-
.unwrap();
795+
invalid.xpubs[1] = crate::keystore::get_xpub(keypath).unwrap();
829796
assert!(validate(&invalid, keypath, expected_coin).is_err());
830797
}
831798

@@ -834,14 +801,7 @@ mod tests {
834801

835802
let mut invalid = multisig.clone();
836803
let keypath = &[48 + HARDENED, expected_coin, 0 + HARDENED, 1 + HARDENED];
837-
invalid.xpubs[1] = parse_xpub(
838-
&bitbox02::keystore::encode_xpub_at_keypath(
839-
keypath,
840-
bitbox02::keystore::xpub_type_t::XPUB,
841-
)
842-
.unwrap(),
843-
)
844-
.unwrap();
804+
invalid.xpubs[1] = crate::keystore::get_xpub(keypath).unwrap();
845805
assert!(validate(&invalid, keypath, expected_coin).is_err());
846806
}
847807

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use super::Error;
1717

1818
use pb::response::Response;
1919

20-
use bitbox02::keystore;
20+
use crate::bip32;
21+
use crate::keystore;
2122

2223
const HARDENED: u32 = 0x80000000;
2324
const ELECTRUM_WALLET_ENCRYPTION_KEYPATH_LEVEL_ONE: u32 = 4541509 + HARDENED;
@@ -38,8 +39,10 @@ pub async fn process(
3839
{
3940
return Err(Error::InvalidInput);
4041
}
41-
let xpub = keystore::encode_xpub_at_keypath(keypath, keystore::xpub_type_t::XPUB)
42-
.or(Err(Error::InvalidInput))?;
42+
let xpub = bip32::serialize_xpub_str(
43+
&keystore::get_xpub(keypath).or(Err(Error::InvalidInput))?,
44+
bip32::XPubType::Xpub,
45+
)?;
4346

4447
Ok(Response::ElectrumEncryptionKey(
4548
pb::ElectrumEncryptionKeyResponse { key: xpub },

src/rust/bitbox02-rust/src/hww/api/ethereum/pubrequest.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ use super::Error;
1818
use pb::eth_pub_request::OutputType;
1919
use pb::eth_response::Response;
2020

21+
use crate::bip32;
22+
use crate::keystore;
2123
use crate::workflow::confirm;
22-
use bitbox02::keystore;
2324

2425
use core::convert::TryInto;
2526

@@ -78,8 +79,10 @@ fn process_xpub(request: &pb::EthPubRequest) -> Result<Response, Error> {
7879
if !super::keypath::is_valid_keypath_xpub(&request.keypath) {
7980
return Err(Error::InvalidInput);
8081
}
81-
let xpub = keystore::encode_xpub_at_keypath(&request.keypath, keystore::xpub_type_t::XPUB)
82-
.or(Err(Error::InvalidInput))?;
82+
let xpub = bip32::serialize_xpub_str(
83+
&keystore::get_xpub(&request.keypath).or(Err(Error::InvalidInput))?,
84+
bip32::XPubType::Xpub,
85+
)?;
8386

8487
Ok(Response::Pub(pb::PubResponse { r#pub: xpub }))
8588
}

src/rust/bitbox02-rust/src/keystore.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ use bitbox02::keystore;
2626
pub fn get_xpub(keypath: &[u32]) -> Result<pb::XPub, ()> {
2727
// Convert from C keystore to Rust by encoding the xpub in C and decoding it in Rust. Would be a
2828
// bit better to encode/decoding using the raw 78 bytes, not the base58Check encoding.
29-
bip32::parse_xpub(&keystore::encode_xpub_at_keypath(
30-
keypath,
31-
keystore::xpub_type_t::XPUB,
32-
)?)
29+
bip32::parse_xpub(&keystore::encode_xpub_at_keypath(keypath)?)
3330
}
3431

3532
/// Return the hash160 of the secp256k1 public key at the keypath.

src/rust/bitbox02/src/keystore.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ use core::convert::TryInto;
2121
use crate::input::SafeInputString;
2222
use bitbox02_sys::keystore_error_t;
2323

24-
pub use bitbox02_sys::xpub_type_t;
25-
2624
pub const BIP39_WORDLIST_LEN: u16 = bitbox02_sys::BIP39_WORDLIST_LEN as u16;
2725
pub const EC_PUBLIC_KEY_UNCOMPRESSED_LEN: usize = bitbox02_sys::EC_PUBLIC_KEY_UNCOMPRESSED_LEN as _;
2826
pub const EC_PUBLIC_KEY_LEN: usize = bitbox02_sys::EC_PUBLIC_KEY_LEN as _;
@@ -200,13 +198,12 @@ pub fn secp256k1_pubkey_uncompressed(
200198
}
201199
}
202200

203-
pub fn encode_xpub_at_keypath(keypath: &[u32], xpub_type: xpub_type_t) -> Result<String, ()> {
201+
pub fn encode_xpub_at_keypath(keypath: &[u32]) -> Result<String, ()> {
204202
let mut xpub = [0u8; bitbox02_sys::XPUB_ENCODED_LEN as _];
205203
match unsafe {
206204
bitbox02_sys::keystore_encode_xpub_at_keypath(
207205
keypath.as_ptr(),
208206
keypath.len() as _,
209-
xpub_type,
210207
xpub.as_mut_ptr(),
211208
xpub.len() as _,
212209
)

0 commit comments

Comments
 (0)