From f2cc8eecaa4bfad0fd32ac9e4ef723e9c03272ba Mon Sep 17 00:00:00 2001 From: Andrew Toth Date: Thu, 5 Sep 2024 13:41:52 -0400 Subject: [PATCH] crypto: return parity when tweaking public key --- .../extmod/modtrezorcrypto/modtrezorcrypto-bip340.h | 13 ++++++++++--- core/src/apps/bitcoin/addresses.py | 2 +- crypto/fuzzer/fuzzer.c | 2 +- crypto/tests/test_check.c | 2 +- crypto/zkp_bip340.c | 5 +++-- crypto/zkp_bip340.h | 3 ++- legacy/firmware/signing.c | 2 +- legacy/firmware/transaction.c | 3 ++- 8 files changed, 21 insertions(+), 11 deletions(-) diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip340.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip340.h index 1b28e4c891..01fa469530 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip340.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip340.h @@ -164,9 +164,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorcrypto_bip340_verify_obj, /// def tweak_public_key( /// public_key: bytes, /// root_hash: bytes | None = None, -/// ) -> bytes: +/// ) -> tuple[int, bytes]: /// """ /// Tweaks the public key with the specified root_hash. +/// First element of tuple is the parity, second is the tweaked public key. /// """ STATIC mp_obj_t mod_trezorcrypto_bip340_tweak_public_key(size_t n_args, const mp_obj_t *args) { @@ -188,13 +189,19 @@ STATIC mp_obj_t mod_trezorcrypto_bip340_tweak_public_key(size_t n_args, vstr_t tpk = {0}; vstr_init_len(&tpk, 32); + int parity = 0; int ret = zkp_bip340_tweak_public_key((const uint8_t *)pk.buf, rh_ptr, - (uint8_t *)tpk.buf); + (uint8_t *)tpk.buf, &parity); if (ret != 0) { vstr_clear(&tpk); mp_raise_ValueError("Failed to tweak public key"); } - return mp_obj_new_str_from_vstr(&mp_type_bytes, &tpk); + + mp_obj_t result[2]; + result[0] = mp_obj_new_int(parity); + result[1] = mp_obj_new_str_from_vstr(&mp_type_bytes, &tpk); + + return mp_obj_new_tuple(2, result); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( diff --git a/core/src/apps/bitcoin/addresses.py b/core/src/apps/bitcoin/addresses.py index 1c78ca1016..6d358b5552 100644 --- a/core/src/apps/bitcoin/addresses.py +++ b/core/src/apps/bitcoin/addresses.py @@ -153,7 +153,7 @@ def _address_p2tr(pubkey: bytes, coin: CoinInfo) -> str: from trezor.crypto.curve import bip340 assert coin.bech32_prefix is not None - output_pubkey = bip340.tweak_public_key(pubkey[1:]) + _, output_pubkey = bip340.tweak_public_key(pubkey[1:]) return encode_bech32_address(coin.bech32_prefix, 1, output_pubkey) diff --git a/crypto/fuzzer/fuzzer.c b/crypto/fuzzer/fuzzer.c index c235a0e5dd..d225331fee 100644 --- a/crypto/fuzzer/fuzzer.c +++ b/crypto/fuzzer/fuzzer.c @@ -1167,7 +1167,7 @@ int fuzz_zkp_bip340_tweak_keys(void) { // IDEA act on return values zkp_bip340_tweak_private_key(internal_priv, root_hash, result); - zkp_bip340_tweak_public_key(internal_pub, root_hash, result); + zkp_bip340_tweak_public_key(internal_pub, root_hash, result, NULL); return 0; } diff --git a/crypto/tests/test_check.c b/crypto/tests/test_check.c index 3dee168e6b..b41d166617 100644 --- a/crypto/tests/test_check.c +++ b/crypto/tests/test_check.c @@ -10587,7 +10587,7 @@ START_TEST(test_zkp_bip340_tweak) { ck_assert_int_eq(res, 0); ck_assert_mem_eq(output_priv, result, 32); - res = zkp_bip340_tweak_public_key(internal_pub, root_hash, result); + res = zkp_bip340_tweak_public_key(internal_pub, root_hash, result, NULL); ck_assert_int_eq(res, 0); ck_assert_mem_eq(output_pub, result, 32); } diff --git a/crypto/zkp_bip340.c b/crypto/zkp_bip340.c index 607cfb5655..3c6a8a6d2e 100644 --- a/crypto/zkp_bip340.c +++ b/crypto/zkp_bip340.c @@ -209,10 +209,11 @@ int zkp_bip340_verify_publickey(const uint8_t *public_key_bytes) { // internal_public_key has 32 bytes // root_hash has 32 bytes or is empty (NULL) // output_public_key has 32 bytes +// pk_parity will be set to the parity if not NULL // returns 0 on success int zkp_bip340_tweak_public_key(const uint8_t *internal_public_key, const uint8_t *root_hash, - uint8_t *output_public_key) { + uint8_t *output_public_key, int *pk_parity) { int result = 0; uint8_t tweak[SHA256_DIGEST_LENGTH] = {0}; @@ -250,7 +251,7 @@ int zkp_bip340_tweak_public_key(const uint8_t *internal_public_key, secp256k1_xonly_pubkey xonly_output_pubkey = {0}; if (result == 0) { if (secp256k1_xonly_pubkey_from_pubkey(context_read_only, - &xonly_output_pubkey, NULL, + &xonly_output_pubkey, pk_parity, &output_pubkey) != 1) { result = -1; } diff --git a/crypto/zkp_bip340.h b/crypto/zkp_bip340.h index 670384a4cb..42c694311c 100644 --- a/crypto/zkp_bip340.h +++ b/crypto/zkp_bip340.h @@ -14,7 +14,8 @@ int zkp_bip340_verify_digest(const uint8_t *public_key_bytes, int zkp_bip340_verify_publickey(const uint8_t *public_key_bytes); int zkp_bip340_tweak_public_key(const uint8_t *internal_public_key, const uint8_t *root_hash, - uint8_t *output_public_key); + uint8_t *output_public_key, + int *pk_parity); int zkp_bip340_tweak_private_key(const uint8_t *internal_private_key, const uint8_t *root_hash, uint8_t *output_private_key); diff --git a/legacy/firmware/signing.c b/legacy/firmware/signing.c index 4d7d700e15..104e3d59b4 100644 --- a/legacy/firmware/signing.c +++ b/legacy/firmware/signing.c @@ -2834,7 +2834,7 @@ static bool signing_verify_orig_nonlegacy_input(TxInputType *orig_input) { signing_hash_bip341(&orig_info, idx1, hash_type & 0xff, hash); uint8_t output_public_key[32] = {0}; valid = (zkp_bip340_tweak_public_key(node.public_key + 1, NULL, - output_public_key) == 0) && + output_public_key, NULL) == 0) && (zkp_bip340_verify_digest(output_public_key, sig, hash) == 0); } else { #if !BITCOIN_ONLY diff --git a/legacy/firmware/transaction.c b/legacy/firmware/transaction.c index a259d74cc7..85178c1f09 100644 --- a/legacy/firmware/transaction.c +++ b/legacy/firmware/transaction.c @@ -194,7 +194,8 @@ bool compute_address(const CoinInfo *coin, InputScriptType script_type, return 0; } uint8_t tweaked_pubkey[32]; - zkp_bip340_tweak_public_key(node->public_key + 1, NULL, tweaked_pubkey); + zkp_bip340_tweak_public_key(node->public_key + 1, NULL, tweaked_pubkey, + NULL); if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_1, tweaked_pubkey, 32)) { return 0;