diff --git a/app/src/apdu.h b/app/src/apdu.h index 467567f78..32d61c109 100644 --- a/app/src/apdu.h +++ b/app/src/apdu.h @@ -83,8 +83,22 @@ typedef void(tz_handler)(command_t *cmd); typedef tz_handler *tz_handler_t; -tz_handler handle_unimplemented; -tz_handler handle_apdu_version; -tz_handler handle_apdu_git; +tz_handler handle_unimplemented; /// handler for unknown commands +tz_handler handle_apdu_version; /// handle version enquiry apdu +tz_handler handle_apdu_git; /// handle git commit enquiry apdu +/** + * @brief Function to handle apdu request for public key. The public key is + * derived only once and stored in the RAM, in order to avoid repeated + * derivation calculations. This function can be called with or without + * prompt. + * + */ tz_handler handle_apdu_get_public_key; +/** + * @brief Parse the received command and prompt user for appropriate action. + * Triggers blindsigning and/or expert mode workflows based on transaction + * involved. Stream based parser helps decode arbitararily large transaction, + * screen by screen. + * + */ tz_handler handle_apdu_sign; diff --git a/app/src/apdu_sign.h b/app/src/apdu_sign.h index 0880a6bed..1b6dbd84c 100644 --- a/app/src/apdu_sign.h +++ b/app/src/apdu_sign.h @@ -29,38 +29,57 @@ #include "keys.h" #include "parser/parser_state.h" +/** + * @brief Save hash of the transaction to be signed. + * + */ typedef struct { - cx_blake2b_t state; - uint8_t final_hash[SIGN_HASH_SIZE]; + cx_blake2b_t state; /// Ledger-sdk blake2b state containing hash header + /// and blake2b state info. + uint8_t final_hash[SIGN_HASH_SIZE]; /// Final hash of the transaction. } apdu_hash_state_t; +/** + * @brief Represents state of sign transaction. + * + */ typedef enum { - SIGN_ST_IDLE, - SIGN_ST_WAIT_DATA, - SIGN_ST_WAIT_USER_INPUT + SIGN_ST_IDLE, /// IDLE + SIGN_ST_WAIT_DATA, /// Waiting for more data from apdu interface + SIGN_ST_WAIT_USER_INPUT /// Waiting for user action } sign_step_t; +/** + * @brief Steps in a blind signing of a transaction. + * + */ typedef enum { BLINDSIGN_ST_OPERATION, BLINDSIGN_ST_HASH, BLINDSIGN_ST_ACCEPT_REJECT, } blindsign_step_t; +/** + * @brief Struct to track state/info about current sign operation. + * + */ typedef struct { - uint8_t packet_index; + uint8_t packet_index; /// Index of the packet currently being processed. - sign_step_t step; - bool return_hash; - bool received_last_msg; - uint8_t tag; + sign_step_t step; /// Current step of the sign operation. + bool return_hash; /// Whether to return the hash of the transaction. + bool received_last_msg; /// Whether the last message has been received. + uint8_t tag; /// Type of tezos operation to sign. union { + /// @brief clear signing state info. struct { size_t total_length; tz_parser_state parser_state; uint8_t last_field_index; bool received_msg; } clear; + /// @brief blindsigning state info. struct { blindsign_step_t step; } blind; diff --git a/app/src/globals.h b/app/src/globals.h index dc38e1e61..7d4b0846f 100644 --- a/app/src/globals.h +++ b/app/src/globals.h @@ -44,20 +44,24 @@ #include "utils.h" #include "parser/parser_state.h" - -// Zeros out all application-specific globals and SDK-specific -// UI/exchange buffers. +/** + * @brief Zeros out all application-specific globals and SDK-specific + * UI/exchange buffers. + */ void init_globals(void); -// Toggles the persisted expert_mode setting +/// Toggles the persisted expert_mode setting void toggle_expert_mode(void); -// Toggles the persisted blindsigning setting +/// Toggles the persisted blindsigning setting void toggle_blindsigning(void); #define MAX_APDU_SIZE 235 #define MAX_SIGNATURE_SIZE 100 - +/** + * @brief Home screen pages in order + * + */ typedef enum { #ifdef HAVE_BAGL SCREEN_HOME = 0, @@ -70,24 +74,33 @@ typedef enum { SCREEN_QUIT, } screen_t; +/** + * @brief State of the app + * + */ typedef enum { - ST_IDLE, - ST_CLEAR_SIGN, - ST_BLIND_SIGN, - ST_PROMPT, - ST_SWAP_SIGN, - ST_ERROR + ST_IDLE, /// Idle state + ST_CLEAR_SIGN, /// Clearsigning an operation + ST_BLIND_SIGN, /// blindisigning an operation + ST_PROMPT, /// Waiting for user prompt + ST_SWAP_SIGN, /// Performing swap operations + ST_ERROR /// In error state. } main_step_t; +/** + * @brief Global structure holding state of operations and buffer of the data + * to be processed. + * + */ typedef struct { /* State */ - main_step_t step; - tz_ui_stream_t stream; - bip32_path_with_curve_t path_with_curve; + main_step_t step; /// Current operational state of app. + tz_ui_stream_t stream; /// UX and display related information + bip32_path_with_curve_t path_with_curve; /// Derivation path union { struct { - apdu_hash_state_t hash; - apdu_sign_state_t sign; + apdu_hash_state_t hash; /// Transaction hash + apdu_sign_state_t sign; /// state of sign operation. } apdu; /** Warning: Use this pubkey only when apdu-hash/sign * is not being used. @@ -96,19 +109,20 @@ typedef struct { * */ cx_ecfp_public_key_t pubkey; } keys; - char line_buf[TZ_UI_STREAM_CONTENTS_SIZE + 1]; + char line_buf[TZ_UI_STREAM_CONTENTS_SIZE + + 1]; /// Buffer to store incoming data. #ifdef HAVE_BAGL struct { bagl_element_t bagls[5 + TZ_SCREEN_LINES_11PX]; - } ux; + } ux; /// Config for history screens for nano devices. #endif } globals_t; /* Settings */ typedef struct { - bool blindsigning; - bool expert_mode; -} settings_t; + bool blindsigning; /// enable blindsigning + bool expert_mode; /// enable expert mode +} settings_t; /// Special settings available in the app. extern globals_t global; @@ -116,5 +130,8 @@ extern const settings_t N_settings_real; #define N_settings (*(volatile settings_t *)PIC(&N_settings_real)) extern unsigned int app_stack_canary; // From SDK - +/** + * @brief IO buffer. + * + */ extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; diff --git a/app/src/handle_swap.h b/app/src/handle_swap.h index f20a3a041..c49c2c945 100644 --- a/app/src/handle_swap.h +++ b/app/src/handle_swap.h @@ -22,4 +22,9 @@ #pragma once +/** + * @brief Called to check the validity of swap params previously communicated + * by swap_copy_transaction_parameters which is called from Ledger SDK. + * + */ void swap_check_validity(void); diff --git a/app/src/keys.h b/app/src/keys.h index e5e587d66..f4e73e193 100644 --- a/app/src/keys.h +++ b/app/src/keys.h @@ -32,8 +32,11 @@ #define MAX_BIP32_LEN 10 #define SIGN_HASH_SIZE 32 -/* The values in the following enum are from the on-the-wire protocol */ - +/** + * @brief The derivation type values in the following enum are from the + * on-the-wire protocol + * + */ typedef enum { DERIVATION_TYPE_ED25519 = 0, DERIVATION_TYPE_SECP256K1 = 1, @@ -53,15 +56,38 @@ typedef struct { } bip32_path_with_curve_t; tz_exc read_bip32_path(bip32_path_t *out, const uint8_t *in, size_t in_size); + +/** + * @brief Derive public key for given derivation type address. + * + * @param public_key Public key derived is stored in this struct. + * @param derivation_type Derivation type to be used + * @param bip32_path path to derive public key from + * @return tz_exc return success/failure using error code + */ tz_exc derive_pk(cx_ecfp_public_key_t *public_key, derivation_type_t derivation_type, const bip32_path_t *bip32_path); +/** + * @brief Derive hash of public key for given derivation type address. + * + * @param hash The hash of public key, output is stored in this buffer. + * @param derivation_type Derivation type to be used. + * @param bip32_path Path to derive public key from. + * @return tz_exc return Error code + */ tz_exc derive_pkh(cx_ecfp_public_key_t *pubkey, derivation_type_t derivation_type, char *buffer, size_t len); void sign(derivation_type_t derivation_type, const bip32_path_t *path, const uint8_t *hash, size_t hashlen, uint8_t *sig, size_t *siglen); +/** + * @brief Check if derivation type is valid enum + * + * @param code Derivation type to check. + * @return validity result + */ static inline bool check_derivation_type(derivation_type_t code) { diff --git a/app/src/ui_commons.h b/app/src/ui_commons.h index 9279e6ac7..72d446c1e 100644 --- a/app/src/ui_commons.h +++ b/app/src/ui_commons.h @@ -25,7 +25,10 @@ #include #include #include - +/** + * @brief Macro to display navigation icons and set associated callback. + * + */ #define DISPLAY(elts, cb, len) \ memcpy(global.ux.bagls, elts, len * sizeof(bagl_element_t)); \ G_ux.stack[0].element_arrays[0].element_array = global.ux.bagls; \ diff --git a/app/src/ui_home.c b/app/src/ui_home.c index 0b3d60240..490af5b98 100644 --- a/app/src/ui_home.c +++ b/app/src/ui_home.c @@ -28,6 +28,10 @@ static void cb(tz_ui_cb_type_t cb_type); +/** + * @brief Callback for home screen stream. + * + * @param cb_type one of the 4 home screens (HOME, VERSION, SETTINGS, QUIT) */ static void cb(tz_ui_cb_type_t cb_type) { diff --git a/app/src/ui_home.h b/app/src/ui_home.h index 33d60b4a6..e81865094 100644 --- a/app/src/ui_home.h +++ b/app/src/ui_home.h @@ -20,4 +20,9 @@ #pragma once +/** + * @brief Initialize home screen with the screen format of ledger. + * Internally call multiple initialization functions for Settings screen and + * other relevant display buffers. + */ void ui_home_init(void); diff --git a/app/src/ui_settings.h b/app/src/ui_settings.h index 11cab28dd..ba971aae5 100644 --- a/app/src/ui_settings.h +++ b/app/src/ui_settings.h @@ -7,4 +7,11 @@ #define SETTINGS_HOME_PAGE 0 #define SETTINGS_BLINDSIGNING_PAGE 1 +/** + * @brief Initialize settings screen for nano devices. Displays status of + * Expert-mode and Blind Signing. + * + * @param page Current page to display among all the pages available under + * Settings. + */ void ui_settings_init(int16_t page); diff --git a/app/src/ui_stream.h b/app/src/ui_stream.h index 564a47f44..24acd3a2c 100644 --- a/app/src/ui_stream.h +++ b/app/src/ui_stream.h @@ -46,9 +46,11 @@ #include "ui_strings.h" #ifdef TARGET_NANOS -#define TZ_UI_STREAM_HISTORY_SCREENS 5 +#define TZ_UI_STREAM_HISTORY_SCREENS \ + 5 /// Max number of screens in history for nanos #else -#define TZ_UI_STREAM_HISTORY_SCREENS 8 +#define TZ_UI_STREAM_HISTORY_SCREENS \ + 8 /// Max number of screens in history for nanos2/nanox. #endif // TARGET_NANOS #define TZ_UI_STREAM_TITLE_WIDTH TZ_SCREEN_WITDH_BETWEEN_ICONS_BOLD_11PX @@ -64,10 +66,10 @@ #define TZ_UI_STREAM_CONTENTS_SIZE \ (TZ_UI_STREAM_CONTENTS_WIDTH * TZ_UI_STREAM_CONTENTS_LINES) -/* - * In the following structure, "cb_type" is passed to our callback and - * it can be used to determine which screen was displayed when both - * buttons were pressed. +/** + * @brief Following #define's specify different "cb_types" which are passed to + * our callback and it can be used to determine which screen was displayed + * when both buttons were pressed. * * If TZ_UI_STREAM_SCREEN_NOCB is specified, no callback will be called * when both buttons are pressed. @@ -90,8 +92,9 @@ typedef uint8_t tz_ui_cb_type_t; #define TZ_UI_STREAM_CB_ACCEPT 0xFFu #define TZ_UI_LAYOUT_HOME_MASK 0x80u + /** - * Layout type: + * @brief Layout type enum * BNP - refers to Bold Title, normal text/picture below the title. * BP - refers to Bold tile and picture below the title(optional). * NP - Normal text and picture below the text(optional) @@ -111,10 +114,9 @@ typedef enum : uint8_t { TZ_UI_LAYOUT_HOME_NP = (0x07 | TZ_UI_LAYOUT_HOME_MASK) } tz_ui_layout_type_t; -/* - * The icons we used are generalised to allow for seamless Stax support +/** + * @brief The icons we used are generalised to allow for seamless Stax support */ - typedef uint8_t tz_ui_icon_t; #define TZ_UI_ICON_NONE 0x00 #define TZ_UI_ICON_TICK 0x01 @@ -124,61 +126,155 @@ typedef uint8_t tz_ui_icon_t; #define TZ_UI_ICON_BACK 0x05 #define TZ_UI_ICON_EYE 0x06 +/** + * @brief Represents a single screen's content and formatting for a ledger + * device. + * + */ typedef struct { - tz_ui_cb_type_t cb_type; + tz_ui_cb_type_t + cb_type; /// call back type for actions taken on this screen. #ifdef HAVE_BAGL - tz_ui_icon_t icon; - tz_ui_layout_type_t layout_type; - char *title; - char *body[TZ_UI_STREAM_CONTENTS_LINES]; + tz_ui_icon_t icon; /// Icon to display on the screen. + tz_ui_layout_type_t + layout_type; /// Layout type for the screen. CAN BP, BNP, NP, PB or + /// HOME_X where X can be one of the BP, BNP, PB. + char *title; /// Title to display on the screen. + char *body[TZ_UI_STREAM_CONTENTS_LINES]; /// Body to display on the + /// screen (Below title). #else - nbgl_layoutTagValue_t pairs[NB_MAX_DISPLAYED_PAIRS_IN_REVIEW]; - uint8_t nb_pairs; + nbgl_layoutTagValue_t + pairs[NB_MAX_DISPLAYED_PAIRS_IN_REVIEW]; /// Title-value pairs to be + /// displayed on stax + /// screen, Max 4 pairs can + /// be displayed on one + /// screen in stax. + uint8_t nb_pairs; /// Number of pairs to be displayed on the stax screen. #endif } tz_ui_stream_screen_t; #ifdef HAVE_NBGL +/** + * @brief Holds list of title-value pairs for the current screen on stax. + * + */ typedef struct { nbgl_layoutTagValueList_t list; } tz_ui_stream_display_t; #endif // HAVE_NBGL +/** + * @brief Holds data for current and all the history screens. + * + */ typedef struct { void (*cb)(tz_ui_cb_type_t cb_type); - tz_ui_stream_screen_t screens[TZ_UI_STREAM_HISTORY_SCREENS]; - tz_ui_strings_t strings; - int16_t current; - int16_t total; - int16_t last; - bool full; - bool pressed_right; + tz_ui_stream_screen_t + screens[TZ_UI_STREAM_HISTORY_SCREENS]; // array containing info of + // all screens. + tz_ui_strings_t strings; // Ring buffer containing text data to be + // displayed on screen. + int16_t current; // index of current screen. + int16_t total; // total number of screens. + int16_t last; // index of last screen. + bool full; // true if history is full. + bool pressed_right; // true if right button was pressed. #ifdef HAVE_NBGL - tz_ui_stream_display_t current_screen; - char verify_address[TZ_BASE58CHECK_BUFFER_SIZE(20, 3)]; - nbgl_callback_t stream_cb; -#endif // HAVE_NBGL + tz_ui_stream_display_t + current_screen; // current screen's title-value pairs. + char verify_address[TZ_BASE58CHECK_BUFFER_SIZE( + 20, 3)]; // Holds the public key.. + nbgl_callback_t + stream_cb; // callback to be called when new screen is needed. +#endif // HAVE_NBGL } tz_ui_stream_t; void tz_ui_stream_init(void (*cb)(tz_ui_cb_type_t cb_type)); -/* Push title & content to screen - * + +/** + * @brief Push title & content to a single screen * content may not always fit on screen entirely - returns total * bytes of content written. + * + * @param cb_type callback type for the screen being pushed. + * @param title title to be displayed + * @param value text to be displayed. + * @param layout_type Layout type, can be one of BP, BNP, NP, HOME_PB, ... and + * so on. + * @param icon icon to be displayed on the screen. + * @return size_t size of content written on the screen.(for ex. when value + * is too large to fit on one screen, only part of it is written and rest is + * displayed on next screen.) */ size_t tz_ui_stream_push(tz_ui_cb_type_t cb_type, const char *title, const char *value, tz_ui_layout_type_t layout_type, tz_ui_icon_t icon); + +/** + * @brief internal implementation of tz_ui_stream_push, implemented + * differently for stax and nano* devices. + * + * @param cb_type callback type for the screen being pushed. + * @param title title to be displayed + * @param value text to be displayed. + * @param max max chars of value to be displayed. (default: -1) + * @param layout_type Layout type, can be one of BP, BNP, NP, HOME_PB, ... and + * so on. + * @param icon icon to be displayed on the screen. + * @return size_t size of content written on the screen.(for ex. when value + * is too large to fit on one screen, only part of it is written and rest is + * displayed on next screen.) + */ size_t tz_ui_stream_pushl(tz_ui_cb_type_t cb_type, const char *title, const char *value, ssize_t max, tz_ui_layout_type_t layout_type, tz_ui_icon_t icon); + +/** + * @brief Push title- value pair, internally calls tz_ui_stream_push multiple + * times so that entire value is pushed, even if it takes multiple screens. + * + * @param cb_type callback type + * @param title Title to be displayed on the screen + * @param value text to be displayed on the screen + * @param layout_type Layout type + * @param icon Icon to be displayed on the screen + * @return size_t returns total number of characters written on the screen. + */ size_t tz_ui_stream_push_all(tz_ui_cb_type_t cb_type, const char *title, const char *value, tz_ui_layout_type_t layout_type, tz_ui_icon_t icon); -void tz_ui_stream_close(void); -void tz_ui_stream(void); -void tz_ui_stream_start(void); + +/** + * @brief Indicates the stream is closed. Can not close it again. + * + */ +void tz_ui_stream_close(void); + +/** + * @brief Redisplay the screen, called when additional data is pushed to the + * screen or when user presses buttons. + * + */ +void tz_ui_stream(void); + +/** + * @brief Start display of contents stored in ring buffer. + * + */ +void tz_ui_stream_start(void); + +/** + * @brief Get the callback type for current screen. + * + * @return tz_ui_cb_type_t + */ tz_ui_cb_type_t tz_ui_stream_get_cb_type(void); + #ifdef HAVE_NBGL +/** + * @brief Reject confirmation screen. + * + */ void tz_reject_ui(void); #endif diff --git a/app/src/ui_strings.c b/app/src/ui_strings.c index 11bd52f68..fcf14986d 100644 --- a/app/src/ui_strings.c +++ b/app/src/ui_strings.c @@ -134,10 +134,6 @@ ui_strings_can_fit(size_t len, bool *can_fit) TZ_POSTAMBLE; } -/* @param in: ptr to char[] to copy into the buffer - @param in_len: number of of chars to copy. in_len <= strlen(in) - @param out: will be set to the start of the char[] in the buffer -*/ void ui_strings_push(const char *in, size_t len, char **out) { @@ -265,11 +261,6 @@ ui_strings_drop_last(char **in) PRINT_STRINGS; } -/* Append as much as possible from str to the last string in the buffer. - * This WILL NOT move `last` in the buffer. - * - * @param out: the start of the copied chars in the buffer. - */ size_t ui_strings_append_last(const char *str, size_t max, char **out) { diff --git a/app/src/ui_strings.h b/app/src/ui_strings.h index 6f309a44b..c29205ff5 100644 --- a/app/src/ui_strings.h +++ b/app/src/ui_strings.h @@ -1,4 +1,4 @@ -/* Tezos Ledger application - Dynamic UI to display a stream of pages +/** Tezos Ledger application - Dynamic UI to display a stream of pages Copyright 2023 TriliTech @@ -16,44 +16,89 @@ #pragma once -/* This implements a multi-page screen, allowing to display a - potentially infinite number of screens, keeping a bounded history. - The user can query new screens using the right button, and go back - a few screens using the left button (until history limit is - reached). - - When a new page is needed, the display will call the `refill` - callback, which in turn can call `tz_ui_stream_push` to add a new - page. When the last page is reached, `tz_ui_stream_close` should be - called, and the two final special pages to `accept` and `reject` - the operation are pushed. The user can trigger the `accept` and - `reject` callbacks by pressing both buttons while there pages are - displayed. - - It is also possible to use this display engine for non streamed - data by pushing a precomputed series of pages with - `tz_ui_stream_push`, calling `tz_ui_stream_close`, and launching - with a `refill` callback set to NULL. */ +/** + * @brief This file implements ring buffer to store the strings to be + * displayed on the ledger screen. The ring buffer is fixed in size and + * implemented as fixed size C char array. The ring properties are implemented + * logically using push, drop etc. When a new element is added after checking + * that enough space in buffer is present, otherwise the oldest element in the + * buffer is removed. (We can also remove the newest element if desired.) + * + */ #ifdef TARGET_NANOS -#define BUFF_LEN 128 +#define BUFF_LEN 128 /// Ring buffer length of nanos #elif defined(HAVE_BAGL) -#define BUFF_LEN 256 +#define BUFF_LEN 256 /// Ring buffer length for nanos2/nanox #else -#define BUFF_LEN 512 +#define BUFF_LEN 512 /// Ring buffer length for stax #endif +/** + * @brief This struct represents the ring buffer to store title-value pairs to + * be displayed on the ledger device screens. + * + * + */ typedef struct { - char buffer[BUFF_LEN]; - char *start; - char *end; - char *internal_end; - size_t count; + char buffer[BUFF_LEN]; /// Stores title-value pairs + char *start; /// Logical start of the buffer. This is the oldest element + /// in the buffer and first character of that string. + char + *end; /// Logical end of the buffer. This is at the end of the newest + /// element in the buffer, after the null terminator character. + char *internal_end; /// Actual end of the buffer after which no data is + /// present. 0 <= internal_end < BUFF_LEN + size_t count; /// Number of strings stored in the buffer } tz_ui_strings_t; -void ui_strings_init(void); -void ui_strings_push(const char *str, size_t len, char **out); -void ui_strings_drop(char **str); -void ui_strings_drop_last(char **str); -void ui_strings_can_fit(size_t len, bool *can_fit); +/** + * @brief Resets ring buffer and set start and end to BUFF_START + */ +void ui_strings_init(void); + +/** + * @brief Push a new string to the ring buffer. + * Throws error if len can not be accomodated in the empty space of + * ring buffer. Therefore, it is important to call ui_strings_can_fit before + * pushing the string on the buffer. + * + * @param str: ptr to string to copy into the buffer + * @param len: number of of chars to copy. len <= strlen(str) + * @param out: will be set to the start of the string in the buffer + */ +void ui_strings_push(const char *str, size_t len, char **out); +/** + * @brief Drop the logical first string from the buffer, which is pointed by + * 'start'. + * + * @param str pointer to 'start' pointer of the buffer. + */ +void ui_strings_drop(char **str); +/** + * @brief Drop the logical last string in the ring buffer, which ends with + * 'end' pointer. + * + * @param str Pointer to start pointer of last string in the buffer. + */ +void ui_strings_drop_last(char **str); +/** + * @brief Checks if the ring buffer can fit the string of length len, without + * deleting any existing strings. + * + * @param len Length of string. + * @param can_fit result of the check, true if string can fit, false + * otherwise. + */ +void ui_strings_can_fit(size_t len, bool *can_fit); +/** + * @brief Append characters from input string to the last string in the + * buffer. Exclude the null termination character. + * + * @param str Input string + * @param max maximum number of characters to append. + * @param out pointer to the end of the resultant string in buffer (Null + * terminator) = s->end - 1 + * @return size_t Number of chars appended. + */ size_t ui_strings_append_last(const char *str, size_t max, char **out);