diff --git a/apps/btc_family/btc_helpers.c b/apps/btc_family/btc_helpers.c index b182ef600..7cc85c1c6 100644 --- a/apps/btc_family/btc_helpers.c +++ b/apps/btc_family/btc_helpers.c @@ -62,10 +62,18 @@ #include "btc_helpers.h" +#include +#include + +#include "bignum.h" #include "btc_priv.h" #include "coin_utils.h" +#include "ecdsa.h" #include "flash_config.h" +#include "secp256k1.h" #include "segwit_addr.h" +#include "sha2.h" +#include "utils.h" /***************************************************************************** * EXTERN VARIABLES @@ -86,6 +94,12 @@ /***************************************************************************** * STATIC VARIABLES *****************************************************************************/ +// sha256("TapTweak") used in BIP-340 +// This is used to derive the taproot address +static const uint8_t tap_tweak_hash[32] = { + 232, 15, 225, 99, 156, 156, 160, 80, 227, 175, 27, + 57, 193, 67, 198, 62, 66, 156, 188, 235, 21, 217, + 64, 251, 181, 197, 161, 244, 175, 87, 197, 233}; /***************************************************************************** * GLOBAL VARIABLES @@ -95,6 +109,99 @@ * STATIC FUNCTIONS *****************************************************************************/ +// Computes sha256(tap_tweak_hash + tap_tweak_hash + x_only_public_key + +// root_hash) and stores the result in tweak_key_hash. +static bool bip340_tweak_key_hash(const uint8_t *x_only_public_key, + const uint8_t *root_hash, + uint8_t tweak_key_hash[32]) { + if (NULL == x_only_public_key || NULL == tweak_key_hash) { + return false; + } + + size_t payload_size = + 32 * 3; // tap_tweak_hash + tap_tweak_hash + x_only_public_key + if (root_hash != NULL) { + payload_size += 32; + } + + uint8_t payload[payload_size]; + memzero(payload, payload_size); + // Prepare the data for hashing + memcpy(payload, tap_tweak_hash, 32); + memcpy(payload + 32, tap_tweak_hash, 32); + memcpy(payload + 64, x_only_public_key, 32); + if (root_hash != NULL) { + memcpy(payload + 32 * 3, root_hash, 32); + } + + sha256_Raw(payload, payload_size, tweak_key_hash); + return true; +} + +// Calculates result = (public_key_point + tweak_key_hash * G).x +static bool bip340_point_add_tweak(const ecdsa_curve *curve, + const uint8_t *public_key, + const uint8_t *tweak_key_hash, + uint8_t result[32]) { + if (NULL == public_key || NULL == tweak_key_hash || NULL == result) { + return false; + } + + curve_point public_key_point = {0}; + if (!ecdsa_read_pubkey(curve, public_key, &public_key_point)) { + return false; + } + + // Negate y-coordinate if it's odd + if (bn_is_odd(&public_key_point.y)) { + bn_subtract(&curve->prime, &public_key_point.y, &public_key_point.y); + bn_mod(&public_key_point.y, &curve->prime); + } + + bignum256 tweak_hash_bn; + bn_read_be(tweak_key_hash, &tweak_hash_bn); + bn_mod(&tweak_hash_bn, &curve->order); + + if (bn_is_zero(&tweak_hash_bn)) { + return false; + } + + curve_point result_point = {0}; + point_multiply(curve, + &tweak_hash_bn, + &curve->G, + &result_point); // result_point = tweak_hash_bn * G + point_add(curve, + &public_key_point, + &result_point); // result_point = public_key_point + result_point + + // take the x-coordinate of the result point + bn_write_be(&result_point.x, result); + return true; +} + +// implementation of BIP-340 tweak public key for taproot without using +// secp256k1 library +static bool bip340_tweak_public_key(const uint8_t *public_key, + const uint8_t *root_hash, + uint8_t *tweaked_public_key) { + if (NULL == public_key || NULL == tweaked_public_key) { + return false; + } + + uint8_t tweak_key_hash[32] = {0}; + if (!bip340_tweak_key_hash(public_key + 1, root_hash, tweak_key_hash)) { + return false; + } + + if (!bip340_point_add_tweak( + &secp256k1, public_key, tweak_key_hash, tweaked_public_key)) { + return false; + } + + return true; +} + /***************************************************************************** * GLOBAL FUNCTIONS *****************************************************************************/ @@ -208,3 +315,18 @@ void format_value(const uint64_t value_in_sat, snprintf( msg, msg_len, "%0.*f %s", precision, fee_in_btc, g_btc_app->lunit_name); } + +int btc_get_taproot_address(uint8_t *public_key, + const char *hrp, + char *address) { + if (NULL == public_key || NULL == hrp || NULL == address) { + return 0; + } + + uint8_t tweaked_public_key[32] = {0}; + if (!bip340_tweak_public_key(public_key, NULL, tweaked_public_key)) { + return 0; + } + + return segwit_addr_encode(address, hrp, 1, tweaked_public_key, 32); +} diff --git a/apps/btc_family/btc_helpers.h b/apps/btc_family/btc_helpers.h index a90ba340d..fed2e5ceb 100644 --- a/apps/btc_family/btc_helpers.h +++ b/apps/btc_family/btc_helpers.h @@ -137,4 +137,19 @@ bool btc_derivation_path_guard(const uint32_t *path, uint32_t depth); */ void format_value(uint64_t value_in_sat, char *msg, size_t msg_len); +/** + * @brief Returns the taproot key path address string (Bech32M encoding) + * @details The functions assumes public key is compressed + * + * @param [in] public_key 33 Byte array representation of public key. + * @param [in] hrp HRP value for bech32M encoding "bc" for mainnet and + * "tb" for testnet. + * @param [out] address char array to store taproot address. + * + * @return 1 if successful and 0 if failure. + */ +int btc_get_taproot_address(uint8_t *public_key, + const char *hrp, + char *address); + #endif diff --git a/apps/btc_family/btc_pub_key.c b/apps/btc_family/btc_pub_key.c index c8a7f3f3b..4ad7048c0 100644 --- a/apps/btc_family/btc_pub_key.c +++ b/apps/btc_family/btc_pub_key.c @@ -199,7 +199,7 @@ static size_t btc_get_address(const uint8_t *seed, uint8_t *public_key, char *address) { HDNode node = {0}; - char addr[50] = ""; + char addr[70] = ""; size_t address_length = 0; if (!derive_hdnode_from_path( @@ -230,7 +230,9 @@ static size_t btc_get_address(const uint8_t *seed, 36); break; - // TODO: add support for taproot + case PURPOSE_TAPROOT: + btc_get_taproot_address(node.public_key, g_btc_app->bech32_hrp, addr); + break; default: break; } diff --git a/common/coin_support/coin_utils.c b/common/coin_support/coin_utils.c index 7e42fd171..b623126d1 100644 --- a/common/coin_support/coin_utils.c +++ b/common/coin_support/coin_utils.c @@ -127,7 +127,7 @@ void bech32_addr_encode(char *output, uint8_t data[65] = {0}; size_t datalen = 0; convert_bits(data, &datalen, 5, address_bytes, byte_len, 8, 1); - bech32_encode(output, hrp, data, datalen); + bech32_encode(output, hrp, data, datalen, BECH32_ENCODING_BECH32); } FUNC_RETURN_CODES hd_path_array_to_string(const uint32_t *path, diff --git a/common/libraries/crypto/segwit_addr.c b/common/libraries/crypto/segwit_addr.c index 584ae639c..2be72ada8 100644 --- a/common/libraries/crypto/segwit_addr.c +++ b/common/libraries/crypto/segwit_addr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017 Pieter Wuille +/* Copyright (c) 2017, 2021 Pieter Wuille * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -18,174 +18,230 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include +#include "segwit_addr.h" + #include +#include #include -#include "segwit_addr.h" +static uint32_t bech32_polymod_step(uint32_t pre) { + uint8_t b = pre >> 25; + return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ + (-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^ + (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL); +} -uint32_t bech32_polymod_step(uint32_t pre) { - uint8_t b = pre >> 25; - return ((pre & 0x1FFFFFF) << 5) ^ - (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ - (-((b >> 1) & 1) & 0x26508e6dUL) ^ - (-((b >> 2) & 1) & 0x1ea119faUL) ^ - (-((b >> 3) & 1) & 0x3d4233ddUL) ^ - (-((b >> 4) & 1) & 0x2a1462b3UL); +static uint32_t bech32_final_constant(bech32_encoding enc) { + if (enc == BECH32_ENCODING_BECH32) + return 1; + if (enc == BECH32_ENCODING_BECH32M) + return 0x2bc830a3; + return 0; } -static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; +static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; static const int8_t charset_rev[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, - -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, - 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 -}; - -int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) { - uint32_t chk = 1; - size_t i = 0; - while (hrp[i] != 0) { - int ch = hrp[i]; - if (ch < 33 || ch > 126) { - return 0; - } + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, + 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, + 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, + -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, + 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; - if (ch >= 'A' && ch <= 'Z') return 0; - chk = bech32_polymod_step(chk) ^ (ch >> 5); - ++i; +int bech32_encode(char *output, + const char *hrp, + const uint8_t *data, + size_t data_len, + bech32_encoding enc) { + uint32_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + int ch = hrp[i]; + if (ch < 33 || ch > 126) { + return 0; } - if (i + 7 + data_len > 90) return 0; + + if (ch >= 'A' && ch <= 'Z') + return 0; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + ++i; + } + if (i + 7 + data_len > 90) + return 0; + chk = bech32_polymod_step(chk); + while (*hrp != 0) { + chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); + *(output++) = *(hrp++); + } + *(output++) = '1'; + for (i = 0; i < data_len; ++i) { + if (*data >> 5) + return 0; + chk = bech32_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for (i = 0; i < 6; ++i) { chk = bech32_polymod_step(chk); - while (*hrp != 0) { - chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); - *(output++) = *(hrp++); - } - *(output++) = '1'; - for (i = 0; i < data_len; ++i) { - if (*data >> 5) return 0; - chk = bech32_polymod_step(chk) ^ (*data); - *(output++) = charset[*(data++)]; - } - for (i = 0; i < 6; ++i) { - chk = bech32_polymod_step(chk); - } - chk ^= 1; - for (i = 0; i < 6; ++i) { - *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; - } - *output = 0; - return 1; + } + chk ^= bech32_final_constant(enc); + for (i = 0; i < 6; ++i) { + *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; } -int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) { - uint32_t chk = 1; - size_t i = 0; - size_t input_len = strlen(input); - size_t hrp_len = 0; - int have_lower = 0, have_upper = 0; - if (input_len < 8 || input_len > 90) { - return 0; - } - *data_len = 0; - while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { - ++(*data_len); +bech32_encoding bech32_decode(char *hrp, + uint8_t *data, + size_t *data_len, + const char *input) { + uint32_t chk = 1; + size_t i = 0; + size_t input_len = strlen(input); + size_t hrp_len = 0; + int have_lower = 0, have_upper = 0; + if (input_len < 8) { + return BECH32_ENCODING_NONE; + } + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if (1 + *data_len >= input_len || *data_len < 6 || + hrp_len > BECH32_MAX_HRP_LEN) { + return BECH32_ENCODING_NONE; + } + *(data_len) -= 6; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return BECH32_ENCODING_NONE; } - hrp_len = input_len - (1 + *data_len); - if (1 + *data_len >= input_len || *data_len < 6) { - return 0; + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; } - *(data_len) -= 6; - for (i = 0; i < hrp_len; ++i) { - int ch = input[i]; - if (ch < 33 || ch > 126) { - return 0; - } - if (ch >= 'a' && ch <= 'z') { - have_lower = 1; - } else if (ch >= 'A' && ch <= 'Z') { - have_upper = 1; - ch = (ch - 'A') + 'a'; - } - hrp[i] = ch; - chk = bech32_polymod_step(chk) ^ (ch >> 5); + hrp[i] = ch; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + } + hrp[i] = 0; + chk = bech32_polymod_step(chk); + for (i = 0; i < hrp_len; ++i) { + chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + } + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') + have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') + have_upper = 1; + if (v == -1) { + return BECH32_ENCODING_NONE; } - hrp[i] = 0; - chk = bech32_polymod_step(chk); - for (i = 0; i < hrp_len; ++i) { - chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + chk = bech32_polymod_step(chk) ^ v; + if (i + 6 < input_len) { + data[i - (1 + hrp_len)] = v; } ++i; - while (i < input_len) { - int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; - if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1; - if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1; - if (v == -1) { - return 0; - } - chk = bech32_polymod_step(chk) ^ v; - if (i + 6 < input_len) { - data[i - (1 + hrp_len)] = v; - } - ++i; - } - if (have_lower && have_upper) { - return 0; - } - return chk == 1; + } + if (have_lower && have_upper) { + return BECH32_ENCODING_NONE; + } + if (chk == bech32_final_constant(BECH32_ENCODING_BECH32)) { + return BECH32_ENCODING_BECH32; + } else if (chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) { + return BECH32_ENCODING_BECH32M; + } else { + return BECH32_ENCODING_NONE; + } } -int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } +int convert_bits(uint8_t *out, + size_t *outlen, + int outbits, + const uint8_t *in, + size_t inlen, + int inbits, + int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; } - return 1; + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; } -int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { - uint8_t data[65] = {0}; - size_t datalen = 0; - if (witver > 16) return 0; - if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; - if (witprog_len < 2 || witprog_len > 40) return 0; - data[0] = witver; - convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); - ++datalen; - return bech32_encode(output, hrp, data, datalen); +int segwit_addr_encode(char *output, + const char *hrp, + int witver, + const uint8_t *witprog, + size_t witprog_len) { + uint8_t data[65] = {0}; + size_t datalen = 0; + bech32_encoding enc = BECH32_ENCODING_BECH32; + if (witver > 16) + return 0; + if (witver == 0 && witprog_len != 20 && witprog_len != 32) + return 0; + if (witprog_len < 2 || witprog_len > 40) + return 0; + if (witver > 0) + enc = BECH32_ENCODING_BECH32M; + data[0] = witver; + convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); + ++datalen; + return bech32_encode(output, hrp, data, datalen, enc); } -int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { - uint8_t data[84] = {0}; - char hrp_actual[84] = {0}; - size_t data_len = 0; - if (!bech32_decode(hrp_actual, data, &data_len, addr)) return 0; - if (data_len == 0 || data_len > 65) return 0; - if (strncmp(hrp, hrp_actual, 84) != 0) return 0; - if (data[0] > 16) return 0; - *witdata_len = 0; - if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; - if (*witdata_len < 2 || *witdata_len > 40) return 0; - if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0; - *witver = data[0]; - return 1; +int segwit_addr_decode(int *witver, + uint8_t *witdata, + size_t *witdata_len, + const char *hrp, + const char *addr) { + uint8_t data[84] = {0}; + char hrp_actual[84] = {0}; + size_t data_len = 0; + if (strlen(addr) > 90) + return 0; + bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr); + if (enc == BECH32_ENCODING_NONE) + return 0; + if (data_len == 0 || data_len > 65) + return 0; + if (strncmp(hrp, hrp_actual, 84) != 0) + return 0; + if (data[0] > 16) + return 0; + if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) + return 0; + if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) + return 0; + *witdata_len = 0; + if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) + return 0; + if (*witdata_len < 2 || *witdata_len > 40) + return 0; + if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) + return 0; + *witver = data[0]; + return 1; } diff --git a/common/libraries/crypto/segwit_addr.h b/common/libraries/crypto/segwit_addr.h index 895676c45..8953840fe 100644 --- a/common/libraries/crypto/segwit_addr.h +++ b/common/libraries/crypto/segwit_addr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017 Pieter Wuille +/* Copyright (c) 2017, 2021 Pieter Wuille * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,12 +22,22 @@ #ifndef _SEGWIT_ADDR_H_ #define _SEGWIT_ADDR_H_ 1 +#include #include +// The maximum length of the Bech32 human-readable part according to BIP-173. +#define BECH32_MAX_HRP_LEN 83 + /** * Encode 8-bit data into 5-bit */ -int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad); +int convert_bits(uint8_t *out, + size_t *outlen, + int outbits, + const uint8_t *in, + size_t inlen, + int inbits, + int pad); /** Encode a SegWit address * @@ -40,8 +50,11 @@ int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, s * prog_len: Number of data bytes in prog. * Returns 1 if successful. */ -int segwit_addr_encode(char *output, const char *hrp, int ver, - const uint8_t *prog, size_t prog_len); +int segwit_addr_encode(char *output, + const char *hrp, + int ver, + const uint8_t *prog, + size_t prog_len); /** Decode a SegWit address * @@ -54,33 +67,51 @@ int segwit_addr_encode(char *output, const char *hrp, int ver, * readable part that is expected (chain/network specific). addr: Pointer to * the null-terminated address. Returns 1 if successful. */ -int segwit_addr_decode(int *ver, uint8_t *prog, size_t *prog_len, - const char *hrp, const char *addr); +int segwit_addr_decode(int *ver, + uint8_t *prog, + size_t *prog_len, + const char *hrp, + const char *addr); + +/** Supported encodings. */ +typedef enum { + BECH32_ENCODING_NONE, + BECH32_ENCODING_BECH32, + BECH32_ENCODING_BECH32M +} bech32_encoding; -/** Encode a Bech32 string +/** Encode a Bech32 or Bech32m string * * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that * will be updated to contain the null-terminated Bech32 string. * In: hrp : Pointer to the null-terminated human readable part. * data : Pointer to an array of 5-bit values. * data_len: Length of the data array. + * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). * Returns 1 if successful. */ -int bech32_encode(char *output, const char *hrp, const uint8_t *data, - size_t data_len); +int bech32_encode(char *output, + const char *hrp, + const uint8_t *data, + size_t data_len, + bech32_encoding enc); -/** Decode a Bech32 string +/** Decode a Bech32 or Bech32m string * - * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be + * Out: hrp: Pointer to a buffer of size BECH32_MAX_HRP_LEN + 1. Will be * updated to contain the null-terminated human readable part. * data: Pointer to a buffer of size strlen(input) - 8 that will * hold the encoded 5-bit data values. * data_len: Pointer to a size_t that will be updated to be the number * of entries in data. * In: input: Pointer to a null-terminated Bech32 string. - * Returns 1 if succesful. + * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful + * with the specified encoding standard. BECH32_ENCODING_NONE is returned if + * decoding failed. */ -int bech32_decode(char *hrp, uint8_t *data, size_t *data_len, - const char *input); +bech32_encoding bech32_decode(char *hrp, + uint8_t *data, + size_t *data_len, + const char *input); #endif