WIP feat(legacy): send BIP-380 descriptor in GetPublicKey response

[skip_ci]
mmilata/pubkey-descriptor-legacy
Martin Milata 2 months ago
parent 8d1ee10619
commit fb240bf48a

@ -42,3 +42,11 @@ size_t strlcat(char *dst, const char *src, size_t size) {
}
#endif
char *itoa(int i, char *dest, int base) {
if (base != 10) {
return dest;
}
int n = sprintf(dest, "%d", i);
return dest + n;
}

@ -27,4 +27,6 @@ size_t strlcpy(char *dst, const char *src, size_t size);
size_t strlcat(char *dst, const char *src, size_t size);
#endif
char *itoa(int i, char *dest, int base) {
#endif

@ -81,6 +81,56 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) {
resp->node.public_key.bytes[0] = 0;
}
bool descriptor = true;
size_t descriptor_len = 0;
if (script_type == InputScriptType_SPENDADDRESS) {
strlcpy(resp->descriptor, "pkh([", sizeof(resp->descriptor));
descriptor_len += 5;
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
strlcpy(resp->descriptor, "sh(wpkh([", sizeof(resp->descriptor));
descriptor_len += 9;
} else if (script_type == InputScriptType_SPENDWITNESS) {
strlcpy(resp->descriptor, "wpkh([", sizeof(resp->descriptor));
descriptor_len += 6;
} else if (script_type == InputScriptType_SPENDTAPROOT) {
strlcpy(resp->descriptor, "tr([", sizeof(resp->descriptor));
descriptor_len += 4;
} else {
descriptor = false;
}
if (descriptor) {
// FIXME this needs to be lowercase
uint32hex(root_fingerprint, resp->descriptor + descriptor_len);
descriptor_len += 8;
for (size_t i = 0; i < msg->address_n_count; i++) {
strlcpy(resp->descriptor + descriptor_len, "/",
sizeof(resp->descriptor) - descriptor_len);
descriptor_len++;
uint32_t unhardened = msg->address_n[i] & PATH_UNHARDEN_MASK;
if (descriptor_len + 17 > sizeof(resp->descriptor)) {
descriptor = false;
break;
}
char *result = itoa(unhardened, resp->descriptor + descriptor_len, 10);
descriptor_len += result - (resp->descriptor + descriptor_len);
if (msg->address_n[i] & PATH_HARDENED) {
strlcpy(resp->descriptor + descriptor_len, "'",
sizeof(resp->descriptor) - descriptor_len);
descriptor_len++;
}
}
strlcpy(resp->descriptor + descriptor_len, "]",
sizeof(resp->descriptor) - descriptor_len);
descriptor_len++;
}
if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS ||
script_type == InputScriptType_SPENDMULTISIG)) {
hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub,
@ -113,9 +163,37 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) {
layoutHome();
return;
}
if (descriptor) {
if (coin->xpub_magic) {
char tmp[XPUB_MAXLEN] = {0};
hdnode_serialize_public(node, fingerprint, coin->xpub_magic, tmp,
sizeof(tmp));
strlcpy(resp->descriptor + descriptor_len, tmp,
sizeof(resp->descriptor) - descriptor_len);
descriptor_len += strlen(tmp);
strlcpy(resp->descriptor + descriptor_len, "/<0;1>/*)",
sizeof(resp->descriptor) - descriptor_len);
descriptor_len += 9;
if (script_type == InputScriptType_SPENDP2SHWITNESS) {
strlcpy(resp->descriptor + descriptor_len, ")",
sizeof(resp->descriptor) - descriptor_len);
descriptor_len++;
}
strlcpy(resp->descriptor + descriptor_len, "#00000000",
sizeof(resp->descriptor) - descriptor_len);
descriptor_len += 9;
} else {
descriptor = false;
}
}
resp->has_descriptor = descriptor;
if (msg->has_show_display && msg->show_display) {
for (int page = 0; page < 2; page++) {
// TODO show descriptor
layoutXPUB(resp->xpub, page);
if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) {
memzero(resp, sizeof(PublicKey));

@ -3,7 +3,7 @@ GetPublicKey.ecdsa_curve_name max_size:32
GetPublicKey.coin_name max_size:21
PublicKey.xpub max_size:113
PublicKey.descriptor type:FT_IGNORE
PublicKey.descriptor max_size:180
GetAddress.address_n max_count:8
GetAddress.coin_name max_size:21

@ -161,14 +161,14 @@ def _address_n(purpose, coin, account, script_type):
return res
@pytest.mark.skip_t1
@pytest.mark.parametrize(
"coin, account, purpose, script_type, descriptors", VECTORS_DESCRIPTORS
)
def test_descriptors(client: Client, coin, account, purpose, script_type, descriptors):
with client:
IF = InputFlowShowXpubQRCode(client)
client.set_input_flow(IF.get())
if client.model != models.T1B1:
IF = InputFlowShowXpubQRCode(client)
client.set_input_flow(IF.get())
address_n = _address_n(purpose, coin, account, script_type)
res = btc.get_public_node(

Loading…
Cancel
Save