Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows to sign using the BLS curve #121

Merged
merged 13 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ ENABLE_NBGL_QRCODE = 1

HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1

CURVE_APP_LOAD_PARAMS = ed25519 secp256k1 secp256r1
# No BLS for NANOS
CURVE_APP_LOAD_PARAMS = ed25519 secp256k1 secp256r1 bls12381g1
PATH_APP_LOAD_PARAMS = "44'/1729'"

# VERSION
Expand All @@ -35,7 +36,8 @@ GIT_DESCRIBE ?= $(shell git describe --tags --abbrev=8 --always --long --dirty 2
VERSION_TAG ?= $(shell echo "$(GIT_DESCRIBE)" | cut -f1 -d-)
COMMIT ?= $(shell echo "$(GIT_DESCRIBE)" | awk -F'-g' '{print $2}' | sed 's/-dirty/*/')

DEFINES += COMMIT=\"$(COMMIT)\"
DEFINES += COMMIT=\"$(COMMIT)\"
DEFINES += HAVE_BLS

# Only warn about version tags if specified/inferred
ifeq ($(VERSION_TAG),)
Expand Down
2 changes: 1 addition & 1 deletion misra.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"script": "misra.py",
"args": [
"--rule-texts=misra.md",
"--suppress-rules 2.7,3.1,8.2,8.9,11.3,15.1,15.2,15.5,16.3,17.7,18.4,18.8,19.2,20.7"
"--suppress-rules 2.7,3.1,8.2,8.9,11.3,15.1,15.2,15.5,16.3,17.6,17.7,18.4,18.8,19.2,20.7"
]
}
18 changes: 9 additions & 9 deletions src/apdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ int provide_pubkey(bip32_path_with_curve_t const* const path_with_curve) {
// 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 = {0};
CX_CHECK(generate_public_key(&pubkey, path_with_curve));
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;
resp[offset] = pubkey->W_len;
offset++;
memmove(resp + offset, pubkey.W, pubkey.W_len);
offset += pubkey.W_len;
memmove(resp + offset, pubkey->W, pubkey->W_len);
offset += pubkey->W_len;

return io_send_response_pointer(resp, offset, SW_OK);

Expand Down Expand Up @@ -107,10 +107,10 @@ int apdu_dispatcher(const command_t* cmd) {

#define ASSERT_NO_P2 TZ_ASSERT(cmd->p2 == 0u, EXC_WRONG_PARAM)

#define READ_P2_DERIVATION_TYPE \
do { \
derivation_type = parse_derivation_type(cmd->p2); \
TZ_ASSERT(derivation_type != DERIVATION_TYPE_UNSET, EXC_WRONG_PARAM); \
#define READ_P2_DERIVATION_TYPE \
do { \
derivation_type = (derivation_type_t) cmd->p2; \
TZ_ASSERT(DERIVATION_TYPE_IS_SET(derivation_type), EXC_WRONG_PARAM); \
} while (0)

#define ASSERT_NO_DATA TZ_ASSERT(cmd->data == NULL, EXC_WRONG_VALUES)
Expand Down
7 changes: 4 additions & 3 deletions src/apdu_query.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "baking_auth.h"
#include "bip32.h"
#include "globals.h"
#include "memory.h"
#include "os_cx.h"
#include "to_string.h"
#include "ui.h"
Expand Down Expand Up @@ -97,10 +98,10 @@ int handle_query_auth_key_with_curve(void) {
uint8_t const length = g_hwm.baking_key.bip32_path.length;
TZ_ASSERT(length <= NUM_ELEMENTS(g_hwm.baking_key.bip32_path.components), EXC_WRONG_LENGTH);

int derivation_type = unparse_derivation_type(g_hwm.baking_key.derivation_type);
TZ_ASSERT(derivation_type >= 0, EXC_REFERENCED_DATA_NOT_FOUND);
TZ_ASSERT(DERIVATION_TYPE_IS_SET(g_hwm.baking_key.derivation_type),
EXC_REFERENCED_DATA_NOT_FOUND);

resp[offset] = derivation_type;
resp[offset] = (uint8_t) g_hwm.baking_key.derivation_type;
offset++;

resp[offset] = length;
Expand Down
162 changes: 30 additions & 132 deletions src/apdu_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,110 +40,6 @@

static int perform_signature(bool const send_hash);

/**
* @brief Initializes the blake2b state if it is not
*
* @param state: blake2b state
* @return tz_exc: exception, SW_OK if none
*/
static inline tz_exc conditional_init_hash_state(blake2b_hash_state_t *const state) {
tz_exc exc = SW_OK;
cx_err_t error = CX_OK;

TZ_ASSERT_NOT_NULL(state);

if (!state->initialized) {
// cx_blake2b_init takes size in bits.
CX_CHECK(cx_blake2b_init_no_throw(&state->state, SIGN_HASH_SIZE * 8u));
state->initialized = true;
}

end:
TZ_CONVERT_CX();
return exc;
}

/**
* @brief Hashes incrementally a buffer using a blake2b state
*
* The hash remains in the buffer, the buffer content length is
* updated and the blake2b state is also updated
*
* @param buff: buffer
* @param buff_size: buffer size
* @param buff_length: buffer content length
* @param state: blake2b state
* @return tz_exc: exception, SW_OK if none
*/
static tz_exc blake2b_incremental_hash(uint8_t *const buff,
size_t const buff_size,
size_t *const buff_length,
blake2b_hash_state_t *const state) {
tz_exc exc = SW_OK;
cx_err_t error = CX_OK;

TZ_ASSERT_NOT_NULL(buff);
TZ_ASSERT_NOT_NULL(buff_length);
TZ_ASSERT_NOT_NULL(state);

TZ_CHECK(conditional_init_hash_state(state));

uint8_t *current = buff;
while (*buff_length > B2B_BLOCKBYTES) {
TZ_ASSERT((current - buff) <= (int) buff_size, EXC_MEMORY_ERROR);

CX_CHECK(
cx_hash_no_throw((cx_hash_t *) &state->state, 0, current, B2B_BLOCKBYTES, NULL, 0));
*buff_length -= B2B_BLOCKBYTES;
current += B2B_BLOCKBYTES;
}
memmove(buff, current, *buff_length);

end:
TZ_CONVERT_CX();
return exc;
}

/**
* @brief Finalizes the hashes of a buffer using a blake2b state
*
* The buffer is modified and the buffer content length is
* updated
*
* The final hash is stored in the ouput, its size is also
* stored and the blake2b state is updated
*
* @param out: output buffer
* @param out_size: output size
* @param buff: buffer
* @param buff_size: buffer size
* @param buff_length: buffer content length
* @param state: blake2b state
* @return tz_exc: exception, SW_OK if none
*/
static tz_exc blake2b_finish_hash(uint8_t *const out,
size_t const out_size,
uint8_t *const buff,
size_t const buff_size,
size_t *const buff_length,
blake2b_hash_state_t *const state) {
tz_exc exc = SW_OK;
cx_err_t error = CX_OK;

TZ_ASSERT_NOT_NULL(out);
TZ_ASSERT_NOT_NULL(buff);
TZ_ASSERT_NOT_NULL(buff_length);
TZ_ASSERT_NOT_NULL(state);

TZ_CHECK(conditional_init_hash_state(state));
TZ_CHECK(blake2b_incremental_hash(buff, buff_size, buff_length, state));
CX_CHECK(
cx_hash_no_throw((cx_hash_t *) &state->state, CX_LAST, buff, *buff_length, out, out_size));
end:
TZ_CONVERT_CX();
return exc;
}

/**
* @brief Allows to clear all data related to signature
*
Expand Down Expand Up @@ -283,6 +179,7 @@ int select_signing_key(buffer_t *cdata, derivation_type_t derivation_type) {
*/
int handle_sign(buffer_t *cdata, const bool last, const bool with_hash) {
tz_exc exc = SW_OK;
cx_err_t error = CX_OK;

TZ_ASSERT_NOT_NULL(cdata);

Expand All @@ -294,6 +191,9 @@ int handle_sign(buffer_t *cdata, const bool last, const bool with_hash) {

// Only parse a single packet when baking
TZ_ASSERT(G.packet_index == 1u, EXC_PARSE_ERROR);
if (G.packet_index == 1u) {
CX_CHECK(cx_hash_init_ex((cx_hash_t *) &G.hash_state.state, CX_BLAKE2B, SIGN_HASH_SIZE));
}

TZ_ASSERT(buffer_read_u8(cdata, &G.magic_byte), EXC_PARSE_ERROR);
bool is_attestation = false;
Expand All @@ -320,32 +220,21 @@ int handle_sign(buffer_t *cdata, const bool last, const bool with_hash) {
TZ_FAIL(EXC_PARSE_ERROR);
}

// Hash contents of *previous* message (which may be empty).
TZ_CHECK(blake2b_incremental_hash(G.message_data,
sizeof(G.message_data),
&G.message_data_length,
&G.hash_state));

TZ_ASSERT(
buffer_seek_set(cdata, 0) && buffer_move(cdata,
G.message_data + G.message_data_length,
sizeof(G.message_data) - G.message_data_length),
EXC_PARSE_ERROR);
CX_CHECK(
cx_hash_no_throw((cx_hash_t *) &G.hash_state.state, 0, cdata->ptr, cdata->size, NULL, 0));

G.message_data_length += cdata->size;
#ifndef TARGET_NANOS
memmove(G.message, cdata->ptr, cdata->size);
G.message_len = cdata->size;
#endif

if (last) {
// Hash contents of *this* message and then get the final hash value.
TZ_CHECK(blake2b_incremental_hash(G.message_data,
sizeof(G.message_data),
&G.message_data_length,
&G.hash_state));
TZ_CHECK(blake2b_finish_hash(G.final_hash,
sizeof(G.final_hash),
G.message_data,
sizeof(G.message_data),
&G.message_data_length,
&G.hash_state));
CX_CHECK(cx_hash_no_throw((cx_hash_t *) &G.hash_state.state,
CX_LAST,
NULL,
0,
G.final_hash,
sizeof(G.final_hash)));

G.maybe_ops.is_valid = parse_operations_final(&G.parse_state, &G.maybe_ops.v);

Expand All @@ -355,6 +244,7 @@ int handle_sign(buffer_t *cdata, const bool last, const bool with_hash) {
}

end:
TZ_CONVERT_CX();
return io_send_apdu_err(exc);
}

Expand All @@ -379,18 +269,26 @@ static int perform_signature(bool const send_hash) {
uint8_t resp[SIGN_HASH_SIZE + MAX_SIGNATURE_SIZE] = {0};
size_t offset = 0;

uint8_t *message = G.final_hash;
size_t message_len = sizeof(G.final_hash);

#ifndef TARGET_NANOS
// The BLS signature uses its own hash function.
// The entire message must be stored in `G.message`.
if (global.path_with_curve.derivation_type == DERIVATION_TYPE_BLS12_381) {
spalmer25 marked this conversation as resolved.
Show resolved Hide resolved
message = G.message;
message_len = G.message_len;
}
#endif

if (send_hash) {
memcpy(resp + offset, G.final_hash, sizeof(G.final_hash));
offset += sizeof(G.final_hash);
}

size_t signature_size = MAX_SIGNATURE_SIZE;

CX_CHECK(sign(resp + offset,
&signature_size,
&global.path_with_curve,
G.final_hash,
sizeof(G.final_hash)));
CX_CHECK(sign(resp + offset, &signature_size, &global.path_with_curve, message, message_len));

offset += signature_size;

Expand Down
Loading
Loading