diff --git a/Makefile b/Makefile index 8197c4db..b01a1eaa 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -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),) diff --git a/misra.json b/misra.json index cc8da8b5..b8042ded 100644 --- a/misra.json +++ b/misra.json @@ -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" ] } diff --git a/src/apdu.c b/src/apdu.c index c4a2aaa1..14848700 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -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); @@ -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) diff --git a/src/apdu_query.c b/src/apdu_query.c index e1518cec..6fc7548a 100644 --- a/src/apdu_query.c +++ b/src/apdu_query.c @@ -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" @@ -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; diff --git a/src/apdu_sign.c b/src/apdu_sign.c index 956c0355..07af8f49 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -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 * @@ -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); @@ -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; @@ -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); @@ -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); } @@ -379,6 +269,18 @@ 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) { + 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); @@ -386,11 +288,7 @@ 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, - G.final_hash, - sizeof(G.final_hash))); + CX_CHECK(sign(resp + offset, &signature_size, &global.path_with_curve, message, message_len)); offset += signature_size; diff --git a/src/crypto.c b/src/crypto.c new file mode 100644 index 00000000..f60eb31d --- /dev/null +++ b/src/crypto.c @@ -0,0 +1,186 @@ +/* Tezos Ledger application - Cryptography operations + + Copyright 2024 Functori + Copyright 2023 Ledger SAS + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#include // uint*_t +#include // memset, explicit_bzero +#include // bool + +#include "crypto.h" + +#include "cx.h" +#include "os.h" +#include "os_io_seproxyhal.h" + +#ifndef TARGET_NANOS + +/** + * @brief Gets the bls private key from the device seed using the specified bip32 path + * key. + * + * @param[in] path Bip32 path to use for derivation. + * + * @param[in] path_len Bip32 path length. + * + * @param[out] privkey Generated private key. + * + * @return Error code: + * - CX_OK on success + * - CX_EC_INVALID_CURVE + * - CX_INTERNAL_ERROR + */ +static WARN_UNUSED_RESULT cx_err_t +bip32_derive_init_privkey_bls(const uint32_t *path, + size_t path_len, + cx_ecfp_384_private_key_t *privkey) { + cx_err_t error = CX_OK; + // Allocate 64 bytes to respect Syscall API but only 48 will be used + uint8_t raw_privkey[64] = {0}; + cx_curve_t curve = CX_CURVE_BLS12_381_G1; + size_t length = BLS_SK_LEN; + + // Derive private key according to the path + io_seproxyhal_io_heartbeat(); + CX_CHECK(os_derive_eip2333_no_throw(curve, path, path_len, raw_privkey + (64u - BLS_SK_LEN))); + io_seproxyhal_io_heartbeat(); + + // Init privkey from raw + CX_CHECK(cx_ecfp_init_private_key_no_throw(curve, + raw_privkey, + length, + (cx_ecfp_private_key_t *) privkey)); + +end: + explicit_bzero(raw_privkey, sizeof(raw_privkey)); + + if (error != CX_OK) { + // Make sure the caller doesn't use uninitialized data in case + // the return code is not checked. + explicit_bzero(privkey, sizeof(cx_ecfp_384_private_key_t)); + } + return error; +} + +WARN_UNUSED_RESULT cx_err_t bip32_derive_get_pubkey_bls(const uint32_t *path, + size_t path_len, + uint8_t raw_pubkey[static BLS_PK_LEN]) { + cx_err_t error = CX_OK; + cx_curve_t curve = CX_CURVE_BLS12_381_G1; + + uint8_t tmp[BLS_SK_LEN * 2u] = {0}; + uint8_t bls_field[BLS_SK_LEN] = {0}; + int diff = 0; + + cx_ecfp_384_private_key_t privkey = {0}; + cx_ecfp_384_public_key_t pubkey = {0}; + + // Derive private key according to BIP32 path + CX_CHECK(bip32_derive_init_privkey_bls(path, path_len, &privkey)); + + // Generate associated pubkey + CX_CHECK(cx_ecfp_generate_pair_no_throw(curve, + (cx_ecfp_public_key_t *) &pubkey, + (cx_ecfp_private_key_t *) &privkey, + true)); + + tmp[BLS_SK_LEN - 1u] = 2; + CX_CHECK(cx_math_mult_no_throw(tmp, pubkey.W + 1u + BLS_SK_LEN, tmp, BLS_SK_LEN)); + CX_CHECK(cx_ecdomain_parameter(curve, CX_CURVE_PARAM_Field, bls_field, sizeof(bls_field))); + CX_CHECK(cx_math_cmp_no_throw(tmp + BLS_SK_LEN, bls_field, BLS_SK_LEN, &diff)); + pubkey.W[1] &= 0x1fu; + if (diff > 0) { + pubkey.W[1] |= 0xa0u; + } else { + pubkey.W[1] |= 0x80u; + } + + // Check pubkey length then copy it to raw_pubkey + if (pubkey.W_len != BLS_PK_LEN) { + error = CX_EC_INVALID_CURVE; + goto end; + } + memmove(raw_pubkey, pubkey.W, pubkey.W_len); + +end: + explicit_bzero(&privkey, sizeof(privkey)); + + if (error != CX_OK) { + // Make sure the caller doesn't use uninitialized data in case + // the return code is not checked. + explicit_bzero(raw_pubkey, BLS_PK_LEN); + } + return error; +} + +// Cipher suite used in tezos: +// 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) { + cx_err_t error = CX_OK; + cx_ecfp_384_private_key_t privkey = {0}; + uint8_t hash[CX_BLS_BLS12381_PARAM_LEN * 4] = {0}; + uint8_t tmp[BLS_COMPRESSED_PK_LEN + BLS_MAX_MESSAGE_LEN] = {0}; + uint8_t raw_pubkey[BLS_PK_LEN] = {0}; + + if ((sig_len == NULL) || (*sig_len < BLS_SIG_LEN)) { + error = CX_INVALID_PARAMETER_VALUE; + goto end; + } + + if (BLS_MAX_MESSAGE_LEN < msg_len) { + error = CX_INVALID_PARAMETER_VALUE; + goto end; + } + + // 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); + memmove(tmp + BLS_COMPRESSED_PK_LEN, msg, msg_len); + + CX_CHECK(cx_hash_to_field(tmp, + BLS_COMPRESSED_PK_LEN + msg_len, + CIPHERSUITE, + sizeof(CIPHERSUITE) - 1u, + hash, + sizeof(hash))); + + CX_CHECK(ox_bls12381_sign(&privkey, hash, sizeof(hash), sig, BLS_SIG_LEN)); + *sig_len = BLS_SIG_LEN; + +end: + explicit_bzero(&privkey, sizeof(privkey)); + explicit_bzero(hash, sizeof(hash)); + explicit_bzero(tmp, sizeof(tmp)); + explicit_bzero(raw_pubkey, sizeof(raw_pubkey)); + + if (error != CX_OK) { + // Make sure the caller doesn't use uninitialized data in case + // the return code is not checked. + explicit_bzero(sig, BLS_SIG_LEN); + } + return error; +} +#endif diff --git a/src/crypto.h b/src/crypto.h new file mode 100644 index 00000000..ba51738b --- /dev/null +++ b/src/crypto.h @@ -0,0 +1,82 @@ +/* Tezos Ledger application - Cryptography operations + + Copyright 2024 Functori + Copyright 2023 Ledger SAS + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#pragma once +#ifndef TARGET_NANOS + +#include // uint*_t + +#include "cx.h" + +#define BLS_SK_LEN 48u +#define BLS_PK_LEN (1u + (BLS_SK_LEN * 2u)) +#define BLS_COMPRESSED_PK_LEN 48u +#define BLS_SIG_LEN 96u + +// `BLS_MAX_MESSAGE_LEN` can be as large as needed +#define BLS_MAX_MESSAGE_LEN 235u + +/** + * @brief Gets the bls public key from the device seed using the specified bip32 path + * key. + * + * @param[in] path Bip32 path to use for derivation. + * + * @param[in] path_len Bip32 path length. + * + * @param[out] raw_pubkey Buffer where to store the public key. + * + * @return Error code: + * - CX_OK on success + * - CX_EC_INVALID_CURVE + * - CX_INTERNAL_ERROR + */ +WARN_UNUSED_RESULT cx_err_t bip32_derive_get_pubkey_bls(const uint32_t *path, + size_t path_len, + uint8_t raw_pubkey[static 97]); + +/** + * @brief Sign a hash with bls using the device seed derived from the specified bip32 path. + * + * @param[in] path Bip32 path to use for derivation. + * + * @param[in] path_len Bip32 path length. + * + * @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. + * + * @param[in] msg_len Length of the digest in octets. + * + * @param[out] sig Buffer where to store the signature. + * + * @param[in] sig_len Length of the signature buffer, updated with signature length. + * + * @return Error code: + * - CX_OK on success + * - 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); +#endif diff --git a/src/globals.h b/src/globals.h index b4bd4ee3..dabc4fc5 100644 --- a/src/globals.h +++ b/src/globals.h @@ -55,13 +55,7 @@ void toggle_hwm(void); /// Maximum number of bytes in a single APDU #define MAX_APDU_SIZE 235u -/// Our buffer must accommodate any remainder from hashing and the next message at once. -#define TEZOS_BUFSIZE (BLAKE2B_BLOCKBYTES + MAX_APDU_SIZE) - -#define PRIVATE_KEY_DATA_SIZE 64u -#define MAX_SIGNATURE_SIZE 100u -#define ELLIPTIC_CURVE_PUB_KEY_LENGTH 65u -#define PUB_KEY_COMPPRESSED_LENGTH 33u +#define MAX_SIGNATURE_SIZE 100u /** * @brief This structure represents the state needed to handle HMAC @@ -79,7 +73,6 @@ typedef struct { */ typedef struct { cx_blake2b_t state; ///< blake2b state - bool initialized; ///< if the state has already been initialized } blake2b_hash_state_t; /** @@ -99,12 +92,12 @@ typedef struct { struct parsed_operation_group v; ///< current parsed operation group } maybe_ops; - /// buffer to hold the current message part and the previous message hash - uint8_t message_data[TEZOS_BUFSIZE]; - size_t message_data_length; ///< length of message data - blake2b_hash_state_t hash_state; ///< current blake2b hash state uint8_t final_hash[SIGN_HASH_SIZE]; ///< buffer to hold hash of all the message +#ifndef TARGET_NANOS + uint8_t message[MAX_APDU_SIZE]; ///< buffer to hold last packet message + size_t message_len; ///< size of the message last packet +#endif magic_byte_t magic_byte; ///< current magic byte read struct parse_state parse_state; ///< current parser state diff --git a/src/keys.c b/src/keys.c index ffbfee04..6c885569 100644 --- a/src/keys.c +++ b/src/keys.c @@ -19,59 +19,21 @@ */ -#include "keys.h" - -#include "apdu.h" #include "crypto_helpers.h" -#include "globals.h" -#include "memory.h" -#include "types.h" -#include -#include +#ifndef TARGET_NANOS +#include "crypto.h" +#endif +#include "keys.h" + +/***** Bip32 path *****/ bool read_bip32_path(buffer_t *buf, bip32_path_t *const out) { return (buffer_read_u8(buf, &out->length) && buffer_read_bip32_path(buf, out->components, (size_t) out->length)); } -/** - * @brief Converts `derivation_type` to `derivation_mode` - * - * @param derivation_type: derivation_type - * @return unsigned int: derivation mode - */ -static inline unsigned int derivation_type_to_derivation_mode( - derivation_type_t const derivation_type) { - switch (derivation_type) { - case DERIVATION_TYPE_ED25519: - return HDW_ED25519_SLIP10; - case DERIVATION_TYPE_SECP256K1: - case DERIVATION_TYPE_SECP256R1: - case DERIVATION_TYPE_BIP32_ED25519: - default: - return HDW_NORMAL; - } -} - -/** - * @brief Converts `signature_type` to `cx_curve` - * - * @param signature_type: signature_type - * @return cx_curve_t: curve result - */ -static inline cx_curve_t signature_type_to_cx_curve(signature_type_t const signature_type) { - switch (signature_type) { - case SIGNATURE_TYPE_SECP256K1: - return CX_CURVE_SECP256K1; - case SIGNATURE_TYPE_SECP256R1: - return CX_CURVE_SECP256R1; - case SIGNATURE_TYPE_ED25519: - return CX_CURVE_Ed25519; - default: - return CX_CURVE_NONE; - } -} +/***** Key *****/ cx_err_t generate_public_key(cx_ecfp_public_key_t *public_key, bip32_path_with_curve_t const *const path_with_curve) { @@ -83,29 +45,55 @@ cx_err_t generate_public_key(cx_ecfp_public_key_t *public_key, bip32_path_t const *const bip32_path = &path_with_curve->bip32_path; derivation_type_t derivation_type = path_with_curve->derivation_type; - unsigned int derivation_mode = derivation_type_to_derivation_mode(derivation_type); - signature_type_t signature_type = derivation_type_to_signature_type(derivation_type); - cx_curve_t cx_curve = signature_type_to_cx_curve(signature_type); - - public_key->W_len = ELLIPTIC_CURVE_PUB_KEY_LENGTH; - public_key->curve = cx_curve; - - // generate corresponding public key - CX_CHECK(bip32_derive_with_seed_get_pubkey_256(derivation_mode, - public_key->curve, - bip32_path->components, - bip32_path->length, - public_key->W, - NULL, - CX_SHA512, - NULL, - 0)); - - // If we're using the old curve, make sure to adjust accordingly. - if (cx_curve == CX_CURVE_Ed25519) { - CX_CHECK( - cx_edwards_compress_point_no_throw(CX_CURVE_Ed25519, public_key->W, public_key->W_len)); - public_key->W_len = PUB_KEY_COMPPRESSED_LENGTH; + unsigned int derivation_mode; + + switch (derivation_type) { + case DERIVATION_TYPE_ED25519: + case DERIVATION_TYPE_BIP32_ED25519: { + derivation_mode = + (derivation_type == DERIVATION_TYPE_ED25519) ? HDW_ED25519_SLIP10 : HDW_NORMAL; + public_key->curve = CX_CURVE_Ed25519; + public_key->W_len = COMPRESSED_PK_LEN; + CX_CHECK( + bip32_derive_with_seed_get_pubkey_256(derivation_mode, + public_key->curve, + bip32_path->components, + bip32_path->length, + ((cx_ecfp_256_public_key_t *) public_key)->W, + NULL, + CX_SHA512, + NULL, + 0)); + CX_CHECK(cx_edwards_compress_point_no_throw(CX_CURVE_Ed25519, + public_key->W, + public_key->W_len)); + break; + } + case DERIVATION_TYPE_SECP256K1: + case DERIVATION_TYPE_SECP256R1: { + public_key->curve = (derivation_type == DERIVATION_TYPE_SECP256K1) ? CX_CURVE_SECP256K1 + : CX_CURVE_SECP256R1; + public_key->W_len = PK_LEN; + CX_CHECK(bip32_derive_get_pubkey_256(public_key->curve, + bip32_path->components, + bip32_path->length, + ((cx_ecfp_256_public_key_t *) public_key)->W, + NULL, + CX_SHA512)); + break; + } +#ifndef TARGET_NANOS + case DERIVATION_TYPE_BLS12_381: { + public_key->curve = CX_CURVE_BLS12_381_G1; + public_key->W_len = BLS_PK_LEN; + CX_CHECK(bip32_derive_get_pubkey_bls(bip32_path->components, + bip32_path->length, + ((cx_ecfp_384_public_key_t *) public_key)->W)); + break; + } +#endif + default: + return CX_INVALID_PARAMETER; } end: @@ -127,7 +115,7 @@ cx_err_t generate_public_key(cx_ecfp_public_key_t *public_key, */ static cx_err_t public_key_hash(uint8_t *const hash_out, size_t const hash_out_size, - cx_ecfp_public_key_t *compressed_out, + cx_ecfp_compressed_public_key_t *compressed_out, derivation_type_t const derivation_type, cx_ecfp_public_key_t const *const public_key) { if ((hash_out == NULL) || (public_key == NULL)) { @@ -138,22 +126,33 @@ static cx_err_t public_key_hash(uint8_t *const hash_out, return CX_INVALID_PARAMETER_SIZE; } - signature_type_t signature_type = derivation_type_to_signature_type(derivation_type); - cx_ecfp_public_key_t compressed = {0}; + cx_ecfp_compressed_public_key_t *compressed = + (cx_ecfp_compressed_public_key_t *) &(tz_ecfp_compressed_public_key_t){0}; - switch (signature_type) { - case SIGNATURE_TYPE_ED25519: { - compressed.W_len = public_key->W_len - 1; - memcpy(compressed.W, public_key->W + 1, compressed.W_len); + switch (derivation_type) { + case DERIVATION_TYPE_ED25519: + case DERIVATION_TYPE_BIP32_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: { + compressed->curve = public_key->curve; + compressed->W_len = COMPRESSED_PK_LEN; + memcpy(compressed->W, public_key->W, compressed->W_len); + compressed->W[0] = 0x02 + (public_key->W[64] & 0x01); break; } - case SIGNATURE_TYPE_SECP256K1: - case SIGNATURE_TYPE_SECP256R1: { - memcpy(compressed.W, public_key->W, public_key->W_len); - compressed.W[0] = 0x02 + (public_key->W[64] & 0x01); - compressed.W_len = PUB_KEY_COMPPRESSED_LENGTH; +#ifndef TARGET_NANOS + case DERIVATION_TYPE_BLS12_381: { + compressed->curve = public_key->curve; + compressed->W_len = BLS_COMPRESSED_PK_LEN; + memcpy(compressed->W, public_key->W + 1, compressed->W_len); break; } +#endif default: return CX_INVALID_PARAMETER; } @@ -165,13 +164,13 @@ static cx_err_t public_key_hash(uint8_t *const hash_out, CX_CHECK(cx_hash_no_throw((cx_hash_t *) &hash_state, CX_LAST, - compressed.W, - compressed.W_len, + compressed->W, + compressed->W_len, hash_out, KEY_HASH_SIZE)); if (compressed_out != NULL) { - memmove(compressed_out, &compressed, sizeof(*compressed_out)); + memmove(compressed_out, compressed, sizeof(tz_ecfp_compressed_public_key_t)); } end: @@ -180,22 +179,22 @@ static cx_err_t public_key_hash(uint8_t *const hash_out, cx_err_t generate_public_key_hash(uint8_t *const hash_out, size_t const hash_out_size, - cx_ecfp_public_key_t *compressed_out, + 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 = {0}; + 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(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)); + pubkey)); end: return error; @@ -214,13 +213,16 @@ cx_err_t sign(uint8_t *const out, bip32_path_t const *const bip32_path = &path_with_curve->bip32_path; derivation_type_t derivation_type = path_with_curve->derivation_type; - unsigned int derivation_mode = derivation_type_to_derivation_mode(derivation_type); - signature_type_t signature_type = derivation_type_to_signature_type(derivation_type); - cx_curve_t cx_curve = signature_type_to_cx_curve(signature_type); + unsigned int derivation_mode; + cx_curve_t cx_curve; uint32_t info; - switch (signature_type) { - case SIGNATURE_TYPE_ED25519: { + switch (derivation_type) { + case DERIVATION_TYPE_ED25519: + case DERIVATION_TYPE_BIP32_ED25519: { + derivation_mode = + (derivation_type == DERIVATION_TYPE_ED25519) ? HDW_ED25519_SLIP10 : HDW_NORMAL; + cx_curve = CX_CURVE_Ed25519; CX_CHECK(bip32_derive_with_seed_eddsa_sign_hash_256(derivation_mode, cx_curve, bip32_path->components, @@ -233,8 +235,10 @@ cx_err_t sign(uint8_t *const out, NULL, 0)); } break; - case SIGNATURE_TYPE_SECP256K1: - case SIGNATURE_TYPE_SECP256R1: { + case DERIVATION_TYPE_SECP256K1: + case DERIVATION_TYPE_SECP256R1: { + cx_curve = (derivation_type == DERIVATION_TYPE_SECP256K1) ? CX_CURVE_SECP256K1 + : CX_CURVE_SECP256R1; CX_CHECK(bip32_derive_ecdsa_sign_hash_256(cx_curve, bip32_path->components, bip32_path->length, @@ -249,6 +253,16 @@ cx_err_t sign(uint8_t *const out, out[0] |= 0x01; } } break; +#ifndef TARGET_NANOS + case DERIVATION_TYPE_BLS12_381: { + CX_CHECK(bip32_derive_with_seed_bls_sign_hash(bip32_path->components, + bip32_path->length, + (uint8_t const *) PIC(in), + in_size, + out, + out_size)); + } break; +#endif default: error = CX_INVALID_PARAMETER; } diff --git a/src/keys.h b/src/keys.h index 616dac31..0b698547 100644 --- a/src/keys.h +++ b/src/keys.h @@ -21,15 +21,106 @@ #pragma once -#include -#include -#include - +#include "bip32.h" #include "buffer.h" -#include "exception.h" -#include "memory.h" #include "os_cx.h" -#include "types.h" + +#ifndef TARGET_NANOS +#include "crypto.h" +#endif + +/***** Key Type *****/ + +/** + * NOTE: There are *two* ways that "key type" or "curve code" are represented in + * this code base: + * 1. `derivation_type` represents how a key will be derived from the seed. It + * is almost the same as `signature_type` but allows for multiple derivation + * strategies for ed25519. This type is often parsed from the APDU + * instruction. See `parse_derivation_type` for the mapping. + * 2. `signature_type` represents how a key will be used for signing. + * The mapping from `derivation_type` to `signature_type` is injective. + * See `derivation_type_to_signature_type`. + * This type is parsed from Tezos data headers. See the relevant parsing + * code for the mapping. + */ +typedef enum { + DERIVATION_TYPE_ED25519 = 0x00, + DERIVATION_TYPE_SECP256K1 = 0x01, + DERIVATION_TYPE_SECP256R1 = 0x02, + DERIVATION_TYPE_BIP32_ED25519 = 0x03, +#ifdef TARGET_NANOS + DERIVATION_TYPE_UNSET = 0x04 +#else + DERIVATION_TYPE_BLS12_381 = 0x04, + DERIVATION_TYPE_UNSET = 0x05 +#endif +} derivation_type_t; + +typedef enum { + SIGNATURE_TYPE_ED25519 = 0, + SIGNATURE_TYPE_SECP256K1 = 1, + SIGNATURE_TYPE_SECP256R1 = 2, +#ifdef TARGET_NANOS + SIGNATURE_TYPE_UNSET = 3 +#else + SIGNATURE_TYPE_BLS12_381 = 3, + SIGNATURE_TYPE_UNSET = 4 +#endif +} signature_type_t; + +#define DERIVATION_TYPE_IS_SET(type) \ + (((derivation_type_t) 0 <= type) && (type < DERIVATION_TYPE_UNSET)) + +#define SIGNATURE_TYPE_IS_SET(type) \ + (((signature_type_t) 0 <= type) && (type < SIGNATURE_TYPE_UNSET)) + +/** + * @brief Converts `derivation_type` to `signature_type` + * + * @param derivation_type: derivation_type + * @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: + return SIGNATURE_TYPE_SECP256K1; + case DERIVATION_TYPE_SECP256R1: + return SIGNATURE_TYPE_SECP256R1; + case DERIVATION_TYPE_ED25519: + case DERIVATION_TYPE_BIP32_ED25519: + return SIGNATURE_TYPE_ED25519; +#ifndef TARGET_NANOS + case DERIVATION_TYPE_BLS12_381: + return SIGNATURE_TYPE_BLS12_381; +#endif + default: + return SIGNATURE_TYPE_UNSET; + } +} + +/***** Bip32 path *****/ + +/** + * @brief This structure represents a bip32 path + * + */ +typedef struct { + uint8_t length; ///< length of the path + uint32_t components[MAX_BIP32_PATH]; ///< array of components +} bip32_path_t; + +/** + * @brief This structure represents a bip32 path and its curve + * + * Defines the key when associated with a mnemonic seed. + * + */ +typedef struct { + bip32_path_t bip32_path; ///< bip32 path of the key + derivation_type_t derivation_type; ///< curve of the key +} bip32_path_with_curve_t; /** * @brief Reads a bip32_path @@ -44,6 +135,126 @@ */ bool read_bip32_path(buffer_t *buf, bip32_path_t *const out); +/** + * @brief Copies a bip32 path + * + * @param out: bip32 path output + * @param in: bip32 path copied + * @return bool: whether the copy was successful or not + */ +static inline bool copy_bip32_path(bip32_path_t *const out, bip32_path_t const *const in) { + if ((out == NULL) || (in == NULL)) { + return false; + } + memcpy(out->components, in->components, in->length * sizeof(*in->components)); + out->length = in->length; + return true; +} + +/** + * @brief Checks that two bip32 paths are equals + * + * @param p1: first bip32 path + * @param p2: second bip32 path + * @return bool: result + */ +static inline bool bip32_paths_eq(bip32_path_t volatile const *const p1, + bip32_path_t volatile const *const p2) { + return (p1 == p2) || ((p1 != NULL) && (p2 != NULL) && (p1->length == p2->length) && + (memcmp((const uint8_t *) p1->components, + (const uint8_t *) p2->components, + p1->length * sizeof(*p1->components)) == 0)); +} + +/** + * @brief Copies a bip32 path and its curve + * + * @param out: output + * @param in: bip32 path and curve copied + * @return bool: whether the copy was successful or not + */ +static inline bool copy_bip32_path_with_curve(bip32_path_with_curve_t *const out, + bip32_path_with_curve_t const *const in) { + if ((out == NULL) || (in == NULL) || !copy_bip32_path(&out->bip32_path, &in->bip32_path)) { + return false; + } + out->derivation_type = in->derivation_type; + return true; +} + +/** + * @brief Checks that two bip32 paths with their paths are equals + * + * @param p1: first bip32 path and curve + * @param p2: first bip32 path and curve + * @return bool: result + */ +static inline bool bip32_path_with_curve_eq(bip32_path_with_curve_t volatile const *const p1, + bip32_path_with_curve_t volatile const *const p2) { + return (p1 == p2) || + ((p1 != NULL) && (p2 != NULL) && bip32_paths_eq(&p1->bip32_path, &p2->bip32_path) && + (p1->derivation_type == p2->derivation_type)); +} + +/***** Key *****/ + +#define KEY_HASH_SIZE 20u +#define PK_LEN 65u +#define COMPRESSED_PK_LEN 33u +#define TZ_EDPK_LEN (COMPRESSED_PK_LEN - 1u) + +/** + * @brief This structure represents elliptic curve public key handled + * Can be explicitly cast into `cx_ecfp_public_key_t` + */ +typedef union { + cx_ecfp_256_public_key_t pk_256; ///< edpk, sppk and p2pk keys +#ifndef TARGET_NANOS + cx_ecfp_384_public_key_t pk_384; ///< BLpk keys +#endif +} tz_ecfp_public_key_t; + +/** + * @brief Alias to represent abstract compressed public key + */ +typedef cx_ecfp_public_key_t cx_ecfp_compressed_public_key_t; + +/** + * @brief These structures are based on `cx_ecfp_public_key_t` and represents compressed elliptic + * curve public key handled + * Can be explicitly cast into `cx_ecfp_compressed_public_key_t` + */ +/** Ed25519 compressed public key */ +typedef struct { + cx_curve_t curve; ///< Curve identifier + size_t W_len; ///< Compressed public key length in bytes + uint8_t W[TZ_EDPK_LEN]; ///< Compressed public key value +} tz_ecfp_ed25519_compressed_public_key_t; +/** Secp256 compressed public key */ +typedef struct { + cx_curve_t curve; ///< Curve identifier + size_t W_len; ///< Compressed public key length in bytes + uint8_t W[COMPRESSED_PK_LEN]; ///< Compressed public key value +} tz_ecfp_secp256_compressed_public_key_t; +#ifndef TARGET_NANOS +/** BLS compressed public key */ +typedef struct { + cx_curve_t curve; ///< Curve identifier + size_t W_len; ///< Compressed public key length in bytes + uint8_t W[BLS_COMPRESSED_PK_LEN]; ///< Compressed public key value +} tz_ecfp_bls_compressed_public_key_t; +#endif +/** + * @brief This structure represents elliptic curve compressed public key handled + */ +typedef union { + tz_ecfp_ed25519_compressed_public_key_t pk_ed25519; ///< edpk keys + tz_ecfp_secp256_compressed_public_key_t pk_secp256; ///< sppk and p2pk keys +#ifndef TARGET_NANOS + tz_ecfp_bls_compressed_public_key_t pk_bls; ///< BLpk keys +#endif +} tz_ecfp_compressed_public_key_t; + /** * @brief Generates a public key from a bip32 path and a curve * @@ -66,7 +277,7 @@ cx_err_t generate_public_key(cx_ecfp_public_key_t *public_key, */ cx_err_t generate_public_key_hash(uint8_t *const hash_out, size_t const hash_out_size, - cx_ecfp_public_key_t *const compressed_out, + cx_ecfp_compressed_public_key_t *const compressed_out, bip32_path_with_curve_t const *const path_with_curve); /** @@ -86,66 +297,3 @@ cx_err_t sign(uint8_t *const out, bip32_path_with_curve_t const *const path_with_curve, uint8_t const *const in, size_t const in_size); - -/** - * @brief Reads a curve code from wire-format and parse into `deviration_type` - * - * @param curve_code: curve code - * @return derivation_type_t: derivation_type result - */ -static inline derivation_type_t parse_derivation_type(uint8_t const curve_code) { - switch (curve_code) { - case 0: - return DERIVATION_TYPE_ED25519; - case 1: - return DERIVATION_TYPE_SECP256K1; - case 2: - return DERIVATION_TYPE_SECP256R1; - case 3: - return DERIVATION_TYPE_BIP32_ED25519; - default: - return DERIVATION_TYPE_UNSET; - } -} - -/** - * @brief Converts `derivation_type` to wire-format. - * - * @param derivation_type: curve - * @return uint8_t: curve code result - */ -static inline int unparse_derivation_type(derivation_type_t const derivation_type) { - switch (derivation_type) { - case DERIVATION_TYPE_ED25519: - return 0; - case DERIVATION_TYPE_SECP256K1: - return 1; - case DERIVATION_TYPE_SECP256R1: - return 2; - case DERIVATION_TYPE_BIP32_ED25519: - return 3; - default: - return -1; - } -} - -/** - * @brief Converts `derivation_type` to `signature_type` - * - * @param derivation_type: derivation_type - * @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: - return SIGNATURE_TYPE_SECP256K1; - case DERIVATION_TYPE_SECP256R1: - return SIGNATURE_TYPE_SECP256R1; - case DERIVATION_TYPE_ED25519: - case DERIVATION_TYPE_BIP32_ED25519: - return SIGNATURE_TYPE_ED25519; - default: - return SIGNATURE_TYPE_UNSET; - } -} diff --git a/src/operations.c b/src/operations.c index 0b371552..4fd137d8 100644 --- a/src/operations.c +++ b/src/operations.c @@ -77,25 +77,11 @@ static tz_parser_result parse_raw_tezos_header_signature_type( raw_tezos_header_signature_type_t const *const raw_signature_type, signature_type_t *signature_type) { tz_parser_result res = PARSER_CONTINUE; - signature_type_t signature_type_result; PARSER_ASSERT(raw_signature_type != NULL); + PARSER_ASSERT(SIGNATURE_TYPE_IS_SET((signature_type_t) raw_signature_type->v)); - switch (raw_signature_type->v) { - case 0: - signature_type_result = SIGNATURE_TYPE_ED25519; - break; - case 1: - signature_type_result = SIGNATURE_TYPE_SECP256K1; - break; - case 2: - signature_type_result = SIGNATURE_TYPE_SECP256R1; - break; - default: - PARSER_FAIL(); - } - - *signature_type = signature_type_result; + *signature_type = (signature_type_t) raw_signature_type->v; res = PARSER_DONE; end: @@ -110,7 +96,7 @@ static tz_parser_result parse_raw_tezos_header_signature_type( * @param path_with_curve: bip32 path and curve of the key * @return tz_exc: exception, SW_OK if none */ -static inline tz_exc compute_pkh(cx_ecfp_public_key_t *const compressed_pubkey_out, +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) { tz_exc exc = SW_OK; @@ -281,7 +267,9 @@ static tz_exc parse_operations_init(struct parsed_operation_group *const out, out->operation.tag = OPERATION_TAG_NONE; - TZ_CHECK(compute_pkh(&out->public_key, &out->signing, path_with_curve)); + TZ_CHECK(compute_pkh((cx_ecfp_compressed_public_key_t *) &out->public_key, + &out->signing, + path_with_curve)); // Start out with source = signing, for reveals memcpy(&out->operation.source, &out->signing, sizeof(out->signing)); @@ -435,13 +423,13 @@ static inline tz_parser_result parse_byte(uint8_t byte, OP_STEP { - size_t klen = out->public_key.W_len; + size_t klen = ((cx_ecfp_compressed_public_key_t *) &out->public_key)->W_len; // klen must match one of the field sizes in the public_key union CALL_SUBPARSER(parse_next_type, byte, &(state->subparser_state.nexttype), klen); - PARSER_ASSERT(memcmp(out->public_key.W, + PARSER_ASSERT(memcmp(((cx_ecfp_compressed_public_key_t *) &out->public_key)->W, &(state->subparser_state.nexttype.body.raw), klen) == 0); diff --git a/src/operations.h b/src/operations.h index a13bf888..ad00f0ef 100644 --- a/src/operations.h +++ b/src/operations.h @@ -61,9 +61,12 @@ struct implicit_contract { * */ union public_key { - uint8_t edpk[32]; ///< raw public key for a edpk key - uint8_t sppk[33]; ///< raw public key for a sppk key - uint8_t p2pk[33]; ///< raw public key for a p2pk key + uint8_t edpk[TZ_EDPK_LEN]; ///< raw public key for a edpk key + uint8_t sppk[COMPRESSED_PK_LEN]; ///< raw public key for a sppk key + uint8_t p2pk[COMPRESSED_PK_LEN]; ///< raw public key for a p2pk key +#ifndef TARGET_NANOS + uint8_t blpk[BLS_COMPRESSED_PK_LEN]; ///< raw public key for a BLpk key +#endif } __attribute__((packed)); /** diff --git a/src/to_string.c b/src/to_string.c index c636a727..d36f7b27 100644 --- a/src/to_string.c +++ b/src/to_string.c @@ -121,6 +121,13 @@ static int pkh_to_string(char *const dest, data.prefix[1] = 161u; data.prefix[2] = 164u; break; +#ifndef TARGET_NANOS + case SIGNATURE_TYPE_BLS12_381: + data.prefix[0] = 6u; + data.prefix[1] = 161u; + data.prefix[2] = 166u; + break; +#endif default: return -1; } diff --git a/src/types.h b/src/types.h index f0ea63eb..cf49ab76 100644 --- a/src/types.h +++ b/src/types.h @@ -23,40 +23,13 @@ #pragma once #include "exception.h" -#include "bip32.h" #include "os.h" #include "os_io_seproxyhal.h" #include #include -/** - * NOTE: There are *two* ways that "key type" or "curve code" are represented in - * this code base: - * 1. `derivation_type` represents how a key will be derived from the seed. It - * is almost the same as `signature_type` but allows for multiple derivation - * strategies for ed25519. This type is often parsed from the APDU - * instruction. See `parse_derivation_type` for the mapping. - * 2. `signature_type` represents how a key will be used for signing. - * The mapping from `derivation_type` to `signature_type` is injective. - * See `derivation_type_to_signature_type`. - * This type is parsed from Tezos data headers. See the relevant parsing - * code for the mapping. - */ -typedef enum { - DERIVATION_TYPE_UNSET = 0, - DERIVATION_TYPE_SECP256K1 = 1, - DERIVATION_TYPE_SECP256R1 = 2, - DERIVATION_TYPE_ED25519 = 3, - DERIVATION_TYPE_BIP32_ED25519 = 4 -} derivation_type_t; - -typedef enum { - SIGNATURE_TYPE_UNSET = 0, - SIGNATURE_TYPE_SECP256K1 = 1, - SIGNATURE_TYPE_SECP256R1 = 2, - SIGNATURE_TYPE_ED25519 = 3 -} signature_type_t; +#include "keys.h" /** * @brief Type of baking message @@ -104,87 +77,6 @@ static chain_id_t const mainnet_chain_id = {.v = 0x7A06A770}; */ typedef bool (*ui_callback_t)(void); -/** - * @brief This structure represents a bip32 path - * - */ -typedef struct { - uint8_t length; ///< length of the path - uint32_t components[MAX_BIP32_PATH]; ///< array of components -} bip32_path_t; - -/** - * @brief Copies a bip32 path - * - * @param out: bip32 path output - * @param in: bip32 path copied - * @return bool: whether the copy was successful or not - */ -static inline bool copy_bip32_path(bip32_path_t *const out, bip32_path_t const *const in) { - if ((out == NULL) || (in == NULL)) { - return false; - } - memcpy(out->components, in->components, in->length * sizeof(*in->components)); - out->length = in->length; - return true; -} - -/** - * @brief Checks that two bip32 paths are equals - * - * @param a: first bip32 path - * @param b: second bip32 path - * @return bool: result - */ -static inline bool bip32_paths_eq(bip32_path_t volatile const *const a, - bip32_path_t volatile const *const b) { - return (a == b) || ((a != NULL) && (b != NULL) && (a->length == b->length) && - (memcmp((const uint8_t *) a->components, - (const uint8_t *) b->components, - a->length * sizeof(*a->components)) == 0)); -} - -/** - * @brief This structure represents a bip32 path and its curve - * - * Defines a key when associates with a mnemonic seed - * - */ -typedef struct { - bip32_path_t bip32_path; ///< bip32 path of the key - derivation_type_t derivation_type; ///< curve of the key -} bip32_path_with_curve_t; - -/** - * @brief Copies a bip32 path and its curve - * - * @param out: output - * @param in: bip32 path and curve copied - * @return bool: whether the copy was successful or not - */ -static inline bool copy_bip32_path_with_curve(bip32_path_with_curve_t *const out, - bip32_path_with_curve_t const *const in) { - if ((out == NULL) || (in == NULL) || !copy_bip32_path(&out->bip32_path, &in->bip32_path)) { - return false; - } - out->derivation_type = in->derivation_type; - return true; -} - -/** - * @brief Checks that two bip32 paths with their paths are equals - * - * @param a: first bip32 path and curve - * @param b: first bip32 path and curve - * @return bool: result - */ -static inline bool bip32_path_with_curve_eq(bip32_path_with_curve_t volatile const *const a, - bip32_path_with_curve_t volatile const *const b) { - return (a == b) || - ((a != NULL) && (b != NULL) && bip32_paths_eq(&a->bip32_path, &b->bip32_path) && - (a->derivation_type == b->derivation_type)); -} - /** * @brief This structure represents a High Watermark (HWM) * @@ -222,8 +114,6 @@ typedef struct { #define PROTOCOL_HASH_BASE58_STRING_SIZE \ sizeof("ProtoBetaBetaBetaBetaBetaBetaBetaBetaBet11111a5ug96") -#define KEY_HASH_SIZE 20u - /** * @brief This structure represents the content of a parsed baking data * @@ -275,12 +165,12 @@ struct parsed_operation { * */ struct parsed_operation_group { - cx_ecfp_public_key_t public_key; ///< signer public key - uint64_t total_fee; ///< sum of all fees - uint64_t total_storage_limit; ///< sum of all storage limits - bool has_reveal; ///< if the bundle contains at least a reveal - struct parsed_contract signing; ///< contract form of signer - struct parsed_operation operation; ///< operation parsed + tz_ecfp_compressed_public_key_t public_key; ///< compressed signer public key + uint64_t total_fee; ///< sum of all fees + uint64_t total_storage_limit; ///< sum of all storage limits + bool has_reveal; ///< if the bundle contains at least a reveal + struct parsed_contract signing; ///< contract form of signer + struct parsed_operation operation; ///< operation parsed }; #define CUSTOM_MAX(a, b) \ diff --git a/src/ui_pubkey_nbgl.c b/src/ui_pubkey_nbgl.c index adba6e87..796eacd0 100644 --- a/src/ui_pubkey_nbgl.c +++ b/src/ui_pubkey_nbgl.c @@ -40,9 +40,9 @@ * */ typedef struct { - char buffer[sizeof(cx_ecfp_public_key_t)]; /// value buffer - ui_callback_t ok_cb; /// accept callback - ui_callback_t cxl_cb; /// cancel callback + char buffer[PKH_STRING_SIZE]; /// value buffer + ui_callback_t ok_cb; /// accept callback + ui_callback_t cxl_cb; /// cancel callback } AddressContext_t; /// Current address context diff --git a/test/common.py b/test/common.py index 4fa707d0..957b6cc8 100644 --- a/test/common.py +++ b/test/common.py @@ -50,6 +50,13 @@ 2 ) +TZ4_ACCOUNT = Account( + "m/44'/1729'/0'/0'", + SigScheme.BLS, + "BLsk2Q1AdMSKNJbM1fLqHEWgaEDUz2odGrgPuCV1bxtzAedVEC2RSz", + 3 +) + LONG_TZ1_ACCOUNT = Account( "m/9'/12'/13'/8'/78'", SigScheme.ED25519, @@ -75,13 +82,18 @@ TZ3_ACCOUNT, ] -ACCOUNTS = TZ1_ACCOUNTS + TZ2_ACCOUNTS + TZ3_ACCOUNTS +TZ4_ACCOUNTS = [ + TZ4_ACCOUNT, +] + +ACCOUNTS = TZ1_ACCOUNTS + TZ2_ACCOUNTS + TZ3_ACCOUNTS + TZ4_ACCOUNTS ZEBRA_ACCOUNTS = [ TZ1_ACCOUNT, TZ2_ACCOUNT, TZ3_ACCOUNT, BIP32_TZ1_ACCOUNT, + TZ4_ACCOUNT, ] EMPTY_PATH = BipPath.from_string("m") diff --git a/test/conftest.py b/test/conftest.py index 7ebb816f..5e8b5cd5 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -15,11 +15,14 @@ """Pytest configuration file.""" +from functools import wraps import pytest + from ragger.backend import BackendInterface from ragger.conftest import configuration from ragger.firmware import Firmware from ragger.navigator import Navigator +from utils.account import SigScheme from utils.client import TezosClient from utils.navigator import TezosNavigator from common import DEFAULT_SEED @@ -44,3 +47,17 @@ def tezos_navigator( test_name: str) -> TezosNavigator: """Get a tezos navigator.""" return TezosNavigator(backend, firmware, client, navigator, golden_run, test_name) + +def skip_nanos_bls(func): + """Allows to skip tests with BLS `account` on NanoS device""" + @wraps(func) + def wrap(*args, **kwargs): + account = kwargs.get("account", None) + firmware = kwargs.get("firmware", None) + if firmware is not None \ + and firmware.name == "nanos" \ + and account is not None \ + and account.sig_scheme == SigScheme.BLS: + pytest.skip("NanoS does not support BLS") + return func(*args, **kwargs) + return wrap diff --git a/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..3b828104 Binary files /dev/null and b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..504ac251 Binary files /dev/null and b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..8948b71a Binary files /dev/null and b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..504ac251 Binary files /dev/null and b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..4321e601 Binary files /dev/null and b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..88c98327 Binary files /dev/null and b/test/snapshots/flex/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..3b828104 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..504ac251 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..8948b71a Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..504ac251 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..4321e601 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..88c98327 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..c7bf4a80 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..504ac251 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..8948b71a Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..504ac251 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..4321e601 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..88c98327 Binary files /dev/null and b/test/snapshots/flex/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/flex/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context_1.png b/test/snapshots/flex/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context_1.png new file mode 100644 index 00000000..9f0d532e Binary files /dev/null and b/test/snapshots/flex/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context_1.png differ diff --git a/test/snapshots/flex/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context_2.png b/test/snapshots/flex/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context_2.png new file mode 100644 index 00000000..1023d387 Binary files /dev/null and b/test/snapshots/flex/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context_2.png differ diff --git a/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..9d1b7109 Binary files /dev/null and b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..5a03eaec Binary files /dev/null and b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6c58d534 Binary files /dev/null and b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..8cbfee0b Binary files /dev/null and b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..88c98327 Binary files /dev/null and b/test/snapshots/flex/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/flex/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/flex/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/flex/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/flex/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/flex/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/flex/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/flex/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/flex/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/flex/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/flex/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/flex/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/flex/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..43405f4d Binary files /dev/null and b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..8f1620d8 Binary files /dev/null and b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..3627f7c6 Binary files /dev/null and b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..9ed8252c Binary files /dev/null and b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..88c98327 Binary files /dev/null and b/test/snapshots/flex/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/flex/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/flex/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/flex/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/flex/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..62ee420a Binary files /dev/null and b/test/snapshots/flex/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..dc46a09a Binary files /dev/null and b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanosp/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..dc46a09a Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..74612c5f Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanosp/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/chain_id.png b/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/chain_id.png new file mode 100644 index 00000000..8795bcf1 Binary files /dev/null and b/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/chain_id.png differ diff --git a/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/high_watermark.png b/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/high_watermark.png new file mode 100644 index 00000000..a970fc01 Binary files /dev/null and b/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/high_watermark.png differ diff --git a/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/public_key_hash.png b/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/public_key_hash.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanosp/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/public_key_hash.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..95a25b8c Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..f8325615 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..8795bcf1 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ec621614 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..a25aef27 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00007.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00007.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00007.png differ diff --git a/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00008.png b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00008.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanosp/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00008.png differ diff --git a/test/snapshots/nanosp/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanosp/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanosp/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanosp/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanosp/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanosp/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanosp/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanosp/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanosp/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanosp/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanosp/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanosp/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanosp/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanosp/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanosp/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanosp/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanosp/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanosp/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..0ef8964e Binary files /dev/null and b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..f8325615 Binary files /dev/null and b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..7847aa6d Binary files /dev/null and b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanosp/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png differ diff --git a/test/snapshots/nanosp/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanosp/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanosp/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanosp/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanosp/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanosp/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..dc46a09a Binary files /dev/null and b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanox/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..dc46a09a Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..74612c5f Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanox/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/chain_id.png b/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/chain_id.png new file mode 100644 index 00000000..8795bcf1 Binary files /dev/null and b/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/chain_id.png differ diff --git a/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/high_watermark.png b/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/high_watermark.png new file mode 100644 index 00000000..a970fc01 Binary files /dev/null and b/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/high_watermark.png differ diff --git a/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/public_key_hash.png b/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/public_key_hash.png new file mode 100644 index 00000000..6d0ae3ec Binary files /dev/null and b/test/snapshots/nanox/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/public_key_hash.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..95a25b8c Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..f8325615 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..8795bcf1 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..ec621614 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..a25aef27 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00007.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00007.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00007.png differ diff --git a/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00008.png b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00008.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanox/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00008.png differ diff --git a/test/snapshots/nanox/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanox/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanox/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanox/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanox/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanox/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanox/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanox/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanox/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanox/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanox/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanox/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanox/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanox/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanox/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanox/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanox/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanox/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..1ef108c4 Binary files /dev/null and b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..0ef8964e Binary files /dev/null and b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..f8325615 Binary files /dev/null and b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..7847aa6d Binary files /dev/null and b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..739d0b16 Binary files /dev/null and b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..ac17dc75 Binary files /dev/null and b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png new file mode 100644 index 00000000..65788722 Binary files /dev/null and b/test/snapshots/nanox/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00006.png differ diff --git a/test/snapshots/nanox/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/nanox/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..b12898fa Binary files /dev/null and b/test/snapshots/nanox/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/nanox/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/nanox/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..690ad81a Binary files /dev/null and b/test/snapshots/nanox/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..0c89aa3e Binary files /dev/null and b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..14515eff Binary files /dev/null and b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6305b5f5 Binary files /dev/null and b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..14515eff Binary files /dev/null and b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..7a494786 Binary files /dev/null and b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..bfd6f175 Binary files /dev/null and b/test/snapshots/stax/test_authorize_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..0c89aa3e Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..14515eff Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6305b5f5 Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..14515eff Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..7a494786 Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..bfd6f175 Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_baking/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..0ef6f0be Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..14515eff Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..6305b5f5 Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..14515eff Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..7a494786 Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png new file mode 100644 index 00000000..bfd6f175 Binary files /dev/null and b/test/snapshots/stax/test_get_public_key_prompt/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00005.png differ diff --git a/test/snapshots/stax/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context.png b/test/snapshots/stax/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context.png new file mode 100644 index 00000000..947415ba Binary files /dev/null and b/test/snapshots/stax/test_review_home/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/app_context.png differ diff --git a/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..c163e6cb Binary files /dev/null and b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..c2343c4a Binary files /dev/null and b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..22313025 Binary files /dev/null and b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..78b3d4f7 Binary files /dev/null and b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..bfd6f175 Binary files /dev/null and b/test/snapshots/stax/test_setup_app_context/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/stax/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/stax/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/stax/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/stax/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_attestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/stax/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/stax/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/stax/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/stax/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_attestation_dal/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/stax/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/stax/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/stax/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/stax/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_block/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png new file mode 100644 index 00000000..06fcd3e1 Binary files /dev/null and b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00000.png differ diff --git a/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png new file mode 100644 index 00000000..e9fa632c Binary files /dev/null and b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00001.png differ diff --git a/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png new file mode 100644 index 00000000..094d0aac Binary files /dev/null and b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00002.png differ diff --git a/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png new file mode 100644 index 00000000..ddea49a9 Binary files /dev/null and b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00003.png differ diff --git a/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png new file mode 100644 index 00000000..bfd6f175 Binary files /dev/null and b/test/snapshots/stax/test_sign_delegation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/00004.png differ diff --git a/test/snapshots/stax/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png b/test/snapshots/stax/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_after_sign.png differ diff --git a/test/snapshots/stax/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png b/test/snapshots/stax/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png new file mode 100644 index 00000000..cb124f80 Binary files /dev/null and b/test/snapshots/stax/test_sign_preattestation/BLS_tz4Gk6EphzZnu84iEGMV24qwU38vrXSxtw7L/hwm_before_sign.png differ diff --git a/test/test_instructions.py b/test/test_instructions.py index 26af3c50..e3fd1b4e 100644 --- a/test/test_instructions.py +++ b/test/test_instructions.py @@ -22,26 +22,28 @@ import hmac import time +from functools import wraps import pytest -from pytezos import pytezos +from conftest import skip_nanos_bls from ragger.backend import BackendInterface from ragger.firmware import Firmware from utils.client import TezosClient, Version, Hwm, StatusCode -from utils.account import Account +from utils.account import Account, PublicKey, SigScheme from utils.helper import get_current_commit from utils.message import ( Message, - UnsafeOp, + ManagerOperation, + OperationGroup, Delegation, Reveal, + Transaction, Preattestation, Attestation, - AttestationDal, Fitness, BlockHeader, Block, - DEFAULT_CHAIN_ID + Default ) from utils.navigator import ( TezosNavigator, @@ -57,6 +59,7 @@ ZEBRA_ACCOUNTS, ) +@skip_nanos_bls @pytest.mark.parametrize("account", [None, *ACCOUNTS]) def test_review_home(account: Optional[Account], backend: BackendInterface, @@ -274,7 +277,7 @@ def test_automatic_low_cost_screensaver(firmware: Firmware, tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, Hwm(0, 0), Hwm(0, 0) ) @@ -289,7 +292,7 @@ def test_automatic_low_cost_screensaver(firmware: Firmware, attestation = build_attestation( op_level=1, op_round=0, - chain_id=DEFAULT_CHAIN_ID + chain_id=Default.CHAIN_ID ) client.sign_message(account, attestation) @@ -328,7 +331,7 @@ def test_automatic_low_cost_screensaver_cancelled_by_display( tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, Hwm(0, 0), Hwm(0, 0) ) @@ -336,7 +339,7 @@ def test_automatic_low_cost_screensaver_cancelled_by_display( attestation = build_attestation( op_level=1, op_round=0, - chain_id=DEFAULT_CHAIN_ID + chain_id=Default.CHAIN_ID ) client.sign_message(account, attestation) @@ -377,7 +380,7 @@ def test_automatic_low_cost_screensaver_exited_by_display( tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, Hwm(0, 0), Hwm(0, 0) ) @@ -385,7 +388,7 @@ def test_automatic_low_cost_screensaver_exited_by_display( attestation = build_attestation( op_level=1, op_round=0, - chain_id=DEFAULT_CHAIN_ID + chain_id=Default.CHAIN_ID ) client.sign_message(account, attestation) @@ -414,7 +417,7 @@ def test_automatic_low_cost_screensaver_exited_by_display( attestation = build_attestation( op_level=2, op_round=0, - chain_id=DEFAULT_CHAIN_ID + chain_id=Default.CHAIN_ID ) client.sign_message(account, attestation) @@ -456,7 +459,14 @@ def test_ledger_screensaver(firmware: Firmware, client: TezosClient, tezos_navigator: TezosNavigator, backend_name) -> None: - # Make sure that ledger device being tested has screensaver time set to 1 minute and PIN lock is disabled. + """Test the ledger's screensaver. + + Make sure that ledger device being tested has screensaver time + set to 1 minute and PIN lock is disabled. + + Only runs for physical devices. + + """ account = DEFAULT_ACCOUNT if backend_name == "speculos": assert True @@ -468,7 +478,7 @@ def test_ledger_screensaver(firmware: Firmware, assert (res.find("y") != -1), "Ledger screensaver should have activated" lvl = 0 - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(lvl, 0) test_hwm = Hwm(0, 0) @@ -495,15 +505,25 @@ def test_ledger_screensaver(firmware: Firmware, assert (res.find("y") != -1), "Ledger screensaver should have activated" +@skip_nanos_bls @pytest.mark.parametrize("account", ZEBRA_ACCOUNTS) -def test_benchmark_attestation_time(account: Account, client: TezosClient, tezos_navigator: TezosNavigator, backend_name) -> None: +def test_benchmark_attestation_time(account: Account, + firmware: Firmware, + client: TezosClient, + tezos_navigator: TezosNavigator, + backend_name) -> None: + """Benchmark attestation signing time. + + Only runs for physical devices. + + """ # check if backend is speculos, then return . if backend_name == "speculos": assert True return lvl = 0 - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(lvl, 0) test_hwm = Hwm(0, 0) @@ -525,21 +545,33 @@ def test_benchmark_attestation_time(account: Account, client: TezosClient, tezos client.sign_message(account, attestation) end= time.time() with open("Avg_time_for_100_attestations.txt",'a') as f: - f.write("\nTime elapsed for derivation type : " + str(account) + " is : " + str(end-st) + "\n") + f.write( + "\nTime elapsed for derivation type : " + + str(account) + + " is : " + + str(end-st) + + "\n" + ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) -def test_authorize_baking(account: Account, tezos_navigator: TezosNavigator) -> None: +def test_authorize_baking(account: Account, + firmware: Firmware, + tezos_navigator: TezosNavigator) -> None: """Test the AUTHORIZE_BAKING instruction.""" snap_path = Path(f"{account}") - public_key = tezos_navigator.authorize_baking(account, snap_path=snap_path) + data = tezos_navigator.authorize_baking(account, snap_path=snap_path) - account.check_public_key(public_key) + public_key = PublicKey.from_bytes(data, account.sig_scheme) + + assert account.public_key == public_key, \ + f"Expected public key {account.public_key} but got {public_key}" tezos_navigator.check_app_context( account, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) @@ -570,14 +602,16 @@ def test_deauthorize(firmware: Firmware, tezos_navigator.check_app_context( None, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) def test_get_auth_key( account: Account, + firmware: Firmware, client: TezosClient, tezos_navigator: TezosNavigator) -> None: """Test the QUERY_AUTH_KEY instruction.""" @@ -589,9 +623,11 @@ def test_get_auth_key( assert path == account.path, \ f"Expected {account.path} but got {path}" +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) def test_get_auth_key_with_curve( account: Account, + firmware: Firmware, client: TezosClient, tezos_navigator: TezosNavigator) -> None: """Test the QUERY_AUTH_KEY_WITH_CURVE instruction.""" @@ -606,33 +642,47 @@ def test_get_auth_key_with_curve( assert sig_scheme == account.sig_scheme, \ f"Expected {account.sig_scheme.name} but got {sig_scheme.name}" +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) -def test_get_public_key_baking(account: Account, tezos_navigator: TezosNavigator) -> None: +def test_get_public_key_baking(account: Account, + firmware: Firmware, + tezos_navigator: TezosNavigator) -> None: """Test the AUTHORIZE_BAKING instruction.""" tezos_navigator.authorize_baking(account) - public_key = tezos_navigator.authorize_baking(None, snap_path=Path(f"{account}")) + data = tezos_navigator.authorize_baking(None, snap_path=Path(f"{account}")) + + public_key = PublicKey.from_bytes(data, account.sig_scheme) - account.check_public_key(public_key) + assert account.public_key == public_key, \ + f"Expected public key {account.public_key} but got {public_key}" +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) -def test_get_public_key_silent(account: Account, client: TezosClient) -> None: +def test_get_public_key_silent(account: Account, + firmware: Firmware, + client: TezosClient) -> None: """Test the GET_PUBLIC_KEY instruction.""" public_key = client.get_public_key_silent(account) - account.check_public_key(public_key) + assert account.public_key == public_key, \ + f"Expected public key {account.public_key} but got {public_key}" +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) -def test_get_public_key_prompt(account: Account, tezos_navigator: TezosNavigator) -> None: +def test_get_public_key_prompt(account: Account, + firmware: Firmware, + tezos_navigator: TezosNavigator) -> None: """Test the PROMPT_PUBLIC_KEY instruction.""" public_key = tezos_navigator.get_public_key_prompt(account, snap_path=Path(f"{account}")) - account.check_public_key(public_key) + assert account.public_key == public_key, \ + f"Expected public key {account.public_key} but got {public_key}" def test_reset_app_context(tezos_navigator: TezosNavigator) -> None: @@ -644,14 +694,17 @@ def test_reset_app_context(tezos_navigator: TezosNavigator) -> None: tezos_navigator.check_app_context( None, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(reset_level, 0), test_hwm=Hwm(reset_level, 0) ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) -def test_setup_app_context(account: Account, tezos_navigator: TezosNavigator) -> None: +def test_setup_app_context(account: Account, + firmware: Firmware, + tezos_navigator: TezosNavigator) -> None: """Test the SETUP instruction.""" snap_path = Path(f"{account}") @@ -667,7 +720,8 @@ def test_setup_app_context(account: Account, tezos_navigator: TezosNavigator) -> snap_path=snap_path ) - account.check_public_key(public_key) + assert account.public_key == public_key, \ + f"Expected public key {account.public_key} but got {public_key}" tezos_navigator.check_app_context( account, @@ -677,14 +731,16 @@ def test_setup_app_context(account: Account, tezos_navigator: TezosNavigator) -> ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) def test_get_main_hwm( account: Account, + firmware: Firmware, client: TezosClient, tezos_navigator: TezosNavigator) -> None: """Test the QUERY_MAIN_HWM instruction.""" - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(0, 0) test_hwm = Hwm(0, 0) @@ -701,14 +757,16 @@ def test_get_main_hwm( f"Expected main hmw {main_hwm} but got {received_main_hwm}" +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) def test_get_all_hwm( account: Account, + firmware: Firmware, client: TezosClient, tezos_navigator: TezosNavigator) -> None: """Test the QUERY_ALL_HWM instruction.""" - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(0, 0) test_hwm = Hwm(0, 0) @@ -735,22 +793,26 @@ def build_preattestation(op_level, op_round, chain_id): """Build a preattestation.""" return Preattestation( op_level=op_level, - op_round=op_round - ).forge(chain_id=chain_id) + op_round=op_round, + chain_id=chain_id + ) def build_attestation(op_level, op_round, chain_id): """Build a attestation.""" return Attestation( op_level=op_level, - op_round=op_round - ).forge(chain_id=chain_id) + op_round=op_round, + chain_id=chain_id + ) def build_attestation_dal(op_level, op_round, chain_id): """Build a attestation_dal.""" - return AttestationDal( + return Attestation( op_level=op_level, - op_round=op_round - ).forge(chain_id=chain_id) + op_round=op_round, + dal_attestation=0, + chain_id=chain_id + ) def build_block(level, current_round, chain_id): """Build a block.""" @@ -758,10 +820,12 @@ def build_block(level, current_round, chain_id): header=BlockHeader( level=level, fitness=Fitness(current_round=current_round) - ) - ).forge(chain_id=chain_id) + ), + chain_id=chain_id + ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) @pytest.mark.parametrize("with_hash", [False, True]) def test_sign_preattestation( @@ -774,7 +838,7 @@ def test_sign_preattestation( """Test the SIGN(_WITH_HASH) instruction on preattestation.""" snap_path = Path(f"{account}") - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(0, 0) test_hwm = Hwm(0, 0) @@ -819,6 +883,7 @@ def test_sign_preattestation( ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) @pytest.mark.parametrize("with_hash", [False, True]) def test_sign_attestation( @@ -831,7 +896,7 @@ def test_sign_attestation( """Test the SIGN(_WITH_HASH) instruction on attestation.""" snap_path = Path(f"{account}") - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(0, 0) test_hwm = Hwm(0, 0) @@ -876,6 +941,7 @@ def test_sign_attestation( ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) @pytest.mark.parametrize("with_hash", [False, True]) def test_sign_attestation_dal( @@ -888,7 +954,7 @@ def test_sign_attestation_dal( """Test the SIGN(_WITH_HASH) instruction on attestation.""" snap_path = Path(f"{account}") - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(0, 0) test_hwm = Hwm(0, 0) @@ -933,6 +999,7 @@ def test_sign_attestation_dal( ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) @pytest.mark.parametrize("with_hash", [False, True]) def test_sign_block( @@ -945,7 +1012,7 @@ def test_sign_block( """Test the SIGN(_WITH_HASH) instruction on block.""" snap_path = Path(f"{account}") - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(0, 0) test_hwm = Hwm(0, 0) @@ -997,7 +1064,7 @@ def test_sign_block_at_reset_level(client: TezosClient, tezos_navigator: TezosNa reset_level: int = 1 - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_hwm = Hwm(reset_level, 0) test_hwm = Hwm(0, 0) @@ -1059,7 +1126,7 @@ def test_sign_level_authorized( account: Account = DEFAULT_ACCOUNT - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID main_level = 1 tezos_navigator.setup_app_context( @@ -1091,18 +1158,20 @@ def test_sign_level_authorized( client.sign_message(account, message_2) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) @pytest.mark.parametrize("with_hash", [False, True]) def test_sign_delegation( account: Account, with_hash: bool, + firmware: Firmware, tezos_navigator: TezosNavigator) -> None: """Test the SIGN(_WITH_HASH) instruction on delegation.""" snap_path = Path(f"{account}") tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) @@ -1112,15 +1181,13 @@ def test_sign_delegation( source=account.public_key_hash, ) - raw_delegation = delegation.forge() - if not with_hash: signature = tezos_navigator.sign_delegation( account, delegation, snap_path=snap_path ) - account.check_signature(signature, bytes(raw_delegation)) + account.check_signature(signature, bytes(delegation)) else: delegation_hash, signature = \ tezos_navigator.sign_delegation_with_hash( @@ -1128,9 +1195,9 @@ def test_sign_delegation( delegation, snap_path=snap_path ) - assert delegation_hash == raw_delegation.hash, \ - f"Expected hash {raw_delegation.hash.hex()} but got {delegation_hash.hex()}" - account.check_signature(signature, bytes(raw_delegation)) + assert delegation_hash == delegation.hash, \ + f"Expected hash {delegation.hash.hex()} but got {delegation_hash.hex()}" + account.check_signature(signature, bytes(delegation)) @@ -1153,7 +1220,7 @@ def test_sign_delegation_fee( tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) @@ -1211,7 +1278,7 @@ def test_sign_delegation_constraints( tezos_navigator.setup_app_context( setup_account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) @@ -1228,18 +1295,20 @@ def test_sign_delegation_constraints( ) +@skip_nanos_bls @pytest.mark.parametrize("account", ACCOUNTS) @pytest.mark.parametrize("with_hash", [False, True]) def test_sign_reveal( account: Account, with_hash: bool, + firmware: Firmware, client: TezosClient, tezos_navigator: TezosNavigator) -> None: """Test the SIGN(_WITH_HASH) instruction on reveal.""" tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) @@ -1247,7 +1316,7 @@ def test_sign_reveal( reveal = Reveal( public_key=account.public_key, source=account.public_key_hash, - ).forge() + ) if not with_hash: signature = client.sign_message( @@ -1306,7 +1375,7 @@ def test_sign_reveal_constraints( tezos_navigator.setup_app_context( setup_account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) @@ -1314,7 +1383,7 @@ def test_sign_reveal_constraints( reveal = Reveal( public_key=public_key_account.public_key, source=source_account.public_key_hash, - ).forge() + ) with status_code.expected(): client.sign_message( @@ -1331,7 +1400,7 @@ def test_sign_not_authorized_key( account_1 = DEFAULT_ACCOUNT account_2 = DEFAULT_ACCOUNT_2 - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID tezos_navigator.setup_app_context( account_1, @@ -1354,7 +1423,7 @@ def test_sign_transaction( account_1 = DEFAULT_ACCOUNT account_2 = DEFAULT_ACCOUNT_2 - main_chain_id = DEFAULT_CHAIN_ID + main_chain_id = Default.CHAIN_ID tezos_navigator.setup_app_context( account_1, @@ -1363,14 +1432,11 @@ def test_sign_transaction( test_hwm=Hwm(0, 0) ) - ctxt = pytezos.using() - transaction = UnsafeOp( - ctxt.transaction( - source=account_1.public_key_hash, - destination=account_2.public_key_hash, - amount=10_000, - ) - ).forge() + transaction = Transaction( + source=account_1.public_key_hash, + destination=account_2.public_key_hash, + amount=10_000, + ) with StatusCode.PARSE_ERROR.expected(): client.sign_message(account_1, transaction) @@ -1388,15 +1454,12 @@ def build_delegation(account: Account) -> Delegation: delegate=account.public_key_hash, source=account.public_key_hash, ) -def build_transaction(account: Account) -> UnsafeOp: +def build_transaction(account: Account) -> Transaction: """Build a transaction.""" - ctxt = pytezos.using() - return UnsafeOp( - ctxt.transaction( - source=account.public_key_hash, - destination=DEFAULT_ACCOUNT_2.public_key_hash, - amount=10_000, - ) + return Transaction( + source=account.public_key_hash, + destination=DEFAULT_ACCOUNT_2.public_key_hash, + amount=10_000, ) def build_bad_reveal_1(account: Account) -> Reveal: """Build a bad reveal.""" @@ -1462,9 +1525,9 @@ def build_bad_delegation_2(account: Account) -> Delegation: PARAMETERS_SIGN_MULTIPLE_OPERATIONS ) def test_sign_multiple_operation( - operation_builder_1: Callable[[Account], UnsafeOp], - operation_builder_2: Callable[[Account], UnsafeOp], - operation_builder_3: Optional[Callable[[Account], UnsafeOp]], + operation_builder_1: Callable[[Account], ManagerOperation], + operation_builder_2: Callable[[Account], ManagerOperation], + operation_builder_3: Optional[Callable[[Account], ManagerOperation]], status_code: StatusCode, operation_display: bool, client: TezosClient, @@ -1475,37 +1538,34 @@ def test_sign_multiple_operation( tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, + Default.CHAIN_ID, main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) - operation = operation_builder_1(account) - operation = operation.merge( - operation_builder_2(account) - ) + operations = [ + operation_builder_1(account), + operation_builder_2(account), + ] if operation_builder_3 is not None: - operation = operation.merge( - operation_builder_3(account) - ) - - message = operation.forge() + operations.append(operation_builder_3(account)) + operation = OperationGroup(operations) with status_code.expected(): if operation_display: signature = send_and_navigate( send=lambda: client.sign_message( account, - message + operation ), navigate=tezos_navigator.accept_sign_navigate ) else: signature = client.sign_message( account, - message + operation ) - account.check_signature(signature, bytes(message)) + account.check_signature(signature, bytes(operation)) def test_sign_when_hwm_disabled( @@ -1519,21 +1579,21 @@ def test_sign_when_hwm_disabled( tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, # Chain = 0 + Default.CHAIN_ID, # Chain = 0 main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) attestation = build_attestation( 1, 0, - DEFAULT_CHAIN_ID # Chain = 0 + Default.CHAIN_ID # Chain = 0 ) client.sign_message(account, attestation) tezos_navigator.check_app_context( account, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(1, 0), test_hwm=Hwm(0, 0) ) @@ -1547,7 +1607,7 @@ def test_sign_when_hwm_disabled( tezos_navigator.check_app_context( account, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(2, 0), test_hwm=Hwm(0, 0) ) @@ -1562,18 +1622,26 @@ def test_sign_when_hwm_disabled( tezos_navigator.check_app_context( account, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(2, 0), test_hwm=Hwm(0, 0) ) @pytest.mark.parametrize("exit_style", ["abruptly", "properly"]) -def test_hwm_disabled_exit(client: TezosClient, tezos_navigator: TezosNavigator, exit_style, backend_name) -> None: - """On device test to verify HWM settings operation. Can run the test with hwm setting enabled or disabled. - When HWM is disabled, an abrupt power off will result in HWM reset to 0. - Whwereas when HWM settings is enabled, the abrupt power off will not - reset the HWM. With a proper exit, HWM will always be preserved.""" +def test_hwm_disabled_exit(client: TezosClient, + tezos_navigator: TezosNavigator, + exit_style, backend_name) -> None: + """On device test to verify HWM settings operation. Can run the + test with hwm setting enabled or disabled. When HWM is + disabled, an abrupt power off will result in HWM reset to 0. + Whwereas when HWM settings is enabled, the abrupt power off + will not reset the HWM. With a proper exit, HWM will always be + preserved. + + Only runs for physical devices. + + """ # check if backend is speculos, then return . if backend_name == "speculos": assert True @@ -1588,12 +1656,12 @@ def test_hwm_disabled_exit(client: TezosClient, tezos_navigator: TezosNavigator, tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, # Chain = 0 + Default.CHAIN_ID, # Chain = 0 main_hwm = Hwm(0, 0), test_hwm = Hwm(0, 0) ) for i in range(1, 11): - attestation = build_attestation(i, 0, DEFAULT_CHAIN_ID) + attestation = build_attestation(i, 0, Default.CHAIN_ID) client.sign_message(account, attestation) main_hwm = Hwm(10,0) received_main_hwm = tezos_navigator.client.get_main_hwm() @@ -1623,21 +1691,21 @@ def test_sign_when_no_chain_setup( tezos_navigator.setup_app_context( account, - DEFAULT_CHAIN_ID, # Chain = 0 + Default.CHAIN_ID, # Chain = 0 main_hwm=Hwm(0, 0), test_hwm=Hwm(0, 0) ) attestation = build_attestation( 1, 0, - DEFAULT_CHAIN_ID # Chain = 0 + Default.CHAIN_ID # Chain = 0 ) client.sign_message(account, attestation) tezos_navigator.check_app_context( account, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(1, 0), test_hwm=Hwm(0, 0) ) @@ -1651,7 +1719,7 @@ def test_sign_when_no_chain_setup( tezos_navigator.check_app_context( account, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(2, 0), test_hwm=Hwm(0, 0) ) @@ -1666,7 +1734,7 @@ def test_sign_when_no_chain_setup( tezos_navigator.check_app_context( account, - chain_id=DEFAULT_CHAIN_ID, + chain_id=Default.CHAIN_ID, main_hwm=Hwm(2, 0), test_hwm=Hwm(0, 0) ) @@ -1703,7 +1771,7 @@ def test_sign_when_chain_is_setup( attestation = build_attestation( 2, 0, - DEFAULT_CHAIN_ID # Chain = 0 + Default.CHAIN_ID # Chain = 0 ) client.sign_message(account, attestation) @@ -1746,7 +1814,7 @@ def get_hmac_key(account): ("0123456789abcdef0123456789abcdef0123456789abcdef") ] -# This HMAC test don't pass with tz2 and tz3 +# This HMAC test don't pass with tz2, tz3 and tz4 @pytest.mark.parametrize("account", TZ1_ACCOUNTS) @pytest.mark.parametrize("message_hex", HMAC_TEST_SET) def test_hmac( diff --git a/test/utils/account.py b/test/utils/account.py index cc691fea..5143de53 100644 --- a/test/utils/account.py +++ b/test/utils/account.py @@ -18,12 +18,15 @@ from enum import IntEnum from typing import Union +from hashlib import blake2b import base58 import pysodium import secp256k1 import fastecdsa +from py_ecc.bls import G2MessageAugmentation as bls import pytezos +from pytezos.crypto.encoding import base58_encode from bip_utils.bip.bip32.bip32_path import Bip32Path, Bip32PathParser from bip_utils.bip.bip32.bip32_key_data import Bip32KeyIndex from utils.helper import BytesReader @@ -35,6 +38,7 @@ class SigScheme(IntEnum): SECP256K1 = 0x01 SECP256R1 = 0x02 BIP32_ED25519 = 0x03 + BLS = 0x04 DEFAULT = ED25519 class BipPath: @@ -81,17 +85,8 @@ def from_bytes(cls, raw_path: bytes) -> 'BipPath': class Signature: """Class representing signature.""" - GENERIC_SIGNATURE_PREFIX = bytes.fromhex("04822b") # sig(96) - - def __init__(self, value: bytes): - value = Signature.GENERIC_SIGNATURE_PREFIX + value - self.value: bytes = base58.b58encode_check(value) - - def __repr__(self) -> str: - return self.value.hex() - - @classmethod - def from_tlv(cls, tlv: Union[bytes, bytearray]) -> 'Signature': + @staticmethod + def from_secp256_tlv(tlv: Union[bytes, bytearray]) -> bytes: """Get the signature encapsulated in a TLV.""" # See: # https://developers.ledger.com/docs/embedded-app/crypto-api/lcx__ecdsa_8h/#cx_ecdsa_sign @@ -124,18 +119,91 @@ def from_tlv(cls, tlv: Union[bytes, bytearray]) -> 'Signature': # A size adjustment is required here. def adjust_size(data, size): return data[-size:].rjust(size, b'\x00') - return Signature(adjust_size(r, 32) + adjust_size(s, 32)) + return adjust_size(r, 32) + adjust_size(s, 32) @classmethod - def from_bytes(cls, data: bytes, sig_scheme: SigScheme) -> 'Signature': + def from_bytes(cls, data: bytes, sig_scheme: SigScheme) -> str: """Get the signature according to the SigScheme.""" if sig_scheme in { SigScheme.ED25519, SigScheme.BIP32_ED25519 }: - return Signature(data) - return Signature.from_tlv(data) + prefix = bytes([9, 245, 205, 134, 18]) + elif sig_scheme in { SigScheme.SECP256K1, SigScheme.SECP256R1 }: + prefix = bytes([13, 115, 101, 19, 63]) if sig_scheme == SigScheme.SECP256K1 \ + else bytes([54, 240, 44, 52]) + data = Signature.from_secp256_tlv(data) + elif sig_scheme == SigScheme.BLS: + prefix = bytes([40, 171, 64, 207]) + else: + assert False, f"Wrong signature type: {sig_scheme}" + + return base58.b58encode_check(prefix + data).decode() + +class PublicKey: + """Set of functions over public key management""" + + class CompressionKind(IntEnum): + """Bytes compression kind""" + EVEN = 0x02 + ODD = 0x03 + UNCOMPRESSED = 0x04 + + def __bytes__(self) -> bytes: + return bytes([self]) + + @staticmethod + def from_bytes(data: bytes, sig_scheme: SigScheme) -> str: + """Convert a public key from bytes to string""" + # `data` should be: + # kind + pk + # pk length = 32 for compressed, 64 for uncompressed + kind = data[0] + data = data[1:] + + # Ed25519 + if sig_scheme in [ + SigScheme.ED25519, + SigScheme.BIP32_ED25519 + ]: + assert kind == PublicKey.CompressionKind.EVEN, \ + f"Wrong Ed25519 public key compression kind: {kind}" + assert len(data) == 32, \ + f"Wrong Ed25519 public key length: {len(data)}" + return base58_encode(data, b'edpk').decode() + + # Secp256 + if sig_scheme in [ + SigScheme.SECP256K1, + SigScheme.SECP256R1 + ]: + assert kind == PublicKey.CompressionKind.UNCOMPRESSED, \ + f"Wrong Secp256 public key compression kind: {kind}" + assert len(data) == 2 * 32, \ + f"Wrong Secp256 public key length: {len(data)}" + kind = PublicKey.CompressionKind.ODD if data[-1] & 1 else \ + PublicKey.CompressionKind.EVEN + prefix = b'sppk' if sig_scheme == SigScheme.SECP256K1 \ + else b'p2pk' + data = bytes(kind) + data[:32] + return base58_encode(data, prefix).decode() + + # BLS + if sig_scheme == SigScheme.BLS: + assert kind == PublicKey.CompressionKind.UNCOMPRESSED, \ + f"Wrong BLS public key compression kind: {kind}" + assert len(data) == 2 * 48, \ + f"Wrong BLS public key length: {len(data)}" + return base58.b58encode_check(bytes([6, 149, 135, 204]) + data[:48]).decode() + + assert False, f"Wrong signature type: {sig_scheme}" class Account: """Class representing account.""" + path: BipPath + sig_scheme: SigScheme + # key: str == BLS.sk since pytezos do not support BLS for now + key: Union[pytezos.Key, str] + nanos_screens: int + def __init__(self, path: Union[BipPath, str, bytes], sig_scheme: SigScheme, @@ -146,31 +214,44 @@ def __init__(self, BipPath.from_bytes(path) if isinstance(path, bytes) else \ path self.sig_scheme: SigScheme = sig_scheme - self.key: pytezos.Key = pytezos.pytezos.using(key=key).key + if self.sig_scheme == SigScheme.BLS: + self.key: str = key + else: + self.key: pytezos.Key = pytezos.pytezos.using(key=key).key self.nanos_screens: int = nanos_screens @property def public_key_hash(self) -> str: """public_key_hash of the account.""" + if isinstance(self.key, str): + pk_raw = base58.b58decode_check(self.public_key.encode())[4:] + pkh_raw = blake2b(pk_raw, digest_size=20).digest() + return base58.b58encode_check(bytes([6, 161, 166]) + pkh_raw).decode() + return self.key.public_key_hash() @property def public_key(self) -> str: """public_key of the account.""" + if isinstance(self.key, str): + sk_raw = base58.b58decode_check(self.secret_key.encode())[4:] + sk_int = int.from_bytes(sk_raw, 'little') + pk_raw = bls.SkToPk(sk_int) + return base58.b58encode_check(bytes([6, 149, 135, 204]) + pk_raw).decode() + return self.key.public_key() @property def secret_key(self) -> str: """secret_key of the account.""" + if isinstance(self.key, str): + return self.key + return self.key.secret_key() def __repr__(self) -> str: return f"{self.sig_scheme.name}_{self.public_key_hash}" - def sign(self, message: Union[str, bytes], generic: bool = False) -> bytes: - """Sign a raw sequence of bytes.""" - return self.key.sign(message, generic) - def sign_prehashed_message(self, prehashed_message: bytes) -> bytes: """Sign a raw sequence of bytes already hashed.""" if self.sig_scheme in [ @@ -196,73 +277,30 @@ def sign_prehashed_message(self, prehashed_message: bytes) -> bytes: prehashed=True ) return r.to_bytes(32, 'big') + s.to_bytes(32, 'big') - raise ValueError(f"Account do not have a right signature type: {self.sig_scheme}") - - @property - def base58_decoded(self) -> bytes: - """base58_decoded of the account.""" + if self.sig_scheme == SigScheme.BLS: + sk_raw = base58.b58decode_check(self.secret_key.encode())[4:] + sk_int = int.from_bytes(sk_raw, 'little') # Tezos encode it in 'little' + return bls.Sign(sk_int, prehashed_message) - # Get the public_key without prefix - public_key = base58.b58decode_check(self.public_key) - - if self.sig_scheme in [ - SigScheme.ED25519, - SigScheme.BIP32_ED25519 - ]: - prefix = bytes.fromhex("0d0f25d9") # edpk(54) - elif self.sig_scheme == SigScheme.SECP256K1: - prefix = bytes.fromhex("03fee256") # sppk(55) - elif self.sig_scheme == SigScheme.SECP256R1: - prefix = bytes.fromhex("03b28b7f") # p2pk(55) - else: - raise ValueError(f"Account do not have a right signature type: {self.sig_scheme}") - assert public_key.startswith(prefix), \ - "Expected prefix {prefix.hex()} but got {public_key.hex()}" - - public_key = public_key[len(prefix):] - - if self.sig_scheme in [ - SigScheme.SECP256K1, - SigScheme.SECP256R1 - ]: - assert public_key[0] in [0x02, 0x03], \ - "Expected a prefix kind of 0x02 or 0x03 but got {public_key[0]}" - public_key = public_key[1:] - - return public_key - - def check_public_key(self, data: bytes) -> None: - """Check that the data correspond to the account.""" - - # `data` should be: - # length + kind + pk - # kind : 02=odd, 03=even, 04=uncompressed - # pk length = 32 for compressed, 64 for uncompressed - assert len(data) - 1 == data[0], \ - "Expected a length of {data[0]} but got {len(data) - 1}" - if data[1] == 0x04: # public key uncompressed - assert data[0] == 1 + 32 + 32, \ - "Expected a length of 1 + 32 + 32 but got {data[0]}" - elif data[1] in [0x02, 0x03]: # public key even or odd (compressed) - assert data[0] == 1 + 32, \ - "Expected a length of 1 + 32 but got {data[0]}" - else: - raise ValueError(f"Expected a prefix kind of 0x02, 0x03 or 0x04 but got {data[1]}") - data = data[2:2+32] - - public_key = self.base58_decoded - assert data == public_key, \ - f"Expected public key {public_key.hex()} but got {data.hex()}" + raise ValueError(f"Account do not have a right signature type: {self.sig_scheme}") def check_signature(self, - signature: Union[bytes, Signature], + signature: Union[str, bytes], message: Union[str, bytes]): """Check that the signature is the signature of the message by the account.""" if isinstance(message, str): message = bytes.fromhex(message) if isinstance(signature, bytes): signature = Signature.from_bytes(signature, self.sig_scheme) - assert self.key.verify(signature.value, message), \ - f"Fail to verify signature {signature}, \n\ - with account {self} \n\ - and message {message.hex()}" + if isinstance(self.key, str): + pk_raw = base58.b58decode_check(self.public_key.encode())[4:] + signature_raw = base58.b58decode_check(signature.encode())[4:] + assert bls.Verify(pk_raw, message, signature_raw), \ + f"Fail to verify signature {signature}, \n\ + with account {self} \n\ + and message {message.hex()}" + else: + assert self.key.verify(signature.encode(), message), \ + f"Fail to verify signature {signature}, \n\ + with account {self} \n\ + and message {message.hex()}" diff --git a/test/utils/client.py b/test/utils/client.py index c6b45e0c..191d4d45 100644 --- a/test/utils/client.py +++ b/test/utils/client.py @@ -23,7 +23,7 @@ from ragger.backend import BackendInterface from ragger.error import ExceptionRAPDU from pytezos.michelson import forge -from utils.account import Account, SigScheme, BipPath, Signature +from utils.account import Account, BipPath, PublicKey, Signature, SigScheme from utils.helper import BytesReader from utils.message import Message @@ -169,6 +169,7 @@ class StatusCode(IntEnum): HID_REQUIRED = 0x6983 CLASS = 0x6e00 MEMORY_ERROR = 0x9200 + CX_ERR = 0x9001 @contextmanager def expected(self) -> Generator[None, None, None]: @@ -237,11 +238,16 @@ def authorize_baking(self, account: Optional[Account]) -> bytes: sig_scheme=account.sig_scheme payload=bytes(account.path) - return self._exchange( + data = self._exchange( ins=Ins.AUTHORIZE_BAKING, sig_scheme=sig_scheme, payload=payload) + length, data = data[0], data[1:] + assert length == len(data), f"Wrong data size, {length} != {len(data)}" + + return data + def deauthorize(self) -> None: """Send the DEAUTHORIZE instruction.""" data = self._exchange(ins=Ins.DEAUTHORIZE) @@ -259,20 +265,30 @@ def get_auth_key_with_curve(self) -> Tuple[SigScheme, BipPath]: sig_scheme = SigScheme(data[0]) return sig_scheme, BipPath.from_bytes(data[1:]) - def get_public_key_silent(self, account: Account) -> bytes: + def get_public_key_silent(self, account: Account) -> str: """Send the GET_PUBLIC_KEY instruction.""" - return self._exchange( + data = self._exchange( ins=Ins.GET_PUBLIC_KEY, sig_scheme=account.sig_scheme, payload=bytes(account.path)) - def get_public_key_prompt(self, account: Account) -> bytes: + length, data = data[0], data[1:] + assert length == len(data), f"Wrong data size, {length} != {len(data)}" + + return PublicKey.from_bytes(data, account.sig_scheme) + + def get_public_key_prompt(self, account: Account) -> str: """Send the PROMPT_PUBLIC_KEY instruction.""" - return self._exchange( + data = self._exchange( ins=Ins.PROMPT_PUBLIC_KEY, sig_scheme=account.sig_scheme, payload=bytes(account.path)) + length, data = data[0], data[1:] + assert length == len(data), f"Wrong data size, {length} != {len(data)}" + + return PublicKey.from_bytes(data, account.sig_scheme) + def reset_app_context(self, reset_level: int) -> None: """Send the RESET instruction.""" reset_level_raw = reset_level.to_bytes(4, byteorder='big') @@ -286,7 +302,7 @@ def setup_app_context(self, account: Account, main_chain_id: str, main_hwm: Hwm, - test_hwm: Hwm) -> bytes: + test_hwm: Hwm) -> str: """Send the SETUP instruction.""" data: bytes = b'' @@ -295,11 +311,16 @@ def setup_app_context(self, data += bytes(test_hwm) data += bytes(account.path) - return self._exchange( + data = self._exchange( ins=Ins.SETUP, sig_scheme=account.sig_scheme, payload=data) + length, data = data[0], data[1:] + assert length == len(data), f"Wrong data size, {length} != {len(data)}" + + return PublicKey.from_bytes(data, account.sig_scheme) + def get_main_hwm(self) -> Hwm: """Send the QUERY_MAIN_HWM instruction.""" return Hwm.from_bytes(self._exchange(ins=Ins.QUERY_MAIN_HWM)) @@ -322,7 +343,7 @@ def get_all_hwm(self) -> Tuple[str, Hwm, Hwm]: def sign_message(self, account: Account, - message: Message) -> Signature: + message: Message) -> str: """Send the SIGN instruction.""" self._exchange( @@ -339,7 +360,7 @@ def sign_message(self, def sign_message_with_hash(self, account: Account, - message: Message) -> Tuple[bytes, Signature]: + message: Message) -> Tuple[bytes, str]: """Send the SIGN_WITH_HASH instruction.""" self._exchange( diff --git a/test/utils/message.py b/test/utils/message.py index fe657328..e1bf7408 100644 --- a/test/utils/message.py +++ b/test/utils/message.py @@ -17,12 +17,25 @@ from abc import ABC, abstractmethod from enum import IntEnum -from hashlib import blake2b -from typing import Optional, Union -from pytezos import pytezos -from pytezos.operation.group import OperationGroup -from pytezos.block.forge import forge_int_fixed, forge_fitness -from pytezos.michelson import forge +from typing import Any, Dict, List, Optional, Union + +import base58 + +from pytezos.block.forge import forge_block_header, forge_int_fixed +from pytezos.crypto.encoding import base58_encodings +from pytezos.crypto.key import blake2b_32 +from pytezos.michelson.forge import ( + forge_address, + forge_base58, + forge_int16, + forge_int32, + forge_nat, + # forge_public_key, # overrode until BLS key included +) +from pytezos.operation.content import ContentMixin +from pytezos.operation.forge import forge_tag +# from pytezos.operation.group import OperationGroup +from pytezos.rpc.kind import operation_tags class Message(ABC): """Class representing a message.""" @@ -32,38 +45,33 @@ class Message(ABC): @property def hash(self) -> bytes: """hash of the message.""" - return blake2b( - self.raw(), - digest_size=Message.HASH_SIZE - ).digest() + return blake2b_32(bytes(self)).digest() @abstractmethod - def raw(self) -> bytes: - """bytes representation of the message.""" - raise NotImplementedError - def __bytes__(self) -> bytes: - return self.raw() + raise NotImplementedError class RawMessage(Message): """Class representing a raw message.""" + _value: bytes + def __init__(self, value: Union[str, bytes]): - self.value: bytes = value if isinstance(value, bytes) else \ + self._value = value if isinstance(value, bytes) else \ bytes.fromhex(value) - def raw(self) -> bytes: - return self.value + def __bytes__(self) -> bytes: + return self._value -class MagicByte(IntEnum): - """Class representing the magic byte.""" +class Watermark(IntEnum): + """Class hodling messages watermark.""" INVALID = 0x00 BLOCK = 0x01 BAKING_OP = 0x02 - UNSAFE_OP = 0x03 + MANAGER_OPERATION = 0x03 UNSAFE_OP2 = 0x04 - UNSAFE_OP3 = 0x05 + MICHELINE_EXPRESSION = 0x05 TENDERBAKE_BLOCK = 0x11 TENDERBAKE_PREATTESTATION = 0x12 TENDERBAKE_ATTESTATION = 0x13 @@ -92,191 +100,365 @@ class OperationTag(IntEnum): ATTESTATION = 21 ATTESTATION_WITH_DAL = 23 -# Chain_id.zero -DEFAULT_CHAIN_ID = "NetXH12Aer3be93" -# Block_hash.zero -DEFAULT_BLOCK_HASH = "BKiHLREqU3JkXfzEDYAkmmfX48gBDtYhMrpA98s7Aq4SzbUAB6M" -# Block_payload_hash.zero -DEFAULT_BLOCK_PAYLOAD_HASH = "vh1g87ZG6scSYxKhspAUzprQVuLAyoa5qMBKcUfjgnQGnFb3dJcG" -# Operation_list_list_hash.zero -DEFAULT_OPERATIONS_HASH = "LLoZKi1iMzbeJrfrGWPFYmkLebcsha6vGskQ4rAXt2uMwQtBfRcjL" -# Time.Protocol.epoch -DEFAULT_TIMESTAMP = "1970-01-01T00:00:00-00:00" -# Context_hash.zero -DEFAULT_CONTEXT_HASH = "CoUeJrcPBj3T3iJL3PY4jZHnmZa5rRZ87VQPdSBNBcwZRMWJGh9j" +Micheline = Union[List, Dict] + +class Default: + """Class holding default values.""" + + BLOCK_HASH: str = "BKiHLREqU3JkXfzEDYAkmmfX48gBDtYhMrpA98s7Aq4SzbUAB6M" + BLOCK_PAYLOAD_HASH: str = "vh1g87ZG6scSYxKhspAUzprQVuLAyoa5qMBKcUfjgnQGnFb3dJcG" + CHAIN_ID: str = "NetXH12Aer3be93" + CONTEXT_HASH: str = "CoUeJrcPBj3T3iJL3PY4jZHnmZa5rRZ87VQPdSBNBcwZRMWJGh9j" + ED25519_PUBLIC_KEY: str = 'edpkteDwHwoNPB18tKToFKeSCykvr1ExnoMV5nawTJy9Y9nLTfQ541' + ED25519_PUBLIC_KEY_HASH: str = 'tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU' + ENTRYPOINT: str = 'default' + OPERATIONS_HASH: str = "LLoZKi1iMzbeJrfrGWPFYmkLebcsha6vGskQ4rAXt2uMwQtBfRcjL" + TIMESTAMP: str = "1970-01-01T00:00:00-00:00" + + class Micheline: + """Class holding Micheline default values.""" + VALUE: Micheline = {'prim': 'Unit'} + +class OperationBuilder(ContentMixin): + """Extends and fix pytezos.operation.content.ContentMixin.""" + + def preattestation( + self, + slot: int = 0, + op_level: int = 0, + op_round: int = 0, + block_payload_hash: str = Default.BLOCK_PAYLOAD_HASH): + """Build a tezos preattestation.""" + return self.operation( + { + 'kind': 'preattestation', + 'slot': slot, + 'level': op_level, + 'round': op_round, + 'block_payload_hash': block_payload_hash, + } + ) + + def attestation( + self, + slot: int = 0, + op_level: int = 0, + op_round: int = 0, + block_payload_hash: str = Default.BLOCK_PAYLOAD_HASH, + dal_attestation: Optional[int] = None): + """Build a tezos attestation.""" + kind = 'attestation' if dal_attestation is None \ + else 'attestation_with_dal' + content = { + 'kind': kind, + 'slot': slot, + 'level': op_level, + 'round': op_round, + 'block_payload_hash': block_payload_hash, + } + + if dal_attestation is not None: + content['dal_attestation'] = str(dal_attestation) + + return self.operation(content) + +base58_encodings += [(b"BLpk", 76, bytes([6, 149, 135, 204]), 48, "BLS public key")] + +def forge_public_key(value: str) -> bytes: + """Encode public key into bytes. + + :param value: public key in in base58 form + """ + prefix = value[:4] + res = base58.b58decode_check(value)[4:] + + if prefix == 'edpk': # noqa: SIM116 + return b'\x00' + res + if prefix == 'sppk': + return b'\x01' + res + if prefix == 'p2pk': + return b'\x02' + res + if prefix == 'BLpk': + return b'\x03' + res + + raise ValueError(f'Unrecognized key type: #{prefix}') + +class OperationForge: + """Extends and fix pytezos.operation.forge.""" + import pytezos.operation.forge as operation + + operation_tags['preattestation'] = 20 + operation_tags['attestation'] = 21 + operation_tags['attestation_with_dal'] = 23 + + delegation = operation.forge_delegation + transaction = operation.forge_transaction + + @staticmethod + def reveal(content: Dict[str, Any]) -> bytes: + """Forge a tezos reveal.""" + res = forge_tag(operation_tags[content['kind']]) + res += forge_address(content['source'], tz_only=True) + res += forge_nat(int(content['fee'])) + res += forge_nat(int(content['counter'])) + res += forge_nat(int(content['gas_limit'])) + res += forge_nat(int(content['storage_limit'])) + res += forge_public_key(content['public_key']) + return res + + @staticmethod + def preattestation(content: Dict[str, Any]) -> bytes: + """Forge a tezos preattestation.""" + res = forge_tag(operation_tags[content['kind']]) + res += forge_int16(content['slot']) + res += forge_int32(content['level']) + res += forge_int32(content['round']) + res += forge_base58(content['block_payload_hash']) + return res + + @staticmethod + def attestation(content: Dict[str, Any]) -> bytes: + """Forge a tezos attestation.""" + res = forge_tag(operation_tags[content['kind']]) + res += forge_int16(content['slot']) + res += forge_int32(content['level']) + res += forge_int32(content['round']) + res += forge_base58(content['block_payload_hash']) + if content.get('dal_attestation'): + res += forge_nat(int(content['dal_attestation'])) + return res + +class Operation(Message, OperationBuilder): + """Class representing a tezos operation.""" + + branch: str + + def __init__(self, branch: str = Default.BLOCK_HASH): + self.branch = branch -class UnsafeOp: - """Class representing an unsafe operation.""" + @abstractmethod + def forge(self) -> bytes: + """Forge the operation.""" + raise NotImplementedError - operation: OperationGroup + @property + @abstractmethod + def watermark(self) -> bytes: + """Watermark of the operation.""" + raise NotImplementedError - def __init__(self, operation: OperationGroup): - self.operation = operation + def __bytes__(self) -> bytes: + raw = b'' + raw += self.watermark + raw += forge_base58(self.branch) + raw += self.forge() + return raw - def forge(self, branch: str = DEFAULT_BLOCK_HASH) -> Message: - """Forge the operation.""" - watermark = forge_int_fixed(MagicByte.UNSAFE_OP, 1) - self.operation.branch = branch - raw = watermark + bytes.fromhex(self.operation.forge()) - return RawMessage(raw) +class ManagerOperation(Operation): + """Class representing a tezos manager operation.""" - def merge(self, unsafe_op: 'UnsafeOp') -> 'UnsafeOp': - res = self.operation - for content in unsafe_op.operation.contents: - res = res.operation(content) - return UnsafeOp(res) + source: str + fee: int + counter: int + gas_limit: int + storage_limit: int -class Delegation(UnsafeOp): - """Class representing a delegation.""" + @property + def watermark(self) -> bytes: + return forge_int_fixed(Watermark.MANAGER_OPERATION, 1) def __init__(self, - delegate: str, - source: str, - counter: int = 0, + source: str = Default.ED25519_PUBLIC_KEY_HASH, fee: int = 0, + counter: int = 0, gas_limit: int = 0, - storage_limit: int = 0): - ctxt = pytezos.using() - delegation = ctxt.delegation(delegate, source, counter, fee, gas_limit, storage_limit) - super().__init__(delegation) + storage_limit: int = 0, + *args, **kwargs): + self.source = source + self.fee = fee + self.counter = counter + self.gas_limit = gas_limit + self.storage_limit = storage_limit + Operation.__init__(self, *args, **kwargs) + +class OperationGroup(Operation): + """Class representing a group of tezos manager operation.""" + + operations: List[ManagerOperation] + + @property + def watermark(self) -> bytes: + return forge_int_fixed(Watermark.MANAGER_OPERATION, 1) + + def __init__(self, operations: List[ManagerOperation], *args, **kwargs): + self.operations = operations + Operation.__init__(self, *args, **kwargs) + + def forge(self) -> bytes: + return b''.join(map(lambda op: op.forge(), self.operations)) + +class Reveal(ManagerOperation): + """Class representing a tezos reveal.""" -class Reveal(UnsafeOp): - """Class representing a reveal.""" + public_key: str def __init__(self, - public_key: str, - source: str, - counter: int = 0, - fee: int = 0, - gas_limit: int = 0, - storage_limit: int = 0): - ctxt = pytezos.using() - reveal = ctxt.reveal(public_key, source, counter, fee, gas_limit, storage_limit) - super().__init__(reveal) + public_key: str = Default.ED25519_PUBLIC_KEY, + *args, **kwargs): + self.public_key = public_key + ManagerOperation.__init__(self, *args, **kwargs) + + def forge(self) -> bytes: + return OperationForge.reveal( + self.reveal( + self.public_key, + self.source, + self.counter, + self.fee, + self.gas_limit, + self.storage_limit + ) + ) -class Preattestation: - """Class representing a preattestation.""" +class Delegation(ManagerOperation): + """Class representing a tezos delegation.""" - slot: int - op_level: int - op_round: int - block_payload_hash: str + delegate: Optional[str] def __init__(self, - slot: int = 0, - op_level: int = 0, - op_round: int = 0, - block_payload_hash: str = DEFAULT_BLOCK_PAYLOAD_HASH): - self.slot = slot - self.op_level = op_level - self.op_round = op_round - self.block_payload_hash = block_payload_hash + delegate: Optional[str] = None, + *args, **kwargs): + self.delegate = delegate + ManagerOperation.__init__(self, *args, **kwargs) + + def forge(self) -> bytes: + return OperationForge.delegation( + self.delegation( + self.delegate, + self.source, + self.counter, + self.fee, + self.gas_limit, + self.storage_limit + ) + ) - def __bytes__(self) -> bytes: - raw = b'' - raw += forge_int_fixed(OperationTag.PREATTESTATION, 1) - raw += forge.forge_int16(self.slot) - raw += forge.forge_int32(self.op_level) - raw += forge.forge_int32(self.op_round) - raw += forge.forge_base58(self.block_payload_hash) - return raw +class Transaction(ManagerOperation): + """Class representing a tezos transaction.""" + + destination: str + amount: int + entrypoint: str + parameter: Micheline + + def __init__(self, + destination: str = Default.ED25519_PUBLIC_KEY_HASH, + amount: int = 0, + entrypoint: str = Default.ENTRYPOINT, + parameter: Micheline = Default.Micheline.VALUE, + *args, **kwargs): + self.destination = destination + self.amount = amount + self.entrypoint = entrypoint + self.parameter = parameter + ManagerOperation.__init__(self, *args, **kwargs) + + def forge(self) -> bytes: + parameters = { "entrypoint": self.entrypoint, "value": self.parameter } + return OperationForge.transaction( + self.transaction( + self.destination, + self.amount, + parameters, + self.source, + self.counter, + self.fee, + self.gas_limit, + self.storage_limit + ) + ) - def forge(self, - chain_id: str = DEFAULT_CHAIN_ID, - branch: str = DEFAULT_BLOCK_HASH) -> Message: - """Forge the preattestation.""" - raw_operation = \ - forge.forge_base58(branch) + \ - bytes(self) - watermark = \ - forge_int_fixed(MagicByte.TENDERBAKE_PREATTESTATION, 1) + \ - forge.forge_base58(chain_id) - raw = watermark + raw_operation - return RawMessage(raw) - -class Attestation: - """Class representing an attestation.""" +class Preattestation(Operation): + """Class representing a tezos preattestation.""" slot: int op_level: int op_round: int block_payload_hash: str + chain_id: str + + @property + def watermark(self) -> bytes: + return \ + forge_int_fixed(Watermark.TENDERBAKE_PREATTESTATION, 1) \ + + forge_base58(self.chain_id) def __init__(self, slot: int = 0, op_level: int = 0, op_round: int = 0, - block_payload_hash: str = DEFAULT_BLOCK_PAYLOAD_HASH): - self.slot = slot - self.op_level = op_level - self.op_round = op_round + block_payload_hash: str = Default.BLOCK_PAYLOAD_HASH, + chain_id: str = Default.CHAIN_ID, + *args, **kwargs): + self.slot = slot + self.op_level = op_level + self.op_round = op_round self.block_payload_hash = block_payload_hash + self.chain_id = chain_id + Operation.__init__(self, *args, **kwargs) + + def forge(self) -> bytes: + return OperationForge.preattestation( + self.preattestation( + self.slot, + self.op_level, + self.op_round, + self.block_payload_hash + ) + ) - def __bytes__(self) -> bytes: - raw = b'' - raw += forge_int_fixed(OperationTag.ATTESTATION, 1) - raw += forge.forge_int16(self.slot) - raw += forge.forge_int32(self.op_level) - raw += forge.forge_int32(self.op_round) - raw += forge.forge_base58(self.block_payload_hash) - return raw - - def forge(self, - chain_id: str = DEFAULT_CHAIN_ID, - branch: str = DEFAULT_BLOCK_HASH) -> Message: - """Forge the attestation.""" - raw_operation = \ - forge.forge_base58(branch) + \ - bytes(self) - watermark = \ - forge_int_fixed(MagicByte.TENDERBAKE_ATTESTATION, 1) + \ - forge.forge_base58(chain_id) - raw = watermark + raw_operation - return RawMessage(raw) - -class AttestationDal: - """Class representing an attestation + DAL.""" +class Attestation(Operation): + """Class representing a tezos attestation.""" slot: int op_level: int op_round: int block_payload_hash: str - dal_attestation: int + dal_attestation: Optional[int] + chain_id: str + + @property + def watermark(self) -> bytes: + return \ + forge_int_fixed(Watermark.TENDERBAKE_ATTESTATION, 1) \ + + forge_base58(self.chain_id) def __init__(self, slot: int = 0, op_level: int = 0, op_round: int = 0, - block_payload_hash: str = DEFAULT_BLOCK_PAYLOAD_HASH, - dal_attestation: int = 0): - self.slot = slot - self.op_level = op_level - self.op_round = op_round + block_payload_hash: str = Default.BLOCK_PAYLOAD_HASH, + dal_attestation: Optional[int] = None, + chain_id: str = Default.CHAIN_ID, + *args, **kwargs): + self.slot = slot + self.op_level = op_level + self.op_round = op_round self.block_payload_hash = block_payload_hash - self.dal_attestation = dal_attestation - - def __bytes__(self) -> bytes: - raw = b'' - raw += forge_int_fixed(OperationTag.ATTESTATION_WITH_DAL, 1) - raw += forge.forge_int16(self.slot) - raw += forge.forge_int32(self.op_level) - raw += forge.forge_int32(self.op_round) - raw += forge.forge_base58(self.block_payload_hash) - raw += forge.forge_nat(self.dal_attestation) - return raw - - def forge(self, - chain_id: str = DEFAULT_CHAIN_ID, - branch: str = DEFAULT_BLOCK_HASH) -> Message: - """Forge the attestation + DAL.""" - raw_operation = \ - forge.forge_base58(branch) + \ - bytes(self) - watermark = \ - forge_int_fixed(MagicByte.TENDERBAKE_ATTESTATION, 1) + \ - forge.forge_base58(chain_id) - raw = watermark + raw_operation - return RawMessage(raw) + self.dal_attestation = dal_attestation + self.chain_id = chain_id + Operation.__init__(self, *args, **kwargs) + + def forge(self) -> bytes: + return OperationForge.attestation( + self.attestation( + self.slot, + self.op_level, + self.op_round, + self.block_payload_hash, + self.dal_attestation + ) + ) class Fitness: """Class representing a fitness.""" @@ -296,84 +478,83 @@ def __init__(self, self.predecessor_round = predecessor_round self.current_round = current_round - def __bytes__(self) -> bytes: + def build(self): + """Build a tezos fitness.""" raw_locked_round = \ b'' if self.locked_round is None else \ - forge.forge_int32(self.locked_round) + forge_int32(self.locked_round) raw_predecessor_round = \ (-self.predecessor_round-1).to_bytes(4, 'big', signed=True) - return forge_fitness( - [ - forge_int_fixed(ConsensusProtocol.TENDERBAKE, 1).hex(), - forge.forge_int32(self.level).hex(), - raw_locked_round.hex(), - raw_predecessor_round.hex(), - forge.forge_int32(self.current_round).hex() - ] - ) + return [ + forge_int_fixed(ConsensusProtocol.TENDERBAKE, 1).hex(), + forge_int32(self.level).hex(), + raw_locked_round.hex(), + raw_predecessor_round.hex(), + forge_int32(self.current_round).hex() + ] class BlockHeader: """Class representing a block header.""" level: int - proto_level: int + proto: int predecessor: str timestamp: str validation_pass: int operations_hash: str fitness: Fitness context: str + protocol_data: str # Hex def __init__(self, level: int = 0, - proto_level: int = 0, - predecessor: str = DEFAULT_BLOCK_HASH, - timestamp: str = DEFAULT_TIMESTAMP, + proto: int = 0, + predecessor: str = Default.BLOCK_HASH, + timestamp: str = Default.TIMESTAMP, validation_pass: int = 0, - operations_hash: str = DEFAULT_OPERATIONS_HASH, + operations_hash: str = Default.OPERATIONS_HASH, fitness: Fitness = Fitness(), - context: str = DEFAULT_CONTEXT_HASH): - self.level = level - self.proto_level = proto_level - self.predecessor = predecessor - self.timestamp = timestamp + context: str = Default.CONTEXT_HASH, + protocol_data: str = ''): + self.level = level + self.proto = proto + self.predecessor = predecessor + self.timestamp = timestamp self.validation_pass = validation_pass self.operations_hash = operations_hash - self.fitness = fitness - self.context = context - - def __bytes__(self) -> bytes: - raw = b'' - raw += forge_int_fixed(self.level, 4) - raw += forge_int_fixed(self.proto_level, 1) - raw += forge.forge_base58(self.predecessor) - raw += forge_int_fixed(forge.optimize_timestamp(self.timestamp), 8) - raw += forge_int_fixed(self.validation_pass, 1) - raw += forge.forge_base58(self.operations_hash) - raw += bytes(self.fitness) - raw += forge.forge_base58(self.context) - return raw - -class Block: + self.fitness = fitness + self.context = context + self.protocol_data = protocol_data + + def build(self): + """Build a tezos Block header.""" + return { + 'level': self.level, + 'proto': self.proto, + 'predecessor': self.predecessor, + 'timestamp': self.timestamp, + 'validation_pass': self.validation_pass, + 'operations_hash': self.operations_hash, + 'fitness': self.fitness.build(), + 'context': self.context, + 'protocol_data': self.protocol_data, + } + +class Block(Message): """Class representing a block.""" header: BlockHeader - content: bytes + chain_id: str def __init__(self, header: BlockHeader = BlockHeader(), - content: Union[str, bytes] = b''): - self.header = header - self.content = content if isinstance(content, bytes) else \ - bytes.fromhex(content) + chain_id: str = Default.CHAIN_ID): + self.header = header + self.chain_id = chain_id def __bytes__(self) -> bytes: - return bytes(self.header) + self.content - - def forge(self, chain_id: str = DEFAULT_CHAIN_ID) -> Message: - """Forge the block.""" - watermark = \ - forge_int_fixed(MagicByte.TENDERBAKE_BLOCK, 1) + \ - forge.forge_base58(chain_id) - raw = watermark + bytes(self) - return RawMessage(raw) + raw = b'' + raw += forge_int_fixed(Watermark.TENDERBAKE_BLOCK, 1) + raw += forge_base58(self.chain_id) + raw += forge_block_header(self.header.build()) + return raw diff --git a/test/utils/navigator.py b/test/utils/navigator.py index 5f588320..e69f94e8 100644 --- a/test/utils/navigator.py +++ b/test/utils/navigator.py @@ -38,8 +38,6 @@ Position, STAX_BUTTON_LOWER_LEFT, STAX_BUTTON_ABOVE_LOWER_MIDDLE, - STAX_BUTTON_LOWER_RIGHT, - STAX_BUTTON_LOWER_MIDDLE, FLEX_BUTTON_LOWER_LEFT, FLEX_BUTTON_ABOVE_LOWER_MIDDLE ) @@ -47,11 +45,8 @@ from common import TESTS_ROOT_DIR, EMPTY_PATH from utils.client import TezosClient, Hwm -from utils.account import Account, Signature -from utils.message import ( - Delegation, - DEFAULT_BLOCK_HASH -) +from utils.account import Account +from utils.message import Delegation RESPONSE = TypeVar('RESPONSE') @@ -78,6 +73,8 @@ def send_and_navigate(send: Callable[[], RESPONSE], navigate: Callable[[], None] class FixedScreen(str, Enum): """Class representing screens that have fixed display.""" + def __str__(self) -> str: + return self.value class NanoFixedScreen(FixedScreen): """FixedScreen for Nano devices.""" @@ -409,7 +406,7 @@ def authorize_baking(self, def get_public_key_prompt(self, account: Account, navigate: Optional[Callable] = None, - **kwargs) -> bytes: + **kwargs) -> str: """Send a get public key request and navigate until accept""" if navigate is None: navigate = self.accept_key_navigate @@ -476,7 +473,7 @@ def setup_app_context(self, main_hwm: Hwm, test_hwm: Hwm, navigate: Optional[Callable] = None, - **kwargs) -> bytes: + **kwargs) -> str: """Send a setup request and navigate until accept""" if navigate is None: navigate = self.accept_setup_navigate @@ -513,16 +510,15 @@ def accept_sign_navigate(self, **kwargs): def sign_delegation(self, account: Account, delegation: Delegation, - branch: str = DEFAULT_BLOCK_HASH, navigate: Optional[Callable] = None, - **kwargs) -> Signature: + **kwargs) -> str: """Send a sign request on delegation and navigate until accept""" if navigate is None: navigate = self.accept_sign_navigate return send_and_navigate( send=lambda: self.client.sign_message( account, - delegation.forge(branch) + delegation ), navigate=lambda: navigate(**kwargs) ) @@ -530,16 +526,15 @@ def sign_delegation(self, def sign_delegation_with_hash(self, account: Account, delegation: Delegation, - branch: str = DEFAULT_BLOCK_HASH, navigate: Optional[Callable] = None, - **kwargs) -> Tuple[bytes, Signature]: + **kwargs) -> Tuple[bytes, str]: """Send a sign and get hash request on delegation and navigate until accept""" if navigate is None: navigate = self.accept_sign_navigate return send_and_navigate( send=lambda: self.client.sign_message_with_hash( account, - delegation.forge(branch) + delegation ), navigate=lambda: navigate(**kwargs) )