From fce94dbd1be6e09b6479ce961d48419d9d2c4758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Fri, 25 Oct 2024 13:21:06 +0200 Subject: [PATCH 1/6] [hash] stop hasing the message to sign if the hash is not used Unused if the command is SIGN and the curve of the signee key is BLS --- src/apdu_sign.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/apdu_sign.c b/src/apdu_sign.c index 07af8f49..8f6a6a69 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -220,8 +220,20 @@ int handle_sign(buffer_t *cdata, const bool last, const bool with_hash) { TZ_FAIL(EXC_PARSE_ERROR); } - CX_CHECK( - cx_hash_no_throw((cx_hash_t *) &G.hash_state.state, 0, cdata->ptr, cdata->size, NULL, 0)); +#ifndef TARGET_NANOS + // There is no need to hash the message if it is not used for signing or if it is not sent at + // the end. + if (with_hash || (global.path_with_curve.derivation_type != DERIVATION_TYPE_BLS12_381)) { +#endif + CX_CHECK(cx_hash_no_throw((cx_hash_t *) &G.hash_state.state, + 0, + cdata->ptr, + cdata->size, + NULL, + 0)); +#ifndef TARGET_NANOS + } +#endif #ifndef TARGET_NANOS memmove(G.message, cdata->ptr, cdata->size); @@ -229,12 +241,20 @@ int handle_sign(buffer_t *cdata, const bool last, const bool with_hash) { #endif if (last) { - CX_CHECK(cx_hash_no_throw((cx_hash_t *) &G.hash_state.state, - CX_LAST, - NULL, - 0, - G.final_hash, - sizeof(G.final_hash))); +#ifndef TARGET_NANOS + // There is no need to hash the message if it is not used for signing or if it is not sent + // at the end. + if (with_hash || (global.path_with_curve.derivation_type != DERIVATION_TYPE_BLS12_381)) { +#endif + CX_CHECK(cx_hash_no_throw((cx_hash_t *) &G.hash_state.state, + CX_LAST, + NULL, + 0, + G.final_hash, + sizeof(G.final_hash))); +#ifndef TARGET_NANOS + } +#endif G.maybe_ops.is_valid = parse_operations_final(&G.parse_state, &G.maybe_ops.v); From 033fecb2d587b7fd09e49d53b88dd7f18579b143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Wed, 6 Nov 2024 09:17:00 +0100 Subject: [PATCH 2/6] [pk] store the pk each time the global.path_with_curve is changed prepare to stop derivating the pk too frequently --- src/apdu.c | 20 ++++++++++++++++++++ src/apdu.h | 14 ++++++++++++++ src/apdu_pubkey.c | 10 ++++++++-- src/apdu_setup.c | 10 ++++++---- src/apdu_sign.c | 7 ++++--- src/globals.h | 1 + 6 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/apdu.c b/src/apdu.c index 14848700..113c57fb 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -33,6 +33,26 @@ #include #include +tz_exc read_path_with_curve(derivation_type_t derivation_type, + buffer_t* buf, + bip32_path_with_curve_t* path_with_curve, + cx_ecfp_public_key_t* pubkey) { + tz_exc exc = SW_OK; + cx_err_t error = CX_OK; + + TZ_ASSERT_NOT_NULL(buf); + TZ_ASSERT_NOT_NULL(path_with_curve); + TZ_ASSERT_NOT_NULL(pubkey); + + path_with_curve->derivation_type = derivation_type; + TZ_ASSERT(read_bip32_path(buf, &path_with_curve->bip32_path), EXC_WRONG_VALUES); + CX_CHECK(generate_public_key(pubkey, path_with_curve)); + +end: + TZ_CONVERT_CX(); + return exc; +} + int provide_pubkey(bip32_path_with_curve_t const* const path_with_curve) { tz_exc exc = SW_OK; cx_err_t error = CX_OK; diff --git a/src/apdu.h b/src/apdu.h index 2af3016d..2bd403b2 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -87,6 +87,20 @@ static inline int io_send_apdu_err(uint16_t sw) { return io_send_sw(sw); } +/** + * @brief Reads a path with curve and derive the public key. + * + * @param[in] derivation_type: Derivation type of the key. + * @param[in] buf: Buffer that should contains a bip32 path. + * @param[out] path_with_curve: Buffer to store the path with curve. + * @param[out] pubkey: Buffer to store the pubkey. + * @return tz_exc: exception, SW_OK if none + */ +tz_exc read_path_with_curve(derivation_type_t derivation_type, + buffer_t* buf, + bip32_path_with_curve_t* path_with_curve, + cx_ecfp_public_key_t* pubkey); + /** * @brief Provides the public key in the apdu response * diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index 8d50102c..65307df8 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -69,15 +69,20 @@ int handle_get_public_key(buffer_t *cdata, bool authorize, bool prompt) { tz_exc exc = SW_OK; + cx_err_t error = CX_OK; TZ_ASSERT_NOT_NULL(cdata); - global.path_with_curve.derivation_type = derivation_type; if ((cdata->size == 0u) && authorize) { TZ_ASSERT(copy_bip32_path_with_curve(&global.path_with_curve, &(g_hwm.baking_key)), EXC_MEMORY_ERROR); + CX_CHECK(generate_public_key((cx_ecfp_public_key_t *) &global.public_key, + &global.path_with_curve)); } else { - TZ_ASSERT(read_bip32_path(cdata, &global.path_with_curve.bip32_path), EXC_WRONG_VALUES); + TZ_CHECK(read_path_with_curve(derivation_type, + cdata, + &global.path_with_curve, + (cx_ecfp_public_key_t *) &global.public_key)); } TZ_ASSERT(cdata->size == cdata->offset, EXC_WRONG_LENGTH); @@ -100,5 +105,6 @@ int handle_get_public_key(buffer_t *cdata, } end: + TZ_CONVERT_CX(); return io_send_apdu_err(exc); } diff --git a/src/apdu_setup.c b/src/apdu_setup.c index 06feb7bc..077a7ea7 100644 --- a/src/apdu_setup.c +++ b/src/apdu_setup.c @@ -72,14 +72,16 @@ int handle_setup(buffer_t *cdata, derivation_type_t derivation_type) { TZ_ASSERT_NOT_NULL(cdata); - global.path_with_curve.derivation_type = derivation_type; - TZ_ASSERT(buffer_read_u32(cdata, &G.main_chain_id.v, BE) && // chain id buffer_read_u32(cdata, &G.hwm.main, BE) && // main hwm level - buffer_read_u32(cdata, &G.hwm.test, BE) && // test hwm level - read_bip32_path(cdata, &global.path_with_curve.bip32_path), + buffer_read_u32(cdata, &G.hwm.test, BE), // test hwm level EXC_WRONG_VALUES); + TZ_CHECK(read_path_with_curve(derivation_type, + cdata, + &global.path_with_curve, + (cx_ecfp_public_key_t *) &global.public_key)); + TZ_ASSERT(cdata->size == cdata->offset, EXC_WRONG_LENGTH); return prompt_setup(ok, reject); diff --git a/src/apdu_sign.c b/src/apdu_sign.c index 8f6a6a69..e36dfba3 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -161,12 +161,13 @@ int select_signing_key(buffer_t *cdata, derivation_type_t derivation_type) { clear_data(); - TZ_ASSERT(read_bip32_path(cdata, &global.path_with_curve.bip32_path), EXC_WRONG_VALUES); + TZ_CHECK(read_path_with_curve(derivation_type, + cdata, + &global.path_with_curve, + (cx_ecfp_public_key_t *) &global.public_key)); TZ_ASSERT(cdata->size == cdata->offset, EXC_WRONG_LENGTH); - global.path_with_curve.derivation_type = derivation_type; - return io_send_sw(SW_OK); end: diff --git a/src/globals.h b/src/globals.h index dabc4fc5..fda140a1 100644 --- a/src/globals.h +++ b/src/globals.h @@ -123,6 +123,7 @@ typedef struct { } dynamic_display; bip32_path_with_curve_t path_with_curve; ///< holds the bip32 path and curve of the current key + tz_ecfp_public_key_t public_key; ///< holds the current public key /// apdu handling state struct { From 2e20ccf67c066389806d10e95bc80114b915db3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Mon, 28 Oct 2024 07:33:17 +0100 Subject: [PATCH 3/6] [get-pk] send the stored pk instead of derived it again --- src/apdu.c | 11 ++--------- src/apdu.h | 2 +- src/apdu_pubkey.c | 4 ++-- src/apdu_setup.c | 2 +- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/apdu.c b/src/apdu.c index 113c57fb..d99a6e82 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -53,22 +53,15 @@ tz_exc read_path_with_curve(derivation_type_t derivation_type, return exc; } -int provide_pubkey(bip32_path_with_curve_t const* const path_with_curve) { +int provide_pubkey(cx_ecfp_public_key_t const* const pubkey) { tz_exc exc = SW_OK; cx_err_t error = CX_OK; - TZ_ASSERT_NOT_NULL(path_with_curve); + TZ_ASSERT_NOT_NULL(pubkey); uint8_t resp[1u + MAX_SIGNATURE_SIZE] = {0}; size_t offset = 0; - // Application could be PIN-locked, and pubkey->W_len would then be 0, - // so throwing an error rather than returning an empty key - TZ_ASSERT(os_global_pin_is_validated() == BOLOS_UX_OK, EXC_SECURITY); - - cx_ecfp_public_key_t* pubkey = (cx_ecfp_public_key_t*) &(tz_ecfp_public_key_t){0}; - CX_CHECK(generate_public_key(pubkey, path_with_curve)); - resp[offset] = pubkey->W_len; offset++; memmove(resp + offset, pubkey->W, pubkey->W_len); diff --git a/src/apdu.h b/src/apdu.h index 2bd403b2..a06ec76c 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -109,4 +109,4 @@ tz_exc read_path_with_curve(derivation_type_t derivation_type, * @param path_with_curve: bip32 path and curve of the key * @return int: zero or positive integer if success, negative integer otherwise. */ -int provide_pubkey(bip32_path_with_curve_t const* const path_with_curve); +int provide_pubkey(cx_ecfp_public_key_t const* const pubkey); diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index 65307df8..06f68bc7 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -38,7 +38,7 @@ * @return true */ static bool pubkey_ok(void) { - provide_pubkey(&global.path_with_curve); + provide_pubkey((cx_ecfp_public_key_t *) &global.public_key); return true; } @@ -88,7 +88,7 @@ int handle_get_public_key(buffer_t *cdata, TZ_ASSERT(cdata->size == cdata->offset, EXC_WRONG_LENGTH); if (!prompt) { - return provide_pubkey(&global.path_with_curve); + return provide_pubkey((cx_ecfp_public_key_t *) &global.public_key); } else { // INS_PROMPT_PUBLIC_KEY || INS_AUTHORIZE_BAKING ui_callback_t cb; diff --git a/src/apdu_setup.c b/src/apdu_setup.c index 077a7ea7..3f3d7bb4 100644 --- a/src/apdu_setup.c +++ b/src/apdu_setup.c @@ -55,7 +55,7 @@ static bool ok(void) { UPDATE_NVRAM; - provide_pubkey(&global.path_with_curve); + provide_pubkey((cx_ecfp_public_key_t *) &global.public_key); return true; } From 47c61e59910a70d58a8efd81f37d87e1220802bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Mon, 28 Oct 2024 08:57:42 +0100 Subject: [PATCH 4/6] [pkh] use the stored pk to derive the pkh --- src/apdu_sign.c | 4 ++- src/keys.c | 56 +++++++--------------------------------- src/keys.h | 33 +++++++++++------------ src/operations.c | 29 ++++++++++----------- src/operations.h | 7 +++-- src/to_string.c | 15 +++++------ src/to_string.h | 10 +++---- src/ui_bagl.c | 12 ++++++--- src/ui_delegation_bagl.c | 6 ++--- src/ui_delegation_nbgl.c | 6 ++--- src/ui_nbgl.c | 10 ++++--- src/ui_pubkey_bagl.c | 6 ++--- src/ui_pubkey_nbgl.c | 6 ++--- src/ui_setup_bagl.c | 6 ++--- src/ui_setup_nbgl.c | 6 ++--- 15 files changed, 91 insertions(+), 121 deletions(-) diff --git a/src/apdu_sign.c b/src/apdu_sign.c index e36dfba3..709c5742 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -215,7 +215,9 @@ int handle_sign(buffer_t *cdata, const bool last, const bool with_hash) { break; case MAGIC_BYTE_UNSAFE_OP: // Parse the operation. It will be verified in `baking_sign_complete`. - TZ_CHECK(parse_operations(cdata, &G.maybe_ops.v, &global.path_with_curve)); + TZ_CHECK(parse_operations(cdata, + &G.maybe_ops.v, + (cx_ecfp_public_key_t *) &global.public_key)); break; default: TZ_FAIL(EXC_PARSE_ERROR); diff --git a/src/keys.c b/src/keys.c index 6c885569..d8c925dd 100644 --- a/src/keys.c +++ b/src/keys.c @@ -100,24 +100,10 @@ cx_err_t generate_public_key(cx_ecfp_public_key_t *public_key, return error; } -/** - * @brief Extract the public key hash from a public key and a curve - * - * Is non-reentrant - * - * @param hash_out: public key hash output - * @param hash_out_size: output size - * @param compressed_out: compressed public key output - * pass NULL if this value is not desired - * @param derivation_type: curve - * @param param public_key: public key - * @return cx_err_t: error, CX_OK if none - */ -static cx_err_t public_key_hash(uint8_t *const hash_out, - size_t const hash_out_size, - cx_ecfp_compressed_public_key_t *compressed_out, - derivation_type_t const derivation_type, - cx_ecfp_public_key_t const *const public_key) { +cx_err_t public_key_hash(uint8_t *const hash_out, + size_t const hash_out_size, + cx_ecfp_compressed_public_key_t *compressed_out, + cx_ecfp_public_key_t const *const public_key) { if ((hash_out == NULL) || (public_key == NULL)) { return CX_INVALID_PARAMETER; } @@ -129,16 +115,15 @@ static cx_err_t public_key_hash(uint8_t *const hash_out, cx_ecfp_compressed_public_key_t *compressed = (cx_ecfp_compressed_public_key_t *) &(tz_ecfp_compressed_public_key_t){0}; - switch (derivation_type) { - case DERIVATION_TYPE_ED25519: - case DERIVATION_TYPE_BIP32_ED25519: { + switch (public_key->curve) { + case CX_CURVE_Ed25519: { compressed->curve = public_key->curve; compressed->W_len = TZ_EDPK_LEN; memcpy(compressed->W, public_key->W + 1, compressed->W_len); break; } - case DERIVATION_TYPE_SECP256K1: - case DERIVATION_TYPE_SECP256R1: { + case CX_CURVE_SECP256K1: + case CX_CURVE_SECP256R1: { compressed->curve = public_key->curve; compressed->W_len = COMPRESSED_PK_LEN; memcpy(compressed->W, public_key->W, compressed->W_len); @@ -146,7 +131,7 @@ static cx_err_t public_key_hash(uint8_t *const hash_out, break; } #ifndef TARGET_NANOS - case DERIVATION_TYPE_BLS12_381: { + case CX_CURVE_BLS12_381_G1: { compressed->curve = public_key->curve; compressed->W_len = BLS_COMPRESSED_PK_LEN; memcpy(compressed->W, public_key->W + 1, compressed->W_len); @@ -177,29 +162,6 @@ static cx_err_t public_key_hash(uint8_t *const hash_out, return error; } -cx_err_t generate_public_key_hash(uint8_t *const hash_out, - size_t const hash_out_size, - cx_ecfp_compressed_public_key_t *compressed_out, - bip32_path_with_curve_t const *const path_with_curve) { - if ((hash_out == NULL) || (path_with_curve == NULL)) { - return CX_INVALID_PARAMETER; - } - - cx_ecfp_public_key_t *pubkey = (cx_ecfp_public_key_t *) &(tz_ecfp_public_key_t){0}; - cx_err_t error = CX_OK; - - CX_CHECK(generate_public_key(pubkey, path_with_curve)); - - CX_CHECK(public_key_hash(hash_out, - hash_out_size, - compressed_out, - path_with_curve->derivation_type, - pubkey)); - -end: - return error; -} - cx_err_t sign(uint8_t *const out, size_t *out_size, bip32_path_with_curve_t const *const path_with_curve, diff --git a/src/keys.h b/src/keys.h index 0b698547..7d5071fa 100644 --- a/src/keys.h +++ b/src/keys.h @@ -76,23 +76,22 @@ typedef enum { (((signature_type_t) 0 <= type) && (type < SIGNATURE_TYPE_UNSET)) /** - * @brief Converts `derivation_type` to `signature_type` + * @brief Gets the signature_type of a public_key * - * @param derivation_type: derivation_type + * @param public_key: public key * @return signature_type_t: signature_type result */ -static inline signature_type_t derivation_type_to_signature_type( - derivation_type_t const derivation_type) { - switch (derivation_type) { - case DERIVATION_TYPE_SECP256K1: +static inline signature_type_t signature_type_of_public_key( + cx_ecfp_public_key_t const *const public_key) { + switch (public_key->curve) { + case CX_CURVE_SECP256K1: return SIGNATURE_TYPE_SECP256K1; - case DERIVATION_TYPE_SECP256R1: + case CX_CURVE_SECP256R1: return SIGNATURE_TYPE_SECP256R1; - case DERIVATION_TYPE_ED25519: - case DERIVATION_TYPE_BIP32_ED25519: + case CX_CURVE_Ed25519: return SIGNATURE_TYPE_ED25519; #ifndef TARGET_NANOS - case DERIVATION_TYPE_BLS12_381: + case CX_CURVE_BLS12_381_G1: return SIGNATURE_TYPE_BLS12_381; #endif default: @@ -266,19 +265,21 @@ cx_err_t generate_public_key(cx_ecfp_public_key_t *public_key, bip32_path_with_curve_t const *const path_with_curve); /** - * @brief Generates a public key hash from a bip32 path and a curve + * @brief Extract the public key hash from a public key and a curve + * + * Is non-reentrant * * @param hash_out: public key hash output * @param hash_out_size: output size * @param compressed_out: compressed public key output * pass NULL if this value is not desired - * @param path_with_curve: bip32 path and curve + * @param public_key: public key * @return cx_err_t: error, CX_OK if none */ -cx_err_t generate_public_key_hash(uint8_t *const hash_out, - size_t const hash_out_size, - cx_ecfp_compressed_public_key_t *const compressed_out, - bip32_path_with_curve_t const *const path_with_curve); +cx_err_t public_key_hash(uint8_t *const hash_out, + size_t const hash_out_size, + cx_ecfp_compressed_public_key_t *compressed_out, + cx_ecfp_public_key_t const *const public_key); /** * @brief Signs a message with a key diff --git a/src/operations.c b/src/operations.c index 4fd137d8..9be9074b 100644 --- a/src/operations.c +++ b/src/operations.c @@ -93,26 +93,25 @@ static tz_parser_result parse_raw_tezos_header_signature_type( * * @param compressed_pubkey_out: compressed_pubkey output * @param contract_out: contract output - * @param path_with_curve: bip32 path and curve of the key + * @param public_key: public key * @return tz_exc: exception, SW_OK if none */ static inline tz_exc compute_pkh(cx_ecfp_compressed_public_key_t *const compressed_pubkey_out, parsed_contract_t *const contract_out, - bip32_path_with_curve_t const *const path_with_curve) { + cx_ecfp_public_key_t const *const public_key) { tz_exc exc = SW_OK; cx_err_t error = CX_OK; - TZ_ASSERT_NOT_NULL(path_with_curve); + TZ_ASSERT_NOT_NULL(public_key); TZ_ASSERT_NOT_NULL(compressed_pubkey_out); TZ_ASSERT_NOT_NULL(contract_out); - CX_CHECK(generate_public_key_hash(contract_out->hash, - sizeof(contract_out->hash), - compressed_pubkey_out, - path_with_curve)); + CX_CHECK(public_key_hash(contract_out->hash, + sizeof(contract_out->hash), + compressed_pubkey_out, + public_key)); - contract_out->signature_type = - derivation_type_to_signature_type(path_with_curve->derivation_type); + contract_out->signature_type = signature_type_of_public_key(public_key); TZ_ASSERT(contract_out->signature_type != SIGNATURE_TYPE_UNSET, EXC_MEMORY_ERROR); contract_out->originated = 0; @@ -251,17 +250,17 @@ static tz_parser_result parse_next_type(uint8_t current_byte, * @brief Initialize the operation parser * * @param out: parsing output - * @param path_with_curve: bip32 path and curve of the key + * @param public_key: public key * @param state: parsing state * @return tz_exc: exception, SW_OK if none */ static tz_exc parse_operations_init(struct parsed_operation_group *const out, - bip32_path_with_curve_t const *const path_with_curve, + cx_ecfp_public_key_t const *const public_key, struct parse_state *const state) { tz_exc exc = SW_OK; TZ_ASSERT_NOT_NULL(out); - TZ_ASSERT_NOT_NULL(path_with_curve); + TZ_ASSERT_NOT_NULL(public_key); memset(out, 0, sizeof(*out)); @@ -269,7 +268,7 @@ static tz_exc parse_operations_init(struct parsed_operation_group *const out, TZ_CHECK(compute_pkh((cx_ecfp_compressed_public_key_t *) &out->public_key, &out->signing, - path_with_curve)); + public_key)); // Start out with source = signing, for reveals memcpy(&out->operation.source, &out->signing, sizeof(out->signing)); @@ -490,11 +489,11 @@ static inline tz_parser_result parse_byte(uint8_t byte, tz_exc parse_operations(buffer_t *buf, struct parsed_operation_group *const out, - bip32_path_with_curve_t const *const path_with_curve) { + cx_ecfp_public_key_t const *const public_key) { tz_exc exc = SW_OK; uint8_t byte; - TZ_CHECK(parse_operations_init(out, path_with_curve, &G.parse_state)); + TZ_CHECK(parse_operations_init(out, public_key, &G.parse_state)); while (buffer_read_u8(buf, &byte) == true) { TZ_ASSERT(parse_byte(byte, &G.parse_state, out) != PARSER_ERROR, EXC_PARSE_ERROR); diff --git a/src/operations.h b/src/operations.h index ad00f0ef..b771ca7c 100644 --- a/src/operations.h +++ b/src/operations.h @@ -145,17 +145,16 @@ struct parse_state { * operation of any other type, which is the one it puts into * the group. * - * Some checks are carried out during the parsing using a key using a key + * Some checks are carried out during the parsing using a key * * @param buf: input operation * @param out: parsing output - * @param curve: curve of the key - * @param path_with_curve: bip32 path and curve of the key + * @param public_key: public key * @return tz_exc: exception, SW_OK if none */ tz_exc parse_operations(buffer_t *buf, struct parsed_operation_group *const out, - bip32_path_with_curve_t const *const path_with_curve); + cx_ecfp_public_key_t const *const public_key); /** * @brief Checks parsing has been completed successfully diff --git a/src/to_string.c b/src/to_string.c index d36f7b27..3444261c 100644 --- a/src/to_string.c +++ b/src/to_string.c @@ -36,22 +36,19 @@ static int pkh_to_string(char *const dest, signature_type_t const signature_type, uint8_t const hash[KEY_HASH_SIZE]); -tz_exc bip32_path_with_curve_to_pkh_string(char *const out, - size_t const out_size, - bip32_path_with_curve_t const *const key) { +tz_exc pk_to_pkh_string(char *const out, + size_t const out_size, + cx_ecfp_public_key_t const *const public_key) { tz_exc exc = SW_OK; cx_err_t error = CX_OK; uint8_t hash[KEY_HASH_SIZE]; TZ_ASSERT_NOT_NULL(out); - TZ_ASSERT_NOT_NULL(key); + TZ_ASSERT_NOT_NULL(public_key); - CX_CHECK(generate_public_key_hash(hash, sizeof(hash), NULL, key)); + CX_CHECK(public_key_hash(hash, sizeof(hash), NULL, public_key)); - TZ_ASSERT(pkh_to_string(out, - out_size, - derivation_type_to_signature_type(key->derivation_type), - hash) >= 0, + TZ_ASSERT(pkh_to_string(out, out_size, signature_type_of_public_key(public_key), hash) >= 0, EXC_WRONG_LENGTH); end: diff --git a/src/to_string.h b/src/to_string.h index fe2ab07d..92a98fd7 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -33,16 +33,16 @@ #define TICKER_WITH_SPACE " XTZ" /** - * @brief Converts a key to a public key hash string using its bip32 path and curve + * @brief Converts a key to a public key hash string using its public key * * @param out: result output * @param out_size: output size - * @param key: bip32 path and curve of the key + * @param public_key: public key * @return tz_exc: exception, SW_OK if none */ -tz_exc bip32_path_with_curve_to_pkh_string(char *const out, - size_t const out_size, - bip32_path_with_curve_t const *const key); +tz_exc pk_to_pkh_string(char *const out, + size_t const out_size, + cx_ecfp_public_key_t const *const public_key); /** * @brief Converts a chain id to string diff --git a/src/ui_bagl.c b/src/ui_bagl.c index e84f6ec5..cd0a1ee0 100644 --- a/src/ui_bagl.c +++ b/src/ui_bagl.c @@ -212,6 +212,9 @@ tz_exc calculate_idle_screen_chain_id(void) { tz_exc calculate_idle_screen_authorized_key(void) { tz_exc exc = SW_OK; + cx_err_t error = CX_OK; + + cx_ecfp_public_key_t *authorized_pk = (cx_ecfp_public_key_t *) &(tz_ecfp_public_key_t){0}; memset(&home_context.authorized_key, 0, sizeof(home_context.authorized_key)); @@ -221,12 +224,15 @@ tz_exc calculate_idle_screen_authorized_key(void) { "No Key Authorized"), EXC_WRONG_LENGTH); } else { - TZ_CHECK(bip32_path_with_curve_to_pkh_string(home_context.authorized_key, - sizeof(home_context.authorized_key), - &g_hwm.baking_key)); + CX_CHECK(generate_public_key(authorized_pk, &g_hwm.baking_key)); + + TZ_CHECK(pk_to_pkh_string(home_context.authorized_key, + sizeof(home_context.authorized_key), + authorized_pk)); } end: + TZ_CONVERT_CX(); return exc; } diff --git a/src/ui_delegation_bagl.c b/src/ui_delegation_bagl.c index b0536d7d..2f2eca1b 100644 --- a/src/ui_delegation_bagl.c +++ b/src/ui_delegation_bagl.c @@ -61,9 +61,9 @@ int prompt_delegation(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { memset(&delegation_context, 0, sizeof(delegation_context)); - TZ_CHECK(bip32_path_with_curve_to_pkh_string(delegation_context.address, - sizeof(delegation_context.address), - &global.path_with_curve)); + TZ_CHECK(pk_to_pkh_string(delegation_context.address, + sizeof(delegation_context.address), + (cx_ecfp_public_key_t *) &global.public_key)); TZ_ASSERT(microtez_to_string(delegation_context.fee, sizeof(delegation_context.fee), diff --git a/src/ui_delegation_nbgl.c b/src/ui_delegation_nbgl.c index f66d9539..2e2e9366 100644 --- a/src/ui_delegation_nbgl.c +++ b/src/ui_delegation_nbgl.c @@ -85,9 +85,9 @@ int prompt_delegation(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { delegation_context.ok_cb = ok_cb; delegation_context.cxl_cb = cxl_cb; - TZ_CHECK(bip32_path_with_curve_to_pkh_string(delegation_context.tagValueRef[ADDRESS_IDX], - MAX_LENGTH, - &global.path_with_curve)); + TZ_CHECK(pk_to_pkh_string(delegation_context.tagValueRef[ADDRESS_IDX], + MAX_LENGTH, + (cx_ecfp_public_key_t *) &global.public_key)); TZ_ASSERT(microtez_to_string(delegation_context.tagValueRef[FEE_IDX], MAX_LENGTH, diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index d1ebe52a..3614418b 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -68,6 +68,9 @@ static const nbgl_contentInfoList_t infoList = {.nbInfos = INFO_NB, */ static void initInfo(void) { tz_exc exc = SW_OK; + cx_err_t error = CX_OK; + + cx_ecfp_public_key_t* authorized_pk = (cx_ecfp_public_key_t*) &(tz_ecfp_public_key_t){0}; for (tz_infoIndex_t idx = 0; idx < INFO_NB; idx++) { infoContents[idx] = infoContentsBridge[idx]; @@ -82,9 +85,9 @@ static void initInfo(void) { TZ_ASSERT(copy_string(infoContentsBridge[PKH_IDX], MAX_LENGTH, "No Key Authorized"), EXC_WRONG_LENGTH); } else { - TZ_CHECK(bip32_path_with_curve_to_pkh_string(infoContentsBridge[PKH_IDX], - MAX_LENGTH, - &g_hwm.baking_key)); + CX_CHECK(generate_public_key(authorized_pk, &g_hwm.baking_key)); + + TZ_CHECK(pk_to_pkh_string(infoContentsBridge[PKH_IDX], MAX_LENGTH, authorized_pk)); } TZ_ASSERT(hwm_to_string(infoContentsBridge[HWM_IDX], MAX_LENGTH, &g_hwm.hwm.main) >= 0, @@ -105,6 +108,7 @@ static void initInfo(void) { EXC_WRONG_LENGTH); end: + TZ_CONVERT_CX(); TZ_EXC_PRINT(exc); } diff --git a/src/ui_pubkey_bagl.c b/src/ui_pubkey_bagl.c index f974bcf1..9effa976 100644 --- a/src/ui_pubkey_bagl.c +++ b/src/ui_pubkey_bagl.c @@ -58,9 +58,9 @@ int prompt_pubkey(bool authorize, ui_callback_t ok_cb, ui_callback_t cxl_cb) { memset(&address_context, 0, sizeof(address_context)); - TZ_CHECK(bip32_path_with_curve_to_pkh_string(address_context.public_key_hash, - sizeof(address_context.public_key_hash), - &global.path_with_curve)); + TZ_CHECK(pk_to_pkh_string(address_context.public_key_hash, + sizeof(address_context.public_key_hash), + (cx_ecfp_public_key_t *) &global.public_key)); ux_prepare_confirm_callbacks(ok_cb, cxl_cb); if (authorize) { diff --git a/src/ui_pubkey_nbgl.c b/src/ui_pubkey_nbgl.c index 796eacd0..4f6d997c 100644 --- a/src/ui_pubkey_nbgl.c +++ b/src/ui_pubkey_nbgl.c @@ -69,9 +69,9 @@ int prompt_pubkey(bool authorize, ui_callback_t ok_cb, ui_callback_t cxl_cb) { address_context.ok_cb = ok_cb; address_context.cxl_cb = cxl_cb; - TZ_CHECK(bip32_path_with_curve_to_pkh_string(address_context.buffer, - sizeof(address_context.buffer), - &global.path_with_curve)); + TZ_CHECK(pk_to_pkh_string(address_context.buffer, + sizeof(address_context.buffer), + (cx_ecfp_public_key_t*) &global.public_key)); const char* text; if (authorize) { diff --git a/src/ui_setup_bagl.c b/src/ui_setup_bagl.c index 9f6fe513..bbfa01f6 100644 --- a/src/ui_setup_bagl.c +++ b/src/ui_setup_bagl.c @@ -67,9 +67,9 @@ int prompt_setup(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { memset(&setup_context, 0, sizeof(setup_context)); - TZ_CHECK(bip32_path_with_curve_to_pkh_string(setup_context.address, - sizeof(setup_context.address), - &global.path_with_curve)); + TZ_CHECK(pk_to_pkh_string(setup_context.address, + sizeof(setup_context.address), + (cx_ecfp_public_key_t *) &global.public_key)); TZ_ASSERT(chain_id_to_string_with_aliases(setup_context.chain, sizeof(setup_context.chain), diff --git a/src/ui_setup_nbgl.c b/src/ui_setup_nbgl.c index 25812182..2ce1be7b 100644 --- a/src/ui_setup_nbgl.c +++ b/src/ui_setup_nbgl.c @@ -146,9 +146,9 @@ int prompt_setup(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { setup_context.ok_cb = ok_cb; setup_context.cxl_cb = cxl_cb; - TZ_CHECK(bip32_path_with_curve_to_pkh_string(setup_context.tagValueRef[ADDRESS_IDX], - MAX_LENGTH, - &global.path_with_curve)); + TZ_CHECK(pk_to_pkh_string(setup_context.tagValueRef[ADDRESS_IDX], + MAX_LENGTH, + (cx_ecfp_public_key_t *) &global.public_key)); TZ_ASSERT(chain_id_to_string_with_aliases(setup_context.tagValueRef[CHAIN_IDX], MAX_LENGTH, From 9146ccfb690457df878b10e91d3ff50ee07d4d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Fri, 25 Oct 2024 17:56:37 +0200 Subject: [PATCH 5/6] [bls-signing] sign using the stored pk instead of derive it again --- src/apdu_hmac.c | 1 + src/apdu_sign.c | 7 ++++++- src/crypto.c | 27 +++++++++++++++++++-------- src/crypto.h | 17 +++++++++++------ src/keys.c | 5 +++++ src/keys.h | 4 ++++ 6 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/apdu_hmac.c b/src/apdu_hmac.c index ec0558ee..b6e5e02e 100644 --- a/src/apdu_hmac.c +++ b/src/apdu_hmac.c @@ -66,6 +66,7 @@ static inline tz_exc hmac(uint8_t *const out, CX_CHECK(sign(state->signed_hmac_key, &signed_hmac_key_size, path_with_curve, + NULL, key_sha256, sizeof(key_sha256))); diff --git a/src/apdu_sign.c b/src/apdu_sign.c index 709c5742..3826f03f 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -311,7 +311,12 @@ static int perform_signature(bool const send_hash) { size_t signature_size = MAX_SIGNATURE_SIZE; - CX_CHECK(sign(resp + offset, &signature_size, &global.path_with_curve, message, message_len)); + CX_CHECK(sign(resp + offset, + &signature_size, + &global.path_with_curve, + (cx_ecfp_public_key_t *) &global.public_key, + message, + message_len)); offset += signature_size; diff --git a/src/crypto.c b/src/crypto.c index f60eb31d..42df1861 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -131,12 +131,14 @@ WARN_UNUSED_RESULT cx_err_t bip32_derive_get_pubkey_bls(const uint32_t *path, // https://gitlab.com/tezos/tezos/-/blob/master/src/lib_bls12_381_signature/bls12_381_signature.ml?ref_type=heads#L351 static const uint8_t CIPHERSUITE[] = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_AUG_"; -WARN_UNUSED_RESULT cx_err_t bip32_derive_with_seed_bls_sign_hash(const uint32_t *path, - size_t path_len, - uint8_t const *msg, - size_t msg_len, - uint8_t *sig, - size_t *sig_len) { +WARN_UNUSED_RESULT cx_err_t +bip32_derive_with_seed_bls_sign_hash(const uint32_t *path, + size_t path_len, + cx_ecfp_384_public_key_t *public_key, + uint8_t const *msg, + size_t msg_len, + uint8_t *sig, + size_t *sig_len) { cx_err_t error = CX_OK; cx_ecfp_384_private_key_t privkey = {0}; uint8_t hash[CX_BLS_BLS12381_PARAM_LEN * 4] = {0}; @@ -156,8 +158,17 @@ WARN_UNUSED_RESULT cx_err_t bip32_derive_with_seed_bls_sign_hash(const uint32_t // Derive private key according to BIP32 path CX_CHECK(bip32_derive_init_privkey_bls(path, path_len, &privkey)); - CX_CHECK(bip32_derive_get_pubkey_bls(path, path_len, raw_pubkey)); - memmove(tmp, raw_pubkey + 1, BLS_COMPRESSED_PK_LEN); + if (public_key == NULL) { + CX_CHECK(bip32_derive_get_pubkey_bls(path, path_len, raw_pubkey)); + memmove(tmp, raw_pubkey + 1, BLS_COMPRESSED_PK_LEN); + } else { + if ((public_key->curve != CX_CURVE_BLS12_381_G1) || + (public_key->W_len < (BLS_COMPRESSED_PK_LEN + 1u))) { + error = CX_INVALID_PARAMETER_VALUE; + goto end; + } + memmove(tmp, public_key->W + 1, BLS_COMPRESSED_PK_LEN); + } memmove(tmp + BLS_COMPRESSED_PK_LEN, msg, msg_len); CX_CHECK(cx_hash_to_field(tmp, diff --git a/src/crypto.h b/src/crypto.h index ba51738b..6b849015 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -58,6 +58,9 @@ WARN_UNUSED_RESULT cx_err_t bip32_derive_get_pubkey_bls(const uint32_t *path, * * @param[in] path_len Bip32 path length. * + * @param[in] public_key Must be the BLS key associated with the path and the inner seed. + * If NULL, it will be computed using the path and the inner seed. + * * @param[in] msg Digest of the message to be signed. * The length of *message* must be shorter than the group order size. * Otherwise it is truncated. @@ -73,10 +76,12 @@ WARN_UNUSED_RESULT cx_err_t bip32_derive_get_pubkey_bls(const uint32_t *path, * - CX_EC_INVALID_CURVE * - CX_INTERNAL_ERROR */ -WARN_UNUSED_RESULT cx_err_t bip32_derive_with_seed_bls_sign_hash(const uint32_t *path, - size_t path_len, - uint8_t const *msg, - size_t msg_len, - uint8_t *sig, - size_t *sig_len); +WARN_UNUSED_RESULT cx_err_t +bip32_derive_with_seed_bls_sign_hash(const uint32_t *path, + size_t path_len, + cx_ecfp_384_public_key_t *public_key, + uint8_t const *msg, + size_t msg_len, + uint8_t *sig, + size_t *sig_len); #endif diff --git a/src/keys.c b/src/keys.c index d8c925dd..faa5f7c7 100644 --- a/src/keys.c +++ b/src/keys.c @@ -165,8 +165,12 @@ cx_err_t public_key_hash(uint8_t *const hash_out, cx_err_t sign(uint8_t *const out, size_t *out_size, bip32_path_with_curve_t const *const path_with_curve, + cx_ecfp_public_key_t *public_key, uint8_t const *const in, size_t const in_size) { +#ifdef TARGET_NANOS + UNUSED(public_key); +#endif if ((out == NULL) || (out_size == NULL) || (path_with_curve == NULL) || (in == NULL)) { return CX_INVALID_PARAMETER; } @@ -219,6 +223,7 @@ cx_err_t sign(uint8_t *const out, case DERIVATION_TYPE_BLS12_381: { CX_CHECK(bip32_derive_with_seed_bls_sign_hash(bip32_path->components, bip32_path->length, + (cx_ecfp_384_public_key_t *) public_key, (uint8_t const *) PIC(in), in_size, out, diff --git a/src/keys.h b/src/keys.h index 7d5071fa..66863ea9 100644 --- a/src/keys.h +++ b/src/keys.h @@ -289,6 +289,9 @@ cx_err_t public_key_hash(uint8_t *const hash_out, * @param out: signature output * @param out_size: output size * @param path_with_curve: bip32 path and curve of the key + * @param public_key: BLS public key associated with the path and the inner seed. + * Will be used only for BLS signature. + * If NULL, it will be computed using the path and the inner seed. * @param in: message input * @param in_size: input size * @return cx_err_t: error, CX_OK if none @@ -296,5 +299,6 @@ cx_err_t public_key_hash(uint8_t *const hash_out, cx_err_t sign(uint8_t *const out, size_t *out_size, bip32_path_with_curve_t const *const path_with_curve, + cx_ecfp_public_key_t *public_key, uint8_t const *const in, size_t const in_size); From 1c55f5a30156ac67b55e6ae030f9c2306a20a144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Wed, 6 Nov 2024 09:28:39 +0100 Subject: [PATCH 6/6] [pk-derivation] do not derive pk if it has already been derived Since `global.public_key` is the key associated to `global.path_with_curve`, if the `path_with_curve` to derive is equal to `global.path_with_curve`, then the key associated to the `path_with_curve` is `global.public_key`. There is no need to re-derive it again. --- src/apdu.c | 15 +++++++++++---- src/apdu.h | 11 +++++++---- src/apdu_pubkey.c | 11 +++++++---- src/ui_bagl.c | 8 +++++++- src/ui_nbgl.c | 8 +++++++- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/apdu.c b/src/apdu.c index d99a6e82..eee51a32 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -39,14 +39,21 @@ tz_exc read_path_with_curve(derivation_type_t derivation_type, cx_ecfp_public_key_t* pubkey) { tz_exc exc = SW_OK; cx_err_t error = CX_OK; + bip32_path_with_curve_t tmp_path_with_curve = {0}; TZ_ASSERT_NOT_NULL(buf); TZ_ASSERT_NOT_NULL(path_with_curve); - TZ_ASSERT_NOT_NULL(pubkey); - path_with_curve->derivation_type = derivation_type; - TZ_ASSERT(read_bip32_path(buf, &path_with_curve->bip32_path), EXC_WRONG_VALUES); - CX_CHECK(generate_public_key(pubkey, path_with_curve)); + tmp_path_with_curve.derivation_type = derivation_type; + TZ_ASSERT(read_bip32_path(buf, &tmp_path_with_curve.bip32_path), EXC_WRONG_VALUES); + + // Do not derive the public key if the two path_with_curve are equal + if (!bip32_path_with_curve_eq(path_with_curve, &tmp_path_with_curve)) { + memmove(path_with_curve, &tmp_path_with_curve, sizeof(bip32_path_with_curve_t)); + if (pubkey != NULL) { + CX_CHECK(generate_public_key(pubkey, path_with_curve)); + } + } end: TZ_CONVERT_CX(); diff --git a/src/apdu.h b/src/apdu.h index a06ec76c..871ffdf9 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -89,11 +89,14 @@ static inline int io_send_apdu_err(uint16_t sw) { /** * @brief Reads a path with curve and derive the public key. + * Set [pubkey] to NULL to not deriving the public key. + * Will not derive the public key if the path with curve read + * is the same as the one provided. * - * @param[in] derivation_type: Derivation type of the key. - * @param[in] buf: Buffer that should contains a bip32 path. - * @param[out] path_with_curve: Buffer to store the path with curve. - * @param[out] pubkey: Buffer to store the pubkey. + * @param[in] derivation_type: Derivation type of the key. + * @param[in] buf: Buffer that should contains a bip32 path. + * @param[in/out] path_with_curve: Buffer to store the path with curve. + * @param[out] pubkey: Buffer to store the pubkey. Can be NULL * @return tz_exc: exception, SW_OK if none */ tz_exc read_path_with_curve(derivation_type_t derivation_type, diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index 06f68bc7..c650c9b9 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -74,10 +74,13 @@ int handle_get_public_key(buffer_t *cdata, TZ_ASSERT_NOT_NULL(cdata); if ((cdata->size == 0u) && authorize) { - TZ_ASSERT(copy_bip32_path_with_curve(&global.path_with_curve, &(g_hwm.baking_key)), - EXC_MEMORY_ERROR); - CX_CHECK(generate_public_key((cx_ecfp_public_key_t *) &global.public_key, - &global.path_with_curve)); + // Do not derive the public key if the two path_with_curve are equal + if (!bip32_path_with_curve_eq(&global.path_with_curve, &g_hwm.baking_key)) { + TZ_ASSERT(copy_bip32_path_with_curve(&global.path_with_curve, &g_hwm.baking_key), + EXC_MEMORY_ERROR); + CX_CHECK(generate_public_key((cx_ecfp_public_key_t *) &global.public_key, + &global.path_with_curve)); + } } else { TZ_CHECK(read_path_with_curve(derivation_type, cdata, diff --git a/src/ui_bagl.c b/src/ui_bagl.c index cd0a1ee0..0620f1ac 100644 --- a/src/ui_bagl.c +++ b/src/ui_bagl.c @@ -224,7 +224,13 @@ tz_exc calculate_idle_screen_authorized_key(void) { "No Key Authorized"), EXC_WRONG_LENGTH); } else { - CX_CHECK(generate_public_key(authorized_pk, &g_hwm.baking_key)); + // Do not derive the public key if the two path_with_curve are equal + if (!bip32_path_with_curve_eq(&global.path_with_curve, &g_hwm.baking_key)) { + CX_CHECK(generate_public_key((cx_ecfp_public_key_t *) authorized_pk, + &global.path_with_curve)); + } else { + memmove(authorized_pk, &global.public_key, sizeof(tz_ecfp_public_key_t)); + } TZ_CHECK(pk_to_pkh_string(home_context.authorized_key, sizeof(home_context.authorized_key), diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 3614418b..9b0bf781 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -85,7 +85,13 @@ static void initInfo(void) { TZ_ASSERT(copy_string(infoContentsBridge[PKH_IDX], MAX_LENGTH, "No Key Authorized"), EXC_WRONG_LENGTH); } else { - CX_CHECK(generate_public_key(authorized_pk, &g_hwm.baking_key)); + // Do not derive the public key if the two path_with_curve are equal + if (!bip32_path_with_curve_eq(&global.path_with_curve, &g_hwm.baking_key)) { + CX_CHECK(generate_public_key((cx_ecfp_public_key_t*) authorized_pk, + &global.path_with_curve)); + } else { + memmove(authorized_pk, &global.public_key, sizeof(tz_ecfp_public_key_t)); + } TZ_CHECK(pk_to_pkh_string(infoContentsBridge[PKH_IDX], MAX_LENGTH, authorized_pk)); }