You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h

656 lines
23 KiB

/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "py/objstr.h"
#include "embed/extmod/trezorobj.h"
#include "bip32.h"
#include "bip39.h"
#include "curves.h"
#include "memzero.h"
#if !BITCOIN_ONLY
#include "nem.h"
#endif
/// package: trezorcrypto.bip32
/// class HDNode:
/// """
/// BIP0032 HD node structure.
/// """
typedef struct _mp_obj_HDNode_t {
mp_obj_base_t base;
uint32_t fingerprint;
HDNode hdnode;
} mp_obj_HDNode_t;
STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type;
/// def __init__(
/// self,
/// depth: int,
/// fingerprint: int,
/// child_num: int,
/// chain_code: bytes,
/// private_key: bytes | None = None,
/// public_key: bytes | None = None,
/// curve_name: str | None = None,
/// ) -> None:
/// """
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw,
const mp_obj_t *args) {
STATIC const mp_arg_t allowed_args[] = {
{MP_QSTR_depth,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_none}},
{MP_QSTR_fingerprint,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_none}},
{MP_QSTR_child_num,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_none}},
{MP_QSTR_chain_code,
MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_private_key,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_public_key,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
{MP_QSTR_curve_name,
MP_ARG_KW_ONLY | MP_ARG_OBJ,
{.u_obj = mp_const_empty_bytes}},
};
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)] = {0};
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args),
allowed_args, vals);
mp_buffer_info_t chain_code = {0};
mp_buffer_info_t private_key = {0};
mp_buffer_info_t public_key = {0};
mp_buffer_info_t curve_name = {0};
const uint32_t depth = trezor_obj_get_uint(vals[0].u_obj);
const uint32_t fingerprint = trezor_obj_get_uint(vals[1].u_obj);
const uint32_t child_num = trezor_obj_get_uint(vals[2].u_obj);
mp_get_buffer_raise(vals[3].u_obj, &chain_code, MP_BUFFER_READ);
mp_get_buffer_raise(vals[4].u_obj, &private_key, MP_BUFFER_READ);
mp_get_buffer_raise(vals[5].u_obj, &public_key, MP_BUFFER_READ);
mp_get_buffer_raise(vals[6].u_obj, &curve_name, MP_BUFFER_READ);
if (32 != chain_code.len) {
mp_raise_ValueError("chain_code is invalid");
}
if (0 == public_key.len && 0 == private_key.len) {
mp_raise_ValueError("either public_key or private_key is required");
}
if (0 != private_key.len && 32 != private_key.len) {
mp_raise_ValueError("private_key is invalid");
}
if (0 != public_key.len && 33 != public_key.len) {
mp_raise_ValueError("public_key is invalid");
}
const curve_info *curve = NULL;
if (0 == curve_name.len) {
curve = get_curve_by_name(SECP256K1_NAME);
} else {
curve = get_curve_by_name(curve_name.buf);
}
if (NULL == curve) {
mp_raise_ValueError("curve_name is invalid");
}
mp_obj_HDNode_t *o = m_new_obj_with_finaliser(mp_obj_HDNode_t);
o->base.type = type;
o->fingerprint = fingerprint;
o->hdnode.depth = depth;
o->hdnode.child_num = child_num;
if (32 == chain_code.len) {
memcpy(o->hdnode.chain_code, chain_code.buf, 32);
} else {
memzero(o->hdnode.chain_code, 32);
}
if (32 == private_key.len) {
memcpy(o->hdnode.private_key, private_key.buf, 32);
} else {
memzero(o->hdnode.private_key, 32);
}
if (33 == public_key.len) {
memcpy(o->hdnode.public_key, public_key.buf, 33);
} else {
memzero(o->hdnode.public_key, 33);
}
o->hdnode.curve = curve;
return MP_OBJ_FROM_PTR(o);
}
/// def derive(self, index: int, public: bool = False) -> None:
/// """
/// Derive a BIP0032 child node in place.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(size_t n_args,
const mp_obj_t *args) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]);
uint32_t i = trezor_obj_get_uint(args[1]);
uint32_t fp = hdnode_fingerprint(&o->hdnode);
bool public = n_args > 2 && args[2] == mp_const_true;
int res = 0;
if (public) {
res = hdnode_public_ckd(&o->hdnode, i);
} else {
if (0 ==
memcmp(
o->hdnode.private_key,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
32)) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive, private key not set");
}
res = hdnode_private_ckd(&o->hdnode, i);
}
if (!res) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive");
}
o->fingerprint = fp;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_HDNode_derive_obj,
2, 3,
mod_trezorcrypto_HDNode_derive);
#if !BITCOIN_ONLY
/// def derive_cardano(self, index: int) -> None:
/// """
/// Derive a BIP0032 child node in place using Cardano algorithm.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive_cardano(mp_obj_t self,
mp_obj_t index) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint32_t i = mp_obj_get_int_truncated(index);
uint32_t fp = hdnode_fingerprint(&o->hdnode);
int res = 0;
// same as in derive
if (0 ==
memcmp(o->hdnode.private_key,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
32)) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive, private key not set");
}
// special for cardano
res = hdnode_private_ckd_cardano(&o->hdnode, i);
if (!res) {
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive");
}
o->fingerprint = fp;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_derive_cardano_obj,
mod_trezorcrypto_HDNode_derive_cardano);
#endif
/// def derive_path(self, path: Sequence[int]) -> None:
/// """
/// Go through a list of indexes and iteratively derive a child node in
/// place.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive_path(mp_obj_t self,
mp_obj_t path) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
// get path objects and length
size_t plen = 0;
mp_obj_t *pitems = NULL;
mp_obj_get_array(path, &plen, &pitems);
if (plen > 32) {
mp_raise_ValueError("Path cannot be longer than 32 indexes");
}
for (uint32_t pi = 0; pi < plen; pi++) {
if (pi == plen - 1) {
// fingerprint is calculated from the parent of the final derivation
o->fingerprint = hdnode_fingerprint(&o->hdnode);
}
uint32_t pitem = trezor_obj_get_uint(pitems[pi]);
if (!hdnode_private_ckd(&o->hdnode, pitem)) {
o->fingerprint = 0;
memzero(&o->hdnode, sizeof(o->hdnode));
mp_raise_ValueError("Failed to derive path");
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_derive_path_obj,
mod_trezorcrypto_HDNode_derive_path);
/// def serialize_public(self, version: int) -> str:
/// """
/// Serialize the public info from HD node to base58 string.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_serialize_public(mp_obj_t self,
mp_obj_t version) {
uint32_t ver = trezor_obj_get_uint(version);
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
vstr_t xpub = {0};
vstr_init_len(&xpub, XPUB_MAXLEN);
hdnode_fill_public_key(&o->hdnode);
int written = hdnode_serialize_public(&o->hdnode, o->fingerprint, ver,
xpub.buf, xpub.alloc);
if (written <= 0) {
vstr_clear(&xpub);
mp_raise_ValueError("Failed to serialize");
}
// written includes NULL at the end of the string
xpub.len = written - 1;
return mp_obj_new_str_from_vstr(&mp_type_str, &xpub);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_serialize_public_obj,
mod_trezorcrypto_HDNode_serialize_public);
/// def clone(self) -> HDNode:
/// """
/// Returns a copy of the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_clone(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
mp_obj_HDNode_t *copy = m_new_obj_with_finaliser(mp_obj_HDNode_t);
copy->base.type = &mod_trezorcrypto_HDNode_type;
copy->hdnode = o->hdnode;
copy->fingerprint = o->fingerprint;
return MP_OBJ_FROM_PTR(copy);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_clone_obj,
mod_trezorcrypto_HDNode_clone);
/// def depth(self) -> int:
/// """
/// Returns a depth of the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_depth(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->hdnode.depth);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_depth_obj,
mod_trezorcrypto_HDNode_depth);
/// def fingerprint(self) -> int:
/// """
/// Returns a fingerprint of the HD node (hash of the parent public key).
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_fingerprint(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->fingerprint);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_fingerprint_obj,
mod_trezorcrypto_HDNode_fingerprint);
/// def child_num(self) -> int:
/// """
/// Returns a child index of the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_child_num(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_int_from_uint(o->hdnode.child_num);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_child_num_obj,
mod_trezorcrypto_HDNode_child_num);
/// def chain_code(self) -> bytes:
/// """
/// Returns a chain code of the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_chain_code(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_bytes(o->hdnode.chain_code, sizeof(o->hdnode.chain_code));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_chain_code_obj,
mod_trezorcrypto_HDNode_chain_code);
/// def private_key(self) -> bytes:
/// """
/// Returns a private key of the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_bytes(o->hdnode.private_key, sizeof(o->hdnode.private_key));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_private_key_obj,
mod_trezorcrypto_HDNode_private_key);
/// def private_key_ext(self) -> bytes:
/// """
/// Returns a private key extension of the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_private_key_ext(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
return mp_obj_new_bytes(o->hdnode.private_key_extension,
sizeof(o->hdnode.private_key_extension));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_private_key_ext_obj,
mod_trezorcrypto_HDNode_private_key_ext);
/// def public_key(self) -> bytes:
/// """
/// Returns a public key of the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_public_key(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
hdnode_fill_public_key(&o->hdnode);
return mp_obj_new_bytes(o->hdnode.public_key, sizeof(o->hdnode.public_key));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode_public_key_obj,
mod_trezorcrypto_HDNode_public_key);
/// def address(self, version: int) -> str:
/// """
/// Compute a base58-encoded address string from the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_address(mp_obj_t self,
mp_obj_t version) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint32_t v = trezor_obj_get_uint(version);
vstr_t address = {0};
vstr_init_len(&address, ADDRESS_MAXLEN);
hdnode_get_address(&o->hdnode, v, address.buf, address.alloc);
address.len = strlen(address.buf);
return mp_obj_new_str_from_vstr(&mp_type_str, &address);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_address_obj,
mod_trezorcrypto_HDNode_address);
#if !BITCOIN_ONLY
/// def nem_address(self, network: int) -> str:
/// """
/// Compute a NEM address string from the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_address(mp_obj_t self,
mp_obj_t network) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
uint8_t n = trezor_obj_get_uint8(network);
vstr_t address = {0};
vstr_init_len(&address, NEM_ADDRESS_SIZE);
if (!hdnode_get_nem_address(&o->hdnode, n, address.buf)) {
vstr_clear(&address);
mp_raise_ValueError("Failed to compute a NEM address");
}
address.len = strlen(address.buf);
return mp_obj_new_str_from_vstr(&mp_type_str, &address);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_nem_address_obj,
mod_trezorcrypto_HDNode_nem_address);
/// def nem_encrypt(
/// self, transfer_public_key: bytes, iv: bytes, salt: bytes, payload: bytes
/// ) -> bytes:
/// """
/// Encrypts payload using the transfer's public key
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_nem_encrypt(size_t n_args,
const mp_obj_t *args) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]);
mp_buffer_info_t transfer_pk = {0};
mp_get_buffer_raise(args[1], &transfer_pk, MP_BUFFER_READ);
if (transfer_pk.len != 32) {
mp_raise_ValueError("transfer_public_key has invalid length");
}
mp_buffer_info_t iv = {0};
mp_get_buffer_raise(args[2], &iv, MP_BUFFER_READ);
if (iv.len != 16) {
mp_raise_ValueError("iv has invalid length");
}
mp_buffer_info_t salt = {0};
mp_get_buffer_raise(args[3], &salt, MP_BUFFER_READ);
if (salt.len != NEM_SALT_SIZE) {
mp_raise_ValueError("salt has invalid length");
}
mp_buffer_info_t payload = {0};
mp_get_buffer_raise(args[4], &payload, MP_BUFFER_READ);
if (payload.len == 0) {
mp_raise_ValueError("payload is empty");
}
vstr_t vstr = {0};
vstr_init_len(&vstr, NEM_ENCRYPTED_SIZE(payload.len));
if (!hdnode_nem_encrypt(
&o->hdnode, *(const ed25519_public_key *)transfer_pk.buf, iv.buf,
salt.buf, payload.buf, payload.len, (uint8_t *)vstr.buf)) {
mp_raise_ValueError("HDNode nem encrypt failed");
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
mod_trezorcrypto_HDNode_nem_encrypt_obj, 5, 5,
mod_trezorcrypto_HDNode_nem_encrypt);
/// def ethereum_pubkeyhash(self) -> bytes:
/// """
/// Compute an Ethereum pubkeyhash (aka address) from the HD node.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode_ethereum_pubkeyhash(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
vstr_t pkh = {0};
vstr_init_len(&pkh, 20);
hdnode_get_ethereum_pubkeyhash(&o->hdnode, (uint8_t *)pkh.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &pkh);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(
mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj,
mod_trezorcrypto_HDNode_ethereum_pubkeyhash);
#endif
/// def __del__(self) -> None:
/// """
/// Cleans up sensitive memory.
/// """
STATIC mp_obj_t mod_trezorcrypto_HDNode___del__(mp_obj_t self) {
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
o->fingerprint = 0;
memzero(&o->hdnode, sizeof(o->hdnode));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_HDNode___del___obj,
mod_trezorcrypto_HDNode___del__);
STATIC const mp_rom_map_elem_t mod_trezorcrypto_HDNode_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR___del__),
MP_ROM_PTR(&mod_trezorcrypto_HDNode___del___obj)},
{MP_ROM_QSTR(MP_QSTR_derive),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_obj)},
#if !BITCOIN_ONLY
{MP_ROM_QSTR(MP_QSTR_derive_cardano),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_cardano_obj)},
#endif
{MP_ROM_QSTR(MP_QSTR_derive_path),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_derive_path_obj)},
{MP_ROM_QSTR(MP_QSTR_serialize_public),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_serialize_public_obj)},
{MP_ROM_QSTR(MP_QSTR_clone),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_clone_obj)},
{MP_ROM_QSTR(MP_QSTR_depth),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_depth_obj)},
{MP_ROM_QSTR(MP_QSTR_fingerprint),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_fingerprint_obj)},
{MP_ROM_QSTR(MP_QSTR_child_num),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_child_num_obj)},
{MP_ROM_QSTR(MP_QSTR_chain_code),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_chain_code_obj)},
{MP_ROM_QSTR(MP_QSTR_private_key),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_obj)},
{MP_ROM_QSTR(MP_QSTR_private_key_ext),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_private_key_ext_obj)},
{MP_ROM_QSTR(MP_QSTR_public_key),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_public_key_obj)},
{MP_ROM_QSTR(MP_QSTR_address),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_address_obj)},
#if !BITCOIN_ONLY
{MP_ROM_QSTR(MP_QSTR_nem_address),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_address_obj)},
{MP_ROM_QSTR(MP_QSTR_nem_encrypt),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_nem_encrypt_obj)},
{MP_ROM_QSTR(MP_QSTR_ethereum_pubkeyhash),
MP_ROM_PTR(&mod_trezorcrypto_HDNode_ethereum_pubkeyhash_obj)},
#endif
};
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_HDNode_locals_dict,
mod_trezorcrypto_HDNode_locals_dict_table);
STATIC const mp_obj_type_t mod_trezorcrypto_HDNode_type = {
{&mp_type_type},
.name = MP_QSTR_HDNode,
.make_new = mod_trezorcrypto_HDNode_make_new,
.locals_dict = (void *)&mod_trezorcrypto_HDNode_locals_dict,
};
/// mock:global
/// def from_seed(seed: bytes, curve_name: str) -> HDNode:
/// """
/// Construct a BIP0032 HD node from a BIP0039 seed value.
/// """
STATIC mp_obj_t mod_trezorcrypto_bip32_from_seed(mp_obj_t seed,
mp_obj_t curve_name) {
mp_buffer_info_t seedb = {0};
mp_get_buffer_raise(seed, &seedb, MP_BUFFER_READ);
if (seedb.len == 0) {
mp_raise_ValueError("Invalid seed");
}
mp_buffer_info_t curveb = {0};
mp_get_buffer_raise(curve_name, &curveb, MP_BUFFER_READ);
if (curveb.len == 0) {
mp_raise_ValueError("Invalid curve name");
}
HDNode hdnode = {0};
int res = 0;
if (strcmp(curveb.buf, ED25519_CARDANO_NAME) != 0) {
res = hdnode_from_seed(seedb.buf, seedb.len, curveb.buf, &hdnode);
#if !BITCOIN_ONLY
} else {
res = hdnode_from_seed_cardano(seedb.buf, seedb.len, &hdnode);
#endif
}
if (!res) {
mp_raise_ValueError("Failed to derive the root node");
}
mp_obj_HDNode_t *o = m_new_obj_with_finaliser(mp_obj_HDNode_t);
o->base.type = &mod_trezorcrypto_HDNode_type;
o->hdnode = hdnode;
o->fingerprint = 0;
return MP_OBJ_FROM_PTR(o);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip32_from_seed_obj,
mod_trezorcrypto_bip32_from_seed);
#if !BITCOIN_ONLY
/// def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> HDNode:
/// """
/// Construct a HD node from a BIP-0039 mnemonic using the Icarus derivation
/// scheme, aka v2 derivation scheme.
/// """
STATIC mp_obj_t mod_trezorcrypto_bip32_from_mnemonic_cardano(
mp_obj_t mnemonic, mp_obj_t passphrase) {
mp_buffer_info_t mnemo = {0}, phrase = {0};
mp_get_buffer_raise(mnemonic, &mnemo, MP_BUFFER_READ);
mp_get_buffer_raise(passphrase, &phrase, MP_BUFFER_READ);
HDNode hdnode = {0};
const char *pmnemonic = mnemo.len > 0 ? mnemo.buf : "";
const char *ppassphrase = phrase.len > 0 ? phrase.buf : "";
uint8_t mnemonic_bits[64] = {0};
int mnemonic_bits_len = mnemonic_to_bits(pmnemonic, mnemonic_bits);
if (mnemonic_bits_len == 0) {
mp_raise_ValueError("Invalid mnemonic");
}
// BEWARE: passing of mnemonic_bits (i.e. entropy + checksum bits) into
// hdnode_from_entropy_cardano_icarus() is actually not correct and we should
// be passing the entropy alone. However, the bug is there since Cardano
// support has been launched for Trezor and its reversal would result in
// people with a 24-word mnemonic on Trezor losing access to their Cardano
// funds. More info at https://github.com/trezor/trezor-firmware/issues/1387
const int res = hdnode_from_entropy_cardano_icarus(
(const uint8_t *)ppassphrase, phrase.len, mnemonic_bits,
mnemonic_bits_len / 8, &hdnode);
if (!res) {
mp_raise_ValueError(
"Secret key generation from mnemonic is looping forever");
} else if (res == -1) {
mp_raise_ValueError("Invalid mnemonic");
}
mp_obj_HDNode_t *o = m_new_obj_with_finaliser(mp_obj_HDNode_t);
o->base.type = &mod_trezorcrypto_HDNode_type;
o->hdnode = hdnode;
o->fingerprint = 0;
return MP_OBJ_FROM_PTR(o);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(
mod_trezorcrypto_bip32_from_mnemonic_cardano_obj,
mod_trezorcrypto_bip32_from_mnemonic_cardano);
#endif
STATIC const mp_rom_map_elem_t mod_trezorcrypto_bip32_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bip32)},
{MP_ROM_QSTR(MP_QSTR_HDNode), MP_ROM_PTR(&mod_trezorcrypto_HDNode_type)},
{MP_ROM_QSTR(MP_QSTR_from_seed),
MP_ROM_PTR(&mod_trezorcrypto_bip32_from_seed_obj)},
#if !BITCOIN_ONLY
{MP_ROM_QSTR(MP_QSTR_from_mnemonic_cardano),
MP_ROM_PTR(&mod_trezorcrypto_bip32_from_mnemonic_cardano_obj)},
#endif
};
STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_bip32_globals,
mod_trezorcrypto_bip32_globals_table);
STATIC const mp_obj_module_t mod_trezorcrypto_bip32_module = {
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mod_trezorcrypto_bip32_globals,
};